mirror of
https://gitee.com/niucloud-team/niucloud-admin.git
synced 2026-03-15 00:01:00 +00:00
update admin
This commit is contained in:
parent
63bf044a64
commit
992729a53d
@ -6,4 +6,8 @@ import request from '@/utils/request'
|
||||
*/
|
||||
export function getApply(params: Record<string, any>) {
|
||||
return request.get(`auth/authaddon`, {params})
|
||||
}
|
||||
}
|
||||
|
||||
export function getAppManage(params: Record<string, any>) {
|
||||
return request.get(`auth/app_manage`, {params})
|
||||
}
|
||||
|
||||
@ -32,13 +32,6 @@ export function getLoginConfig() {
|
||||
return request.get('login/config')
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置加星应用
|
||||
* @returns
|
||||
*/
|
||||
export function setStarAddon(params: Record<string, any>) {
|
||||
return request.post('auth/appstar', params)
|
||||
}
|
||||
/**
|
||||
* 获取默认页面应用列表
|
||||
*/
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
|
||||
/**
|
||||
* 获取交易配置
|
||||
* @returns
|
||||
*/
|
||||
export function getShopTransaction() {
|
||||
return request.get('shop/transaction')
|
||||
}
|
||||
/**
|
||||
* 编辑交易配置
|
||||
* @returns
|
||||
*/
|
||||
export function setShopTransaction(param:any) {
|
||||
return request.post('shop/transaction',param, {showSuccessMessage: true})
|
||||
}
|
||||
@ -1,8 +1,5 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// USER_CODE_BEGIN -- sys_dict
|
||||
|
||||
|
||||
/**
|
||||
* 获取数据字典列表
|
||||
* @param params
|
||||
@ -32,7 +29,6 @@ export function addDict(params: Record<string, any>) {
|
||||
|
||||
/**
|
||||
* 编辑数据字典
|
||||
* @param id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
@ -42,7 +38,6 @@ export function addDictData(params: Record<string, any>) {
|
||||
|
||||
/**
|
||||
* 编辑数据字典
|
||||
* @param id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
@ -74,12 +69,10 @@ export function setDictData(id:number,params: Record<string, any>) {
|
||||
export function getDictAll() {
|
||||
return request.get(`dict/all`)
|
||||
}
|
||||
// USER_CODE_END -- sys_dict
|
||||
|
||||
/**
|
||||
* 数据字典关键词查询
|
||||
* @param id
|
||||
* @param params
|
||||
* @param type
|
||||
* @returns
|
||||
*/
|
||||
export function useDictionary(type: string) {
|
||||
|
||||
@ -40,7 +40,7 @@ export function getModuleVersion() {
|
||||
|
||||
/**
|
||||
* 下载版本
|
||||
* @param addon
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function downloadVersion(params: Record<string, any>) {
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
|
||||
|
||||
/***************************************************** 账单列表 **************************************************/
|
||||
|
||||
/**
|
||||
|
||||
@ -15,4 +15,3 @@ export function getUserInfo(type: string) {
|
||||
export function setUserInfo(params: Record<string, any>) {
|
||||
return request.put(`auth/edit`, params, {showSuccessMessage: true});
|
||||
}
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ export function getUrl() {
|
||||
* @returns
|
||||
*/
|
||||
export function getRoleList(params: Record<string, any>) {
|
||||
return request.get('sys/role', { params })
|
||||
return request.get('sys/role', {params})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -42,7 +42,7 @@ export function getRoleInfo(roleId: number) {
|
||||
* @returns
|
||||
*/
|
||||
export function addRole(params: Record<string, any>) {
|
||||
return request.post(`sys/role`, params, { showSuccessMessage: true })
|
||||
return request.post(`sys/role`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,7 +50,7 @@ export function addRole(params: Record<string, any>) {
|
||||
* @param params
|
||||
*/
|
||||
export function editRole(params: Record<string, any>) {
|
||||
return request.put(`sys/role/${params.role_id}`, params, { showSuccessMessage: true })
|
||||
return request.put(`sys/role/${params.role_id}`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -58,7 +58,7 @@ export function editRole(params: Record<string, any>) {
|
||||
* @param roleId
|
||||
*/
|
||||
export function deleteRole(roleId: number) {
|
||||
return request.delete(`sys/role/${roleId}`, { showSuccessMessage: true })
|
||||
return request.delete(`sys/role/${roleId}`, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,8 +66,9 @@ export function deleteRole(roleId: number) {
|
||||
* @param params
|
||||
*/
|
||||
export function edstatus(params: Record<string, any>) {
|
||||
return request.put(`sys/role/status/${params.role_id}/${params.status}`, { showSuccessMessage: true })
|
||||
return request.put(`sys/role/status/${params.role_id}/${params.status}`, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 全部分组
|
||||
* @returns
|
||||
@ -83,12 +84,14 @@ export function allRole() {
|
||||
export function getSystem() {
|
||||
return request.get(`sys/menu/system_menu`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用权限列表
|
||||
*/
|
||||
export function getAddonList() {
|
||||
return request.get(`app/getAddonList`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用权限详情列表
|
||||
* @param key
|
||||
@ -96,6 +99,7 @@ export function getAddonList() {
|
||||
export function getaddonMenu(key: any) {
|
||||
return request.get(`sys/menu/addon_menu/${key}`)
|
||||
}
|
||||
|
||||
/***************************************************** 全部菜单 ****************************************************/
|
||||
|
||||
/**
|
||||
@ -120,7 +124,7 @@ export function getMenuInfo(menu_key: string) {
|
||||
* @returns
|
||||
*/
|
||||
export function addMenu(params: Record<string, any>) {
|
||||
return request.post('sys/menu', params, { showSuccessMessage: true })
|
||||
return request.post('sys/menu', params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,29 +132,33 @@ export function addMenu(params: Record<string, any>) {
|
||||
* @param params
|
||||
*/
|
||||
export function editMenu(params: Record<string, any>) {
|
||||
return request.put(`sys/menu/${params.menu_key}`, params, { showSuccessMessage: true })
|
||||
return request.put(`sys/menu/${params.menu_key}`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除菜单
|
||||
* @param menu_key
|
||||
*/
|
||||
export function deleteMenu(menu_key: string) {
|
||||
return request.delete(`sys/menu/${menu_key}`, { showSuccessMessage: true })
|
||||
return request.delete(`sys/menu/${menu_key}`, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统菜单
|
||||
*
|
||||
*
|
||||
*/
|
||||
export function getSystemMenu() {
|
||||
return request.get(`sys/menu/system_menu`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用菜单
|
||||
*
|
||||
*
|
||||
*/
|
||||
export function getAddonMenu(key:any) {
|
||||
export function getAddonMenu(key: any) {
|
||||
return request.get(`sys/menu/addon_menu/${key}`)
|
||||
}
|
||||
|
||||
/***************************************************** 站点菜单 ****************************************************/
|
||||
|
||||
/**
|
||||
@ -186,7 +194,7 @@ export function getWebConfig() {
|
||||
* @returns
|
||||
*/
|
||||
export function setWebsite(params: Record<string, any>) {
|
||||
return request.post(`sys/config/website`, params, { showSuccessMessage: true })
|
||||
return request.post(`sys/config/website`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -211,7 +219,7 @@ export function getService() {
|
||||
* @returns
|
||||
*/
|
||||
export function setCopyright(params: Record<string, any>) {
|
||||
return request.put(`sys/config/copyright`, params, { showSuccessMessage: true })
|
||||
return request.put(`sys/config/copyright`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -220,7 +228,7 @@ export function setCopyright(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function getAttachmentCategoryList(params: Record<string, any>) {
|
||||
return request.get(`sys/attachment/category`, { params })
|
||||
return request.get(`sys/attachment/category`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,7 +236,7 @@ export function getAttachmentCategoryList(params: Record<string, any>) {
|
||||
* @param params
|
||||
*/
|
||||
export function addAttachmentCategory(params: Record<string, any>) {
|
||||
return request.post(`sys/attachment/category`, params, { showSuccessMessage: true })
|
||||
return request.post(`sys/attachment/category`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -237,7 +245,7 @@ export function addAttachmentCategory(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function editAttachmentCategory(params: Record<string, any>) {
|
||||
return request.put(`sys/attachment/category/${params.id}`, params, { showSuccessMessage: true })
|
||||
return request.put(`sys/attachment/category/${params.id}`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -246,7 +254,7 @@ export function editAttachmentCategory(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function deleteAttachmentCategory(id: number) {
|
||||
return request.delete(`sys/attachment/category/${id}`, { showSuccessMessage: true })
|
||||
return request.delete(`sys/attachment/category/${id}`, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -255,7 +263,7 @@ export function deleteAttachmentCategory(id: number) {
|
||||
* @returns
|
||||
*/
|
||||
export function getAttachmentList(params: Record<string, any>) {
|
||||
return request.get(`sys/attachment`, { params })
|
||||
return request.get(`sys/attachment`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -264,7 +272,7 @@ export function getAttachmentList(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function deleteAttachment(params: Record<string, any>) {
|
||||
return request.delete(`sys/attachment/del`, { data: params, showSuccessMessage: true })
|
||||
return request.delete(`sys/attachment/del`, {data: params, showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -294,7 +302,7 @@ export function getShortcutMenu() {
|
||||
* 添加快捷菜单
|
||||
*/
|
||||
export function setShortcutMenu(params: Record<string, any>) {
|
||||
return request.put(`sys/config/shortcut_menu`, params, { showSuccessMessage: true })
|
||||
return request.put(`sys/config/shortcut_menu`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -303,7 +311,7 @@ export function setShortcutMenu(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function getIconCategoryList(params: Record<string, any>) {
|
||||
return request.get(`sys/attachment/icon_category`, { params })
|
||||
return request.get(`sys/attachment/icon_category`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -312,7 +320,7 @@ export function getIconCategoryList(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function getIconList(params: Record<string, any>) {
|
||||
return request.get(`sys/attachment/icon`, { params })
|
||||
return request.get(`sys/attachment/icon`, {params})
|
||||
}
|
||||
|
||||
/***************************************************** 地址管理 ****************************************************/
|
||||
@ -338,14 +346,22 @@ export function getAreatree(level: number = 1) {
|
||||
* 获取地址信息
|
||||
*/
|
||||
export function getAddressInfo(params: any) {
|
||||
return request.get(`sys/area/get_info`, { params })
|
||||
return request.get(`sys/area/get_info`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取地址信息
|
||||
*/
|
||||
export function getContraryAddress(params: any) {
|
||||
return request.get(`sys/area/contrary`, { params })
|
||||
return request.get(`sys/area/contrary`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取地址
|
||||
* @param code
|
||||
*/
|
||||
export function getAreaByCode(code: number | string) {
|
||||
return request.get(`sys/area/code/${code}`)
|
||||
}
|
||||
|
||||
/***************************************************** 存储设置 ****************************************************/
|
||||
@ -371,7 +387,7 @@ export function getStorageInfo(type: string) {
|
||||
* @returns
|
||||
*/
|
||||
export function editStorage(params: Record<string, any>) {
|
||||
return request.put(`sys/storage/${params.storage_type}`, params, { showSuccessMessage: true })
|
||||
return request.put(`sys/storage/${params.storage_type}`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/***************************************************** 支付设置 ****************************************************/
|
||||
@ -389,7 +405,7 @@ export function getPayConfig(type: string) {
|
||||
* @returns
|
||||
*/
|
||||
export function setPayConfig(params: Record<string, any>) {
|
||||
return request.put(`pay/config/${params.type}`, params, { showSuccessMessage: true });
|
||||
return request.put(`pay/config/${params.type}`, params, {showSuccessMessage: true});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -405,7 +421,7 @@ export function getPayList() {
|
||||
* 获取打款设置配置
|
||||
* @param channel
|
||||
*/
|
||||
export function getTransferInfo(channel) {
|
||||
export function getTransferInfo(channel: string) {
|
||||
return request.get(`pay/channel/lists/${channel}`)
|
||||
}
|
||||
|
||||
@ -425,7 +441,7 @@ export function setTransferInfo(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function getCronList(params: any) {
|
||||
return request.get(`sys/schedule/list`, { params })
|
||||
return request.get(`sys/schedule/list`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -465,7 +481,7 @@ export function getWeek() {
|
||||
* @returns
|
||||
*/
|
||||
export function addCron(params: Record<string, any>) {
|
||||
return request.post(`sys/schedule`, params, { showSuccessMessage: true })
|
||||
return request.post(`sys/schedule`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -473,7 +489,7 @@ export function addCron(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function editCron(params: Record<string, any>) {
|
||||
return request.put(`sys/schedule/${params.id}`, params, { showSuccessMessage: true })
|
||||
return request.put(`sys/schedule/${params.id}`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -481,7 +497,7 @@ export function editCron(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function deleteCron(id: string) {
|
||||
return request.delete(`sys/schedule/${id}`, { showSuccessMessage: true })
|
||||
return request.delete(`sys/schedule/${id}`, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/***************************************************** 协议管理 ****************************************************/
|
||||
@ -507,7 +523,7 @@ export function getAgreementInfo(key: string) {
|
||||
* @returns
|
||||
*/
|
||||
export function editAgreement(params: Record<string, any>) {
|
||||
return request.put(`sys/agreement/${params.key}`, params, { showSuccessMessage: true })
|
||||
return request.put(`sys/agreement/${params.key}`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -542,7 +558,7 @@ export function getConfigLogin() {
|
||||
* @returns
|
||||
*/
|
||||
export function setConfigLogin(params: Record<string, any>) {
|
||||
return request.put(`sys/config/login`, params, { showSuccessMessage: true })
|
||||
return request.put(`sys/config/login`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -556,7 +572,7 @@ export function getPayConfigList() {
|
||||
* 设置支付配置
|
||||
*/
|
||||
export function setPatConfig(params: Record<string, any>) {
|
||||
return request.post(`pay/channel/set/all`, params, { showSuccessMessage: true })
|
||||
return request.post(`pay/channel/set/all`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
|
||||
@ -565,14 +581,14 @@ export function setPatConfig(params: Record<string, any>) {
|
||||
* 刷新菜单
|
||||
*/
|
||||
export function menuRefresh(params: Record<string, any>) {
|
||||
return request.post(`sys/menu/refresh`, {}, { showSuccessMessage: true })
|
||||
return request.post(`sys/menu/refresh`, {}, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理数据字段缓存
|
||||
*/
|
||||
export function clearSchemaCache(params: Record<string, any>) {
|
||||
return request.post(`sys/schema/clear`, {}, { showSuccessMessage: true })
|
||||
return request.post(`sys/schema/clear`, {}, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/***************************************************** 地图设置 ****************************************************/
|
||||
@ -581,7 +597,7 @@ export function clearSchemaCache(params: Record<string, any>) {
|
||||
* 设置地图key
|
||||
*/
|
||||
export function setMap(params: Record<string, any>) {
|
||||
return request.put(`sys/config/map`, params, { showSuccessMessage: true })
|
||||
return request.put(`sys/config/map`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -603,30 +619,30 @@ export function getIndexList() {
|
||||
* 设置首页模版
|
||||
*/
|
||||
export function setIndexList(params: Record<string, any>) {
|
||||
return request.put(`sys/config/site_index`, params, { showSuccessMessage: true })
|
||||
return request.put(`sys/config/site_index`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支付待审核记录
|
||||
*/
|
||||
export function getPayAuditList(params: Record<string, any>) {
|
||||
return request.get('pay/audit', { params })
|
||||
return request.get('pay/audit', {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付审核通过
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
export function payAuditPass(outTradeNo: string) {
|
||||
return request.put(`pay/pass/${outTradeNo}`, {}, { showSuccessMessage: true })
|
||||
return request.put(`pay/pass/${outTradeNo}`, {}, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付审核拒绝
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
export function payAuditRefuse(params: Record<string, any>) {
|
||||
return request.put(`pay/refuse/${params.out_trade_no}`, params, { showSuccessMessage: true })
|
||||
return request.put(`pay/refuse/${params.out_trade_no}`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -640,5 +656,5 @@ export function getPayDetail(id: number) {
|
||||
* 获取手机端首页列表
|
||||
*/
|
||||
export function getWapIndexList(params: Record<string, any>) {
|
||||
return request.get('sys/config/wap_index', { params })
|
||||
return request.get('sys/config/wap_index', {params})
|
||||
}
|
||||
@ -1,12 +1,14 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/***************************************************** 插件开发 ****************************************************/
|
||||
/**
|
||||
* 获取插件列表
|
||||
* @returns
|
||||
*/
|
||||
export function getAddonDevelop(params: Record<string, any>) {
|
||||
return request.get(`addon_develop`,{params});
|
||||
return request.get(`addon_develop`, {params});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件类型配置
|
||||
* @returns
|
||||
@ -14,60 +16,70 @@ export function getAddonDevelop(params: Record<string, any>) {
|
||||
export function getAddontype() {
|
||||
return request.get(`addontype`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件详情
|
||||
|
||||
* @returns
|
||||
*/
|
||||
export function getAddonDevelopInfo(key:any) {
|
||||
export function getAddonDevelopInfo(key: any) {
|
||||
return request.get(`addon_develop/${key}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件key是否存在
|
||||
|
||||
* @returns
|
||||
*/
|
||||
export function getAddonDevelopCheck(key:any) {
|
||||
export function getAddonDevelopCheck(key: any) {
|
||||
return request.get(`addon_develop/check/${key}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加插件
|
||||
* @param key
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addAddonDevelop(key:any,params: Record<string, any>) {
|
||||
export function addAddonDevelop(key: any, params: Record<string, any>) {
|
||||
return request.post(`addon_develop/${key}`, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑插件
|
||||
* @param key
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function editAddonDevelop(key:any,params: Record<string, any>) {
|
||||
export function editAddonDevelop(key: any, params: Record<string, any>) {
|
||||
return request.put(`addon_develop/${key}`, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除插件
|
||||
* @param id
|
||||
* @param key
|
||||
* @returns
|
||||
*/
|
||||
export function deleteAddonDevelop(key: any) {
|
||||
return request.delete(`addon_develop/${key}`, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 打包插件
|
||||
* @returns
|
||||
*/
|
||||
export function addonDevelopBuild(key:any) {
|
||||
export function addonDevelopBuild(key: any) {
|
||||
return request.post(`addon_develop/build/${key}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载插件
|
||||
* @returns
|
||||
*/
|
||||
export function addonDevelopDownload(key:any) {
|
||||
return request.post(`addon_develop/download/${key}`,{},{ "responseType": "blob" })
|
||||
export function addonDevelopDownload(key: any) {
|
||||
return request.post(`addon_develop/download/${key}`, {}, {"responseType": "blob"})
|
||||
}
|
||||
|
||||
/***************************************************** 代码生成 ****************************************************/
|
||||
|
||||
/**
|
||||
@ -122,14 +134,16 @@ export function deleteGenerateTable(id: number) {
|
||||
export function generateCreate(params: Record<string, any>) {
|
||||
return request.post(`generator/download`, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码生成预览
|
||||
* @param params
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
export function generatePreview(id: number) {
|
||||
return request.get(`generator/preview/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据表
|
||||
*/
|
||||
@ -143,21 +157,24 @@ export function generateTable() {
|
||||
export function getSystem() {
|
||||
return request.get(`sys/system`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全部模型
|
||||
*/
|
||||
export function getGeneratorAllModel(params:any) {
|
||||
return request.get(`generator/all_model`,{params})
|
||||
export function getGeneratorAllModel(params: any) {
|
||||
return request.get(`generator/all_model`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 表字段
|
||||
*/
|
||||
export function getGeneratorTableColumn(params:any){
|
||||
return request.get(`generator/table_column`,{params})
|
||||
export function getGeneratorTableColumn(params: any) {
|
||||
return request.get(`generator/table_column`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步校验
|
||||
*/
|
||||
export function generatorCheckFile(params: Record<string, any>){
|
||||
return request.get(`generator/check_file`,{params})
|
||||
export function generatorCheckFile(params: Record<string, any>) {
|
||||
return request.get(`generator/check_file`, {params})
|
||||
}
|
||||
@ -44,7 +44,6 @@ export function setWeappVersion(params: Record<string, any>) {
|
||||
|
||||
/**
|
||||
* 微信小程序预览码
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getWeappPreview() {
|
||||
@ -100,7 +99,7 @@ export function getVersionList(params: Record<string, any>) {
|
||||
|
||||
/**
|
||||
* 版本详情
|
||||
* @param params
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
export function getVersionInfo(id: string) {
|
||||
@ -118,7 +117,7 @@ export function editVersion(params: Record<string, any>) {
|
||||
|
||||
/**
|
||||
* 版本删除
|
||||
* @param params
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
export function deleteVersion(id: string) {
|
||||
|
||||
@ -58,7 +58,3 @@ export function getTemplateList() {
|
||||
export function getBatchAcquisition(params: Record<string, any>) {
|
||||
return request.put('wechat/template/sync', params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
admin/src/app/assets/images/diy/notice/style_01.png
Normal file
BIN
admin/src/app/assets/images/diy/notice/style_01.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
BIN
admin/src/app/assets/images/index/apply_empty.png
Normal file
BIN
admin/src/app/assets/images/index/apply_empty.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
@ -24,5 +24,7 @@
|
||||
"viewPathPlaceholder": "请输入组件路径",
|
||||
"authIdPlaceholder": "请输入api路径",
|
||||
"selectIconPlaceholder": "请选择菜单图标",
|
||||
"topLevel": "顶级"
|
||||
"topLevel": "顶级",
|
||||
"menuShortName":"菜单短标题",
|
||||
"menuShortNamePlaceholder":"请输入菜单短标题"
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
{
|
||||
"app":"应用",
|
||||
"noPlug":"暂无应用",
|
||||
"descriptionLeft":"暂无安装任何应用或插件,马上去",
|
||||
"link":"官方应用市场",
|
||||
"descriptionRight":"逛逛",
|
||||
"installApp":"安装应用"
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
{
|
||||
"refresh":"刷新",
|
||||
"refreshMenu":"刷新菜单",
|
||||
"refreshMenuDesc":"新增/修改插件菜单后,需要刷新插件菜单",
|
||||
"resetting": "重置",
|
||||
"refreshMenu":"重置菜单",
|
||||
"refreshMenuDesc":"重置菜单会按照菜单的配置文件进行重置,针对用户自己添加的菜单不处理",
|
||||
"dataCache":"数据缓存",
|
||||
"dataCacheDesc":"新增/修改数据表后,需要清除数据表缓存"
|
||||
}
|
||||
@ -24,7 +24,7 @@
|
||||
<span class="text-[14px] flex items-center text-[#797979]">
|
||||
<span>授权码</span>
|
||||
<em class="ml-[12px] mr-[10px] text-[12px] text-[#222222]">{{ authinfo.auth_code ? (isCheck ? authinfo.auth_code : hideAuthCode(authinfo.auth_code)) : '--' }}</em>
|
||||
<el-icon v-if="isCheck" @click="isCheck = !isCheck" class="text-[12px] cursor-pointer"><View/></el-icon>
|
||||
<el-icon v-if="!isCheck" @click="isCheck = !isCheck" class="text-[12px] cursor-pointer"><View/></el-icon>
|
||||
<el-icon v-else @click="isCheck = !isCheck" class="text-[12px] cursor-pointer"><Hide /></el-icon>
|
||||
</span>
|
||||
</div>
|
||||
@ -33,7 +33,7 @@
|
||||
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary" @click="authCodeApproveFn">授权码认证</el-button>
|
||||
<el-popover ref="getAuthCodeDialog" placement="bottom" :width="478" trigger="click" class="mt-[8px]">
|
||||
<div class="px-[18px] py-[8px]">
|
||||
<p class="leading-[32px] text-[18px]">您在官方应用市场购买任意一款应用,即可获得授权码。输入正确授权码认证通过后,即可支持在线升级和其它相关服务</p>
|
||||
<p class="leading-[32px] text-[14px]">您在官方应用市场购买任意一款应用,即可获得授权码。输入正确授权码认证通过后,即可支持在线升级和其它相关服务</p>
|
||||
<div class="flex justify-end mt-[36px]">
|
||||
<el-button class="w-[182px] !h-[48px]" plain @click="market">去应用市场逛逛</el-button>
|
||||
<el-button class="w-[100px] !h-[48px]" plain @click="getAuthCodeDialog.hide()">关闭</el-button>
|
||||
@ -44,7 +44,7 @@
|
||||
</template>
|
||||
</el-popover>
|
||||
</div>
|
||||
<el-dialog v-model="authCodeApproveDialog" title="授权码认证" width="400px" :before-close="closeAuthCodeApproveDialogFn">
|
||||
<el-dialog v-model="authCodeApproveDialog" title="授权码认证" width="400px">
|
||||
<el-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<el-form-item prop="auth_code">
|
||||
@ -96,12 +96,6 @@ const hideAuthCode = (res)=>{
|
||||
|
||||
const authCodeApproveFn = ()=>{
|
||||
authCodeApproveDialog.value = true;
|
||||
authinfo.value = "";
|
||||
}
|
||||
|
||||
const closeAuthCodeApproveDialogFn = ()=>{
|
||||
loading.value = true;
|
||||
checkAppMange();
|
||||
}
|
||||
|
||||
const authinfo = ref("");
|
||||
@ -139,14 +133,6 @@ const formRules = reactive<FormRules>({
|
||||
],
|
||||
});
|
||||
|
||||
const setFormData = async () => {
|
||||
const data = await (await getAdminAuthinfo()).data;
|
||||
Object.keys(formData).forEach((key: string) => {
|
||||
if (data[key] != undefined) formData[key] = data[key];
|
||||
});
|
||||
};
|
||||
setFormData();
|
||||
|
||||
const save = async (formEl: FormInstance | undefined) => {
|
||||
if (saveLoading.value || !formEl) return;
|
||||
|
||||
|
||||
@ -1,14 +1,10 @@
|
||||
<template>
|
||||
<div class="main-container h-[500px] w-full p-5 bg-white" v-loading="loading">
|
||||
|
||||
<div class="flex mb-4">
|
||||
<div class="border rounded-sm switch-btn active px-4 py-1 cursor-pointer flex items-center ">
|
||||
<img src="@/app/assets/images/app_store/local_icon_select.png" class="mr-1.5 w-3.5 h-3.5 mb-0.5">
|
||||
{{ t('localAppText') }}
|
||||
</div>
|
||||
<div class="flex justify-between items-center h-[32px] mb-4">
|
||||
<span class="text-[20px]">{{ t('localAppText') }}</span>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<div class="absolute right-0 top-[2px] flex items-center cursor-pointer z-20 border border-inherit">
|
||||
<div class="absolute right-0 top-[2px] flex items-center cursor-pointer z-[4] border border-inherit">
|
||||
<div class="flex item-center justify-center px-[6px] py-[4px]"
|
||||
:class="{ 'bg-slate-200': showType == 'small' }" @click="showType = 'small'">
|
||||
<img src="@/app/assets/images/app_store/switch_icon_1.png" class=" w-[16px] h-[16px]">
|
||||
@ -325,6 +321,7 @@ import { TabsPaneContext, ElMessageBox, ElNotification } from 'element-plus'
|
||||
import { img } from '@/utils/common'
|
||||
import { Terminal, api as terminalApi } from 'vue-web-terminal'
|
||||
import { useRouter } from 'vue-router'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
|
||||
const router = useRouter()
|
||||
const activeName = ref('installed')
|
||||
@ -332,6 +329,7 @@ const loading = ref<Boolean>(false)
|
||||
const showType = ref('large')
|
||||
const downloading = ref('')
|
||||
const installAfterTips = ref<string[]>([])
|
||||
const userStore = useUserStore()
|
||||
|
||||
const downEvent = (param: Record<string, any>) => {
|
||||
if (downloading.value) return
|
||||
@ -475,6 +473,7 @@ const getInstallTask = (first: boolean = true) => {
|
||||
if (!first) {
|
||||
installStep.value = 3
|
||||
localListFn()
|
||||
userStore.getAppList()
|
||||
notificationEl.close()
|
||||
}
|
||||
}
|
||||
@ -498,6 +497,7 @@ const handleInstall = () => {
|
||||
installAddon({ addon: currAddon.value }).then(res => {
|
||||
installStep.value = 3
|
||||
localListFn()
|
||||
userStore.getAppList()
|
||||
localInstalling.value = false
|
||||
if (res.data.length) installAfterTips.value = res.data
|
||||
}).catch((res) => {
|
||||
@ -581,6 +581,7 @@ watch(currAddon, (nval) => {
|
||||
const uninstallAddonFn = (key: string) => {
|
||||
uninstallAddon({ addon: key }).then(res => {
|
||||
localListFn()
|
||||
userStore.getAppList()
|
||||
loading.value = false
|
||||
}).catch(() => {
|
||||
loading.value = false
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { debounce } from '@/utils/common'
|
||||
import { ref, computed, onMounted, nextTick, } from 'vue'
|
||||
|
||||
const prop = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
@ -18,11 +19,9 @@ const prop = defineProps({
|
||||
let data = ref([])
|
||||
data.value.push(prop.data)
|
||||
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'change'])
|
||||
const value = computed({
|
||||
get() {
|
||||
|
||||
return prop.modelValue
|
||||
},
|
||||
set(value) {
|
||||
@ -30,6 +29,7 @@ const value = computed({
|
||||
}
|
||||
})
|
||||
const treeRef = ref(null)
|
||||
|
||||
//选择控制
|
||||
onMounted(()=>{
|
||||
nextTick(()=>{
|
||||
|
||||
@ -71,6 +71,10 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('menuShortName')" >
|
||||
<el-input v-model="formData.menu_short_name" :placeholder="t('menuShortNamePlaceholder')" class="input-width" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('sort')">
|
||||
<el-input-number v-model="formData.sort" :min="0" />
|
||||
</el-form-item>
|
||||
@ -92,6 +96,7 @@ import type { FormInstance } from 'element-plus'
|
||||
import selectMenuItem from './select-menu-item.vue'
|
||||
import { addMenu, editMenu, getMenuInfo, getSystemMenu,getAddonMenu } from '@/app/api/sys'
|
||||
import { getAddonDevelop } from '@/app/api/tools'
|
||||
|
||||
const showDialog = ref(false)
|
||||
const method = ref('post')
|
||||
const loading = ref(false)
|
||||
@ -115,7 +120,8 @@ const initialFormData = {
|
||||
is_show: 1,
|
||||
menu_key: '',
|
||||
app_type: '',
|
||||
addon: ''
|
||||
addon: '',
|
||||
menu_short_name:''
|
||||
}
|
||||
const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
|
||||
@ -168,23 +174,27 @@ const formRules = computed(() => {
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
//获取插件列表
|
||||
const getAddonDevelopFn = async () => {
|
||||
let { data } = await getAddonDevelop({})
|
||||
addonLst.value = [{ title: "系统", key: "" }]
|
||||
addonLst.value.push(...data)
|
||||
}
|
||||
|
||||
//获取系统菜单列表
|
||||
const getSystemMenuFn = async () => {
|
||||
let {data} = await getSystemMenu()
|
||||
sysMenuList.value = [{ menu_name: "顶级", menu_key: "" }]
|
||||
sysMenuList.value.push(...data)
|
||||
}
|
||||
|
||||
//获取系统应用列表
|
||||
const getAddonMenuFn = async (key:any) => {
|
||||
let {data} = await getAddonMenu(key)
|
||||
addonMenuList.value = data
|
||||
}
|
||||
|
||||
//选择应用
|
||||
const addonChange =async(val:any)=>{
|
||||
formData.parent_key = ''
|
||||
@ -193,6 +203,7 @@ const addonChange =async(val:any)=>{
|
||||
formData.parent_key = addonMenuList.value[0].menu_key
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits(['complete'])
|
||||
|
||||
/**
|
||||
|
||||
@ -41,8 +41,8 @@
|
||||
<el-table-column prop="sort" :label="t('sort')" min-width="100" />
|
||||
<el-table-column :label="t('operation')" fixed="right" align="right" width="130">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="editEvent(row)" v-if="row.source == 'generator' || row.source == 'create'">{{ t('edit') }}</el-button>
|
||||
<el-button type="primary" link @click="deleteEvent(row.menu_key)" v-if="row.source == 'generator' || row.source == 'create'">{{ t('delete') }}</el-button>
|
||||
<el-button type="primary" link @click="editEvent(row)" >{{ t('edit') }}</el-button>
|
||||
<el-button type="primary" link @click="deleteEvent(row.menu_key)" >{{ t('delete') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -81,8 +81,8 @@
|
||||
<el-table-column prop="sort" :label="t('sort')" min-width="100" />
|
||||
<el-table-column :label="t('operation')" fixed="right" align="right" width="130">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="editEvent(row)" v-if="row.source == 'generator' || row.source == 'create'">{{ t('edit') }}</el-button>
|
||||
<el-button type="primary" link @click="deleteEvent(row.menu_key)" v-if="row.source == 'generator' || row.source == 'create'">{{ t('delete') }}</el-button>
|
||||
<el-button v-if="row.menu_key.indexOf('1') ==-1" type="primary" link @click="editEvent(row)" >{{ t('edit') }}</el-button>
|
||||
<el-button v-if="row.menu_key.indexOf('1') ==-1" type="primary" link @click="deleteEvent(row.menu_key)" >{{ t('delete') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -102,6 +102,7 @@ import { t } from '@/lang'
|
||||
import EditMenu from '@/app/views/auth/components/edit-menu.vue'
|
||||
import { getSystem, getAddonList, deleteMenu, getMenus } from '@/app/api/sys'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
const pageName = route.meta.title
|
||||
|
||||
@ -112,7 +113,7 @@ const menusTableData = reactive({
|
||||
data:[],
|
||||
activeName: 'system'
|
||||
})
|
||||
console.log(menusTableData.applicationDate)
|
||||
|
||||
/**
|
||||
* 获取菜单
|
||||
*/
|
||||
|
||||
@ -55,6 +55,7 @@ import { t } from '@/lang'
|
||||
import { getRoleList, deleteRole, edstatus } from '@/app/api/sys'
|
||||
import { ElMessageBox, FormInstance } from 'element-plus'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const pageName = route.meta.title;
|
||||
@ -106,9 +107,10 @@ const editRoleDialog: Record<string, any> | null = ref(null)
|
||||
const addEvent = () => {
|
||||
router.push({ path: '/setting/auth/role_edit' })
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑角色
|
||||
* @param data
|
||||
* @param role_id
|
||||
*/
|
||||
const editEvent = (role_id: any) => {
|
||||
router.push({
|
||||
|
||||
@ -61,6 +61,7 @@ import { debounce } from '@/utils/common'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import addonRole from '@/app/views/auth/components/addon-role.vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const pageName = route.meta.title
|
||||
|
||||
@ -55,8 +55,8 @@ import { getMenus, deleteMenu } from '@/app/api/sys'
|
||||
import { t } from '@/lang'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import EditMenu from '@/app/views/auth/components/edit-menu.vue'
|
||||
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
const pageName = route.meta.title
|
||||
|
||||
|
||||
@ -226,6 +226,7 @@ import { useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
import {img} from '@/utils/common'
|
||||
import { getAliappConfig } from '@/app/api/aliapp'
|
||||
|
||||
const router = useRouter()
|
||||
let activeName = ref("/website/channel/aliapp");
|
||||
let active = ref(2);
|
||||
|
||||
@ -120,7 +120,6 @@ const formData = reactive<Record<string, string>>({
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
|
||||
/**
|
||||
* 获取支付宝配置
|
||||
*/
|
||||
@ -135,7 +134,6 @@ getAliappStatic().then(res => {
|
||||
formData.request_url = res.data.domain
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* 复制
|
||||
*/
|
||||
|
||||
@ -45,7 +45,6 @@ const formData = reactive<Record<string, string | boolean>>({
|
||||
const formRef = ref<FormInstance>()
|
||||
const router = useRouter()
|
||||
|
||||
|
||||
/**
|
||||
* 获取pc域名
|
||||
*/
|
||||
|
||||
@ -145,6 +145,7 @@ import { useRouter } from "vue-router";
|
||||
import { t } from "@/lang";
|
||||
import {img} from '@/utils/common'
|
||||
import { getWeappConfig } from '@/app/api/weapp'
|
||||
|
||||
const router = useRouter();
|
||||
let activeName = ref("/website/channel/weapp");
|
||||
let active = ref(2);
|
||||
|
||||
@ -9,17 +9,10 @@
|
||||
<el-tab-pane :label="t('weappRelease')" name="/website/channel/weapp/code" />
|
||||
</el-tabs>
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<el-collapse v-model="activeNames">
|
||||
<el-collapse-item :title="t('operatePrompt')" name="1">
|
||||
<div>
|
||||
<p class="indent-4">{{ t('operatePromptTipsTwo') }}</p>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
|
||||
<div class="mt-[50px]">
|
||||
<el-button type="primary" @click="insert" :loading="uploading">{{ t('cloudRelease') }}</el-button>
|
||||
<el-button @click="localInsert">{{ t('localRelease') }}</el-button>
|
||||
<el-button type="primary" @click="insert" :loading="uploading" :disabled="weappTableData.loading">{{
|
||||
t('cloudRelease') }}</el-button>
|
||||
<el-button @click="localInsert" :disabled="weappTableData.loading">{{ t('localRelease') }}</el-button>
|
||||
</div>
|
||||
<el-table class="mt-[15px]" :data="weappTableData.data" v-loading="weappTableData.loading" size="default">
|
||||
<template #empty>
|
||||
@ -36,10 +29,9 @@
|
||||
<el-table-column prop="create_time" :label="t('createTime')" align="center" />
|
||||
<el-table-column :label="t('operation')" fixed="right" align="right" min-width="120">
|
||||
<template #default="{ row, $index }">
|
||||
<div class="">
|
||||
<div class="" v-if="previewContent && $index == 0 && row.status == 1 && weappTableData.page == 1">
|
||||
<el-tooltip :content="previewContent" raw-content effect="light">
|
||||
<el-button type="primary" link
|
||||
v-if="previewContent && $index == 0 && weappTableData.page == 1">
|
||||
<el-button type="primary" link>
|
||||
{{ t('preview') }}</el-button>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
@ -74,13 +66,6 @@
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- <el-dialog v-model="uploading" title="" width="300px" :show-close="false" :align-center="true"
|
||||
:close-on-click-modal="false">
|
||||
<template #default>
|
||||
<div v-loading="uploading" class="w-full h-[100px]" :element-loading-text="t('uploadingTips')"></div>
|
||||
</template>
|
||||
</el-dialog> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -147,7 +132,7 @@ const getWeappVersionListFn = (page: number = 1) => {
|
||||
weappTableData.loading = false
|
||||
})
|
||||
}
|
||||
// loadWeappTemplateList()
|
||||
|
||||
getWeappVersionListFn()
|
||||
|
||||
const handleClose = () => {
|
||||
@ -168,8 +153,11 @@ const insert = () => {
|
||||
if (uploading.value) return
|
||||
uploading.value = true
|
||||
|
||||
previewContent.value = ''
|
||||
|
||||
setWeappVersion(form.value).then(res => {
|
||||
getWeappVersionListFn()
|
||||
getWeappPreviewImage()
|
||||
uploading.value = false
|
||||
}).catch(() => {
|
||||
uploading.value = false
|
||||
|
||||
@ -64,6 +64,7 @@ import { getTemplateList, getBatchAcquisition } from '@/app/api/weapp'
|
||||
import { editNoticeStatus } from '@/app/api/notice'
|
||||
import { ElLoading } from 'element-plus'
|
||||
import { useRoute,useRouter } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const pageName = route.meta.title
|
||||
|
||||
@ -232,6 +232,7 @@ import { useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
import {img} from '@/utils/common'
|
||||
import { getWechatConfig } from '@/app/api/wechat'
|
||||
|
||||
const router = useRouter()
|
||||
let activeName = ref("/website/channel/wechat");
|
||||
let active = ref(2);
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<h3 class="mb-[10px]">{{ t('addonListSet') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<div ref="addonBoxRef">
|
||||
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap !cursor-move p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<div v-show="item.title" class="flex items-center pb-[10px]">
|
||||
<img class="w-[60px] h-[60px] rounded-md" :src="img(item.icon)" />
|
||||
<div class="flex flex-col justify-center ml-[10px] leading-[1]">
|
||||
|
||||
78
admin/src/app/views/diy/components/edit-goods-list.vue
Normal file
78
admin/src/app/views/diy/components/edit-goods-list.vue
Normal file
@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<!-- 内容 -->
|
||||
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
|
||||
内容
|
||||
</div>
|
||||
|
||||
<!-- 样式 -->
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('titleStyle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('textFontSize')">
|
||||
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] article-slider" :min="12" :max="20"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textFontWeight')">
|
||||
<el-radio-group v-model="diyStore.editComponent.fontWeight">
|
||||
<el-radio :label="'normal'">{{t('fontWeightNormal')}}</el-radio>
|
||||
<el-radio :label="'bold'">{{t('fontWeightBold')}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.textColor"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 组件样式 -->
|
||||
<slot name="style"></slot>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {t} from '@/lang'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
import {ref, reactive} from 'vue'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = []; // 忽略公共属性
|
||||
|
||||
const showDialog = ref(false)
|
||||
|
||||
const showStyle = () => {
|
||||
showDialog.value = true
|
||||
}
|
||||
|
||||
const selectStyle = ref(diyStore.editComponent.style)
|
||||
|
||||
const changeStyle = () => {
|
||||
switch (selectStyle.value) {
|
||||
case 'style-1':
|
||||
diyStore.editComponent.subTitle.control = false
|
||||
diyStore.editComponent.more.control = false
|
||||
diyStore.editComponent.styleName = "风格1"
|
||||
break;
|
||||
case 'style-2':
|
||||
diyStore.editComponent.subTitle.control = true
|
||||
diyStore.editComponent.more.control = true
|
||||
diyStore.editComponent.styleName = "风格2"
|
||||
break;
|
||||
}
|
||||
diyStore.editComponent.style = selectStyle.value
|
||||
showDialog.value = false
|
||||
}
|
||||
|
||||
defineExpose({})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.horz-blank-slider {
|
||||
.el-slider__input {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped></style>
|
||||
@ -67,7 +67,7 @@
|
||||
<p class="text-sm text-gray-400 mb-[10px]">{{ t('graphicNavTips') }}</p>
|
||||
|
||||
<div ref="imageBoxRef">
|
||||
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap !cursor-move p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<el-form-item :label="t('image')" v-show="diyStore.editComponent.mode === 'graphic' || diyStore.editComponent.mode === 'img'">
|
||||
<upload-image v-model="item.imageUrl" :limit="1"/>
|
||||
</el-form-item>
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
</el-form-item>
|
||||
|
||||
<div ref="imageBoxRef">
|
||||
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap !cursor-move p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<el-form-item :label="t('image')">
|
||||
<upload-image v-model="item.imageUrl" :limit="1" @change="selectImg" />
|
||||
</el-form-item>
|
||||
|
||||
113
admin/src/app/views/diy/components/edit-notice.vue
Normal file
113
admin/src/app/views/diy/components/edit-notice.vue
Normal file
@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<!-- 内容 -->
|
||||
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">公告图标</h3>
|
||||
|
||||
<div class="px-[22px] pb-[20px]">
|
||||
<el-radio-group v-model="diyStore.editComponent.iconType" class="mb-[18px]">
|
||||
<el-radio label="system">系统图标</el-radio>
|
||||
<el-radio label="custom">自定义图标</el-radio>
|
||||
</el-radio-group>
|
||||
<div v-if="diyStore.editComponent.iconType == 'system'" class="flex items-center flex-wrap py-[8px] px-[10px] bg-[#f4f3f7] rounded">
|
||||
<img src="@/app/assets/images/diy/notice/style_01.png" :class="['h-[28px] px-[10px] py-[5px] mr-[10px] rounded cursor-pointer', {'border-[1px] border-solid border-[var(--el-color-primary)]': diyStore.editComponent.systemIcon == 'style_01'}]" @click="diyStore.editComponent.systemIcon = 'style_01'" alt="">
|
||||
</div>
|
||||
<div v-if="diyStore.editComponent.iconType == 'custom'">
|
||||
<upload-image v-model="diyStore.editComponent.imageUrl" :limit="1"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">公告内容</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('title')">
|
||||
<el-input v-model="diyStore.editComponent.list.text" :placeholder="t('titlePlaceholder')" clearable show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item label="点击类型">
|
||||
<el-radio-group v-model="diyStore.editComponent.showType" class="mb-[18px]">
|
||||
<el-radio label="popup">弹出公告内容</el-radio>
|
||||
<el-radio label="link">跳出链接</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('link')" class="!mb-0" v-if="diyStore.editComponent.showType == 'link'">
|
||||
<diy-link v-model="diyStore.editComponent.list.link"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 样式 -->
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('titleStyle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('textFontSize')">
|
||||
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] article-slider" :min="12" :max="20"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textFontWeight')">
|
||||
<el-radio-group v-model="diyStore.editComponent.fontWeight">
|
||||
<el-radio :label="'normal'">{{t('fontWeightNormal')}}</el-radio>
|
||||
<el-radio :label="'bold'">{{t('fontWeightBold')}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.textColor"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 组件样式 -->
|
||||
<slot name="style"></slot>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {t} from '@/lang'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
import {ref, reactive} from 'vue'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = []; // 忽略公共属性
|
||||
|
||||
const showDialog = ref(false)
|
||||
|
||||
let iconSelect = ref('0')
|
||||
|
||||
const showStyle = () => {
|
||||
showDialog.value = true
|
||||
}
|
||||
|
||||
const selectStyle = ref(diyStore.editComponent.style)
|
||||
|
||||
const changeStyle = () => {
|
||||
switch (selectStyle.value) {
|
||||
case 'style-1':
|
||||
diyStore.editComponent.subTitle.control = false
|
||||
diyStore.editComponent.more.control = false
|
||||
diyStore.editComponent.styleName = "风格1"
|
||||
break;
|
||||
case 'style-2':
|
||||
diyStore.editComponent.subTitle.control = true
|
||||
diyStore.editComponent.more.control = true
|
||||
diyStore.editComponent.styleName = "风格2"
|
||||
break;
|
||||
}
|
||||
diyStore.editComponent.style = selectStyle.value
|
||||
showDialog.value = false
|
||||
}
|
||||
|
||||
defineExpose({})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.horz-blank-slider {
|
||||
.el-slider__input {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
.add-notice-width{
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped></style>
|
||||
@ -25,7 +25,7 @@
|
||||
<el-tabs v-model="activeName" class="demo-tabs mt-[15px]">
|
||||
<el-tab-pane :label="t('navImage')" name="navPicture">
|
||||
<div ref="navItemRef">
|
||||
<div v-for="(item,index) in diyBottomData.list" :key="'a'+index" :data-id="index" class="item-wrap border-2 border-dashed pt-[18px] m-[10px] mb-[15px] relative list-item">
|
||||
<div v-for="(item,index) in diyBottomData.list" :key="'a'+index" :data-id="index" class="item-wrap !cursor-move border-2 border-dashed pt-[18px] m-[10px] mb-[15px] relative list-item">
|
||||
<el-form-item :label="t('navIconOne')">
|
||||
<div class="flex align-center">
|
||||
<div class="flex flex-col justify-center items-center">
|
||||
|
||||
@ -49,9 +49,6 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="with-ite absolute top-0 right-0 flex flex-col hidden">
|
||||
<span class="block pr-4 mt-3 text-primary" @click.stop="withEvent(item.key)"><el-icon size="18px"><StarFilled /> </el-icon></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -65,7 +62,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { getApply } from "@/app/api/apply";
|
||||
import { setStarAddon } from "@/app/api/auth";
|
||||
import { img } from "@/utils/common";
|
||||
import { findFirstValidRoute } from "@/router/routers";
|
||||
import useUserStore from "@/stores/modules/user";
|
||||
@ -108,12 +104,6 @@ const toLink = (addon: string) => {
|
||||
userStore.setAppMenuList(data);
|
||||
router.push({ name: appLink.value[addon] });
|
||||
};
|
||||
|
||||
const withEvent = (key: string) => {
|
||||
setStarAddon({ key: key }).then(() => {
|
||||
getApplelist();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -47,9 +47,6 @@
|
||||
<p class="app-text text-[14px] text-[#999] w-[200px]">{{ item.desc }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="with-ite absolute top-0 right-0 flex flex-col hidden">
|
||||
<span class="block pr-4 mt-3" :class="item.is_star == 2 ? 'text-primary' : 'text-[#999]'" @click.stop="withEvent(item.key)"><el-icon size="18px"><StarFilled /></el-icon></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -63,7 +60,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { getApply } from '@/app/api/apply'
|
||||
import { setStarAddon } from '@/app/api/auth'
|
||||
import { img } from '@/utils/common'
|
||||
import { findFirstValidRoute } from '@/router/routers'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
@ -102,12 +98,6 @@ getAppLink()
|
||||
const toLink = (addon: string) => {
|
||||
router.push({ name: appLink.value[addon] })
|
||||
}
|
||||
|
||||
const withEvent = (key: string) => {
|
||||
setStarAddon({key: key}).then(() => {
|
||||
getApplelist()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -29,14 +29,11 @@
|
||||
<p class="app-text w-[190px] text-[17px] text-[#222] pl-3">{{ item.title }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="with-ite absolute top-0 right-0 flex flex-col hidden">
|
||||
<span class="block pr-4 mt-3" :class="item.is_star == 2 ? 'text-primary' : 'text-[#999]'" @click.stop="withEvent(item.key)"><el-icon size="18px"><StarFilled /></el-icon></span>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="empty flex items-center justify-center" v-if="!loading&&!applyList.list.length" >
|
||||
<el-empty :description="t('emptyData')" />
|
||||
<el-empty :description="t('emptyAppData')" />
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
@ -46,24 +43,25 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { getApply } from '@/app/api/apply'
|
||||
import { setStarAddon } from '@/app/api/auth'
|
||||
import { img } from '@/utils/common'
|
||||
import { findFirstValidRoute } from '@/router/routers'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
import storage from '@/utils/storage'
|
||||
var key = storage.get('menuAppStorage')
|
||||
const userStore = useUserStore()
|
||||
const router = useRouter()
|
||||
const applyList = reactive({
|
||||
list: [],
|
||||
search: {
|
||||
title: ""
|
||||
title: "",
|
||||
key: key
|
||||
}
|
||||
})
|
||||
let loading = ref(true)
|
||||
const getApplelist = async () => {
|
||||
const res = await getApply({title: applyList.search.title})
|
||||
const res = await getApply({title: applyList.search.title,support_app:applyList.search.key})
|
||||
applyList.list = res.data.filter(el=>{
|
||||
return appLink.value[el.key] &&el.type == 'addon'
|
||||
})
|
||||
@ -97,12 +95,6 @@ const toLink = (addon: string) => {
|
||||
userStore.setAppMenuList(data)
|
||||
router.push({ name: appLink.value[addon] })
|
||||
}
|
||||
|
||||
const withEvent = (key: string) => {
|
||||
setStarAddon({key: key}).then(() => {
|
||||
getApplelist()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -25,7 +25,14 @@
|
||||
<div class="font-500 text-[13px] text-[#6D7278] mt-[14px]">{{ item.desc }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-empty :description="t('noPlug')" v-if="!detail.appList.length && !loading" class="mx-auto" />
|
||||
<el-empty v-if="!detail.appList.length && !loading" class="mx-auto overview-empty">
|
||||
<template #image>
|
||||
<div class="w-[230px] mx-auto"><img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt=""></div>
|
||||
</template>
|
||||
<template #description>
|
||||
<p class="flex items-center"><span>{{ t('descriptionLeft') }}</span><el-link type="primary" @click="goRouter">{{ t('link') }}</el-link><span>{{ t('descriptionRight') }}</span></p>
|
||||
</template>
|
||||
</el-empty>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -69,12 +76,15 @@ const itemPath = (key: any) => {
|
||||
}
|
||||
|
||||
}
|
||||
const goRouter = ()=>{
|
||||
window.open('https://www.niucloud.com/product/')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.main-container{
|
||||
background: linear-gradient(180deg, rgba(253,253,253,0.24) 0%, #FAFAFA 100%);
|
||||
min-height: calc(100vh - 63px);
|
||||
min-height: calc(100vh - 64px);
|
||||
}
|
||||
.overview-top {
|
||||
background-image: url('@/app/assets/images/index/overview.png');
|
||||
@ -86,3 +96,8 @@ const itemPath = (key: any) => {
|
||||
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.overview-empty .el-empty__image{
|
||||
width: auto !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -44,7 +44,7 @@
|
||||
</div>
|
||||
<div class="flex flex-wrap">
|
||||
<div class="flex flex-wrap" ref="shortcutModel" v-if="edit_menu">
|
||||
<div v-for="(items, index) in shortcut_menu" :style="{backgroundColor : items.bg_color}" :key="items.id" class="design-field w-[180px] h-[120px] relative mt-[30px] rounded-[5px] mr-[30px] cursor-pointer">
|
||||
<div v-for="(items, index) in shortcut_menu" :style="{backgroundColor : items.bg_color}" :key="items.id" class="design-field w-[180px] h-[120px] relative mt-[30px] rounded-[5px] mr-[30px] !cursor-move">
|
||||
<div class="flex items-center h-[88px]" @click="editModel(items)">
|
||||
<!-- <img class="ml-[24px] w-[40px]" :src="img(items.img)"/> -->
|
||||
<div class="ml-[24px] w-[40px]">
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<span class="text-[20px]">素材管理</span>
|
||||
</div>
|
||||
<el-tabs v-model="type" class="">
|
||||
<el-tabs v-model="type">
|
||||
<el-tab-pane :label="t(tab)" v-for="(tab, index) in attachmentType" :name="tab" :key="index">
|
||||
<attachment scene="attachment" :type="tab" />
|
||||
</el-tab-pane>
|
||||
@ -27,7 +27,7 @@
|
||||
<style lang="scss">
|
||||
.attachment-container {
|
||||
.el-card__body {
|
||||
height: 100%;
|
||||
height: 96%;
|
||||
}
|
||||
|
||||
.el-tabs {
|
||||
|
||||
@ -52,7 +52,7 @@
|
||||
<el-table :data="formData.table_column" size="large" ref="tableRef" :key="toggleIndex">
|
||||
<el-table-column align="center" label="操作" width="80">
|
||||
<template #default>
|
||||
<i class="iconfont iconfenlei vues-rank cursor-pointer"></i>
|
||||
<i class="iconfont icontuodong vues-rank cursor-move"></i>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('columnName')" prop="column_name" min-width="130px" />
|
||||
|
||||
@ -1,637 +0,0 @@
|
||||
<template>
|
||||
<div class="main-container mb-80" v-loading="loading">
|
||||
<div class="detail-head !mb-[10px]">
|
||||
<div class="left" @click="router.push({ path: '/tools/code' })">
|
||||
<span class="iconfont iconxiangzuojiantou !text-xs"></span>
|
||||
<span class="ml-[1px]">{{t('returnToPreviousPage')}}</span>
|
||||
</div>
|
||||
<span class="adorn">|</span>
|
||||
<span class="right">{{ pageName }}</span>
|
||||
</div>
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form">
|
||||
<el-form-item :label="t('tableName')" prop="table_name">
|
||||
<el-input v-model="formData.table_name" clearable :placeholder="t('tableNamePlaceholder')" class="input-width" maxlength="64" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('tableContent')" prop="table_content">
|
||||
<el-input v-model="formData.table_content" clearable :placeholder="t('tableContentPlaceholder')" class="input-width" maxlength="64" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('moduleName')">
|
||||
<el-input v-model="formData.module_name" clearable :placeholder="t('moduleNamePlaceholder')" class="input-width" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('className')">
|
||||
<el-input v-model="formData.class_name" clearable :placeholder="t('classNamePlaceholder')" class="input-width" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('editType')">
|
||||
<el-radio-group v-model="formData.edit_type" :placeholder="t('editTypePlaceholder')">
|
||||
<el-radio :label="1">{{ t('popup') }}</el-radio>
|
||||
<el-radio :label="2">{{ t('page') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-row class="flex mt-4" :gutter="15">
|
||||
<el-col :span="6">
|
||||
<el-card class="box-card !border-none p-none" shadow="never">
|
||||
<el-divider content-position="left">{{ t('commentField') }}</el-divider>
|
||||
<div class="flex flex-row m-0.5 cursor-pointer flex-wrap" :ref="tabsRefs.set">
|
||||
<div class="border border-dashed border-gray-200 mt-2 text-sm mr-2 pt-1 pb-1 pl-1.5 pr-1.5 dashed-border design-field" v-for="(item, index) in fieldList.common" :key="index" :data-id="index">{{ item.column_comment }}</div>
|
||||
</div>
|
||||
<el-divider content-position="left">{{ t('baseField') }}</el-divider>
|
||||
<div class="flex flex-row m-0.5 cursor-pointer flex-wrap" :ref="tabsRefs.set">
|
||||
<div class="border border-dashed border-gray-200 mt-2 text-sm mr-2 pt-1 pb-1 pl-1.5 pr-1.5 dashed-border design-field" v-for="(item, index) in fieldList.base" :key="index" :data-id="index">{{ item.column_comment }}</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card !border-none p-none" shadow="never">
|
||||
<div class="flex flex-col" ref="fieldBoxRef">
|
||||
<div class="flex flex-row m-0.5 cursor-pointer justify-between items-center border border-dashed border-gray-200 dashed-border p-2 pt-1 pb-1" v-for="(item, index) in formData.table_column" :key="index" :data-id="index" @click="onActivateField(index)" :class="index === formData.editFiledIndex ? 'activate' : ''">
|
||||
<div class="flex flex-row ">
|
||||
<div class="flex flex-row design-field">
|
||||
<div class="text-xs text-gray-500 w-28 items-center justify-end flex">{{t('columnName') }}:</div>
|
||||
<el-input class="w-50 m-2" v-model="item.column_name" size="small" :placeholder="t('columnNamePlaceholder')" />
|
||||
</div>
|
||||
<div class="flex flex-row design-field">
|
||||
<div class="text-xs text-gray-500 w-28 items-center justify-end flex">{{ t('columnComment') }}:</div>
|
||||
<el-input class="w-50 m-2" v-model="item.column_comment" size="small" :placeholder="t('columnCommentPlaceholder')" />
|
||||
</div>
|
||||
<div class="flex flex-row design-field flex-shrink-0 w-40">
|
||||
<div class="text-xs text-gray-500 w-20 items-center justify-end flex">{{t('columnType') }}:</div>
|
||||
<div class="w-50 m-2">{{ item.column_type }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div @click="onDel(index)" class="items-center justify-center flex items-center flex-shrink-0 rounded-full bg-red-400 text-white icon-btn w-7 h-7">
|
||||
<el-icon>
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card class="box-card !border-none p-none" shadow="never" v-if="formData.table_column.length">
|
||||
|
||||
<el-divider content-position="left">{{ t('fieldAttribute') }}</el-divider>
|
||||
<div>
|
||||
<div class="flex flex-row">
|
||||
<div class="text-xs text-gray-500 w-20 items-center justify-end flex">{{ t('columnName') }}:
|
||||
</div>
|
||||
<div>
|
||||
<el-input class="w-50 m-2"
|
||||
v-model="formData.table_column[formData.editFiledIndex]['column_name']" size="small"
|
||||
:placeholder="t('columnNamePlaceholder')" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row ">
|
||||
<div class="text-xs text-gray-500 w-20 items-center justify-end flex">{{ t('columnComment') }}:
|
||||
</div>
|
||||
<div>
|
||||
<el-input class="w-50 m-2" v-model="formData.table_column[formData.editFiledIndex]['column_comment']" size="small" :placeholder="t('columnCommentPlaceholder')" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row ">
|
||||
<div class="text-xs text-gray-500 w-20 items-center justify-end flex">{{ t('isPk') }}:</div>
|
||||
<div>
|
||||
<el-radio-group class="ml-4" v-model="formData.table_column[formData.editFiledIndex]['is_pk']">
|
||||
<el-radio :label="1" size="large">{{ t('yes') }}</el-radio>
|
||||
<el-radio :label="0" size="large">{{ t('no') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row ">
|
||||
<div class="text-xs text-gray-500 w-20 items-center justify-end flex">{{ t('viewType') }}:
|
||||
</div>
|
||||
<div>
|
||||
<el-select class="m-2" :placeholder="t('selectPlaceholder')" size="small" v-model="formData.table_column[formData.editFiledIndex]['view_type']">
|
||||
<el-option :label="item.label" :value="item.value" v-for="(item, index) in viewType" :key="index" />
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-divider content-position="left">{{t('addAndEdit')}}</el-divider>
|
||||
<div>
|
||||
<div class="flex flex-row ">
|
||||
<div class="text-xs text-gray-500 w-20 items-center justify-end flex">{{ t('isInsert') }}:
|
||||
</div>
|
||||
<div>
|
||||
<el-radio-group class="ml-4" v-model="formData.table_column[formData.editFiledIndex]['is_insert']">
|
||||
<el-radio :label="1" size="large">{{ t('yes') }}</el-radio>
|
||||
<el-radio :label="0" size="large">{{ t('no') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row ">
|
||||
<div class="text-xs text-gray-500 w-20 items-center justify-end flex">{{ t('isUpdate') }}:
|
||||
</div>
|
||||
<div>
|
||||
<el-radio-group class="ml-4" v-model="formData.table_column[formData.editFiledIndex]['is_update']">
|
||||
<el-radio :label="1" size="large">{{ t('yes') }}</el-radio>
|
||||
<el-radio :label="0" size="large">{{ t('no') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row ">
|
||||
<div class="text-xs text-gray-500 w-20 items-center justify-end flex">{{ t('isRequired') }}:
|
||||
</div>
|
||||
<div>
|
||||
<el-radio-group class="ml-4" v-model="formData.table_column[formData.editFiledIndex]['is_required']">
|
||||
<el-radio :label="1" size="large">{{ t('yes') }}</el-radio>
|
||||
<el-radio :label="0" size="large">{{ t('no') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-divider content-position="left">{{t('listSearch')}}</el-divider>
|
||||
<div>
|
||||
|
||||
<div class="flex flex-row ">
|
||||
<div class="text-xs text-gray-500 w-20 items-center justify-end flex">{{ t('isLists') }}:</div>
|
||||
<div>
|
||||
<el-radio-group class="ml-4" v-model="formData.table_column[formData.editFiledIndex]['is_lists']">
|
||||
<el-radio :label="1" size="large">{{ t('yes') }}</el-radio>
|
||||
<el-radio :label="0" size="large">{{ t('no') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row ">
|
||||
<div class="text-xs text-gray-500 w-20 items-center justify-end flex">{{ t('isSearch') }}:
|
||||
</div>
|
||||
<div>
|
||||
<el-radio-group class="ml-4" v-model="formData.table_column[formData.editFiledIndex]['is_search']">
|
||||
<el-radio :label="1" size="large">{{ t('yes') }}</el-radio>
|
||||
<el-radio :label="0" size="large">{{ t('no') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row ">
|
||||
<div class="text-xs text-gray-500 w-20 items-center justify-end flex">{{ t('isQuery') }}:</div>
|
||||
<div>
|
||||
<el-radio-group class="ml-4" v-model="formData.table_column[formData.editFiledIndex]['is_query']">
|
||||
<el-radio :label="1" size="large">{{ t('yes') }}</el-radio>
|
||||
<el-radio :label="0" size="large">{{ t('no') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row ">
|
||||
<div class="text-xs text-gray-500 w-20 items-center justify-end flex">{{ t('queryType') }}:
|
||||
</div>
|
||||
<div>
|
||||
<el-select class="m-2" :placeholder="t('selectPlaceholder')" size="small" v-model="formData.table_column[formData.editFiledIndex]['query_type']">
|
||||
<el-option :label="item" :value="item" v-for="(item, index) in queryType" :key="index" />
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<div class="fixed-footer-wrap">
|
||||
<div class="fixed-footer">
|
||||
<el-button type="primary" @click="onSave(formRef)">{{ t('save') }}</el-button>
|
||||
<el-button @click="back()">{{ t('cancel') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed, onMounted, nextTick } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { FormInstance, ElNotification } from 'element-plus'
|
||||
import { getGenerateTableInfo, editGenerateTable } from '@/app/api/tools'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import Sortable, { SortableEvent } from 'sortablejs'
|
||||
import { useTemplateRefsList } from '@vueuse/core'
|
||||
import { cloneDeep, range } from 'lodash-es'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
|
||||
const appStore = useAppStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const pageName = route.meta.title
|
||||
|
||||
const id: number = parseInt(route.query.id || 0)
|
||||
|
||||
const loading = ref(true)
|
||||
const tabsRefs = useTemplateRefsList<HTMLElement>()
|
||||
const fieldBoxRef = ref()
|
||||
let nameRepeatCount = 1
|
||||
|
||||
const fieldData: any = {
|
||||
column_name: '',
|
||||
column_comment: '',
|
||||
column_type: '',
|
||||
is_required: 1,
|
||||
is_pk: 1,
|
||||
is_insert: 1,
|
||||
is_update: 1,
|
||||
is_lists: 1,
|
||||
is_query: 1,
|
||||
is_search: 1,
|
||||
query_type: '=',
|
||||
view_type: 'input'
|
||||
}
|
||||
/**
|
||||
* 表单数据
|
||||
*/
|
||||
const initialFormData = {
|
||||
id: '',
|
||||
table_name: '',
|
||||
table_content: '',
|
||||
module_name: '',
|
||||
class_name: '',
|
||||
edit_type: 1,
|
||||
table_column: [],
|
||||
editFiledIndex: 0
|
||||
}
|
||||
|
||||
const fieldList: {
|
||||
common: fieldData[],
|
||||
base: fieldData[],
|
||||
} = {
|
||||
common: [
|
||||
{
|
||||
column_name: 'id',
|
||||
column_comment: t('pk'),
|
||||
column_type: 'int',
|
||||
is_required: 1,
|
||||
is_pk: 1,
|
||||
is_insert: 0,
|
||||
is_update: 0,
|
||||
is_lists: 0,
|
||||
is_query: 1,
|
||||
is_search: 0,
|
||||
query_type: '=',
|
||||
view_type: 'input'
|
||||
},
|
||||
{
|
||||
column_name: 'status',
|
||||
column_comment: t('status'),
|
||||
column_type: 'int',
|
||||
is_required: 1,
|
||||
is_pk: 0,
|
||||
is_insert: 1,
|
||||
is_update: 1,
|
||||
is_lists: 1,
|
||||
is_query: 1,
|
||||
is_search: 0,
|
||||
query_type: '=',
|
||||
view_type: 'radio'
|
||||
},
|
||||
{
|
||||
column_name: 'create_time',
|
||||
column_comment: t('createTime'),
|
||||
column_type: 'int',
|
||||
is_required: 0,
|
||||
is_pk: 0,
|
||||
is_insert: 0,
|
||||
is_update: 0,
|
||||
is_lists: 1,
|
||||
is_query: 1,
|
||||
is_search: 0,
|
||||
query_type: 'BETWEEN',
|
||||
view_type: 'datetime'
|
||||
},
|
||||
{
|
||||
column_name: 'update_time',
|
||||
column_comment: t('updateTime'),
|
||||
column_type: 'int',
|
||||
is_required: 0,
|
||||
is_pk: 0,
|
||||
is_insert: 0,
|
||||
is_update: 0,
|
||||
is_lists: 1,
|
||||
is_query: 1,
|
||||
is_search: 0,
|
||||
query_type: 'BETWEEN',
|
||||
view_type: 'datetime'
|
||||
}
|
||||
|
||||
],
|
||||
base: [
|
||||
{
|
||||
column_name: 'string',
|
||||
column_comment: t('string'),
|
||||
column_type: 'string',
|
||||
is_required: 1,
|
||||
is_pk: 0,
|
||||
is_insert: 1,
|
||||
is_update: 1,
|
||||
is_lists: 1,
|
||||
is_query: 1,
|
||||
is_search: 1,
|
||||
query_type: '=',
|
||||
view_type: 'input'
|
||||
},
|
||||
{
|
||||
column_name: 'image',
|
||||
column_comment: t('image'),
|
||||
column_type: 'string',
|
||||
is_required: 1,
|
||||
is_pk: 0,
|
||||
is_insert: 1,
|
||||
is_update: 1,
|
||||
is_lists: 1,
|
||||
is_query: 1,
|
||||
is_search: 1,
|
||||
query_type: '=',
|
||||
view_type: 'imageSelect'
|
||||
},
|
||||
{
|
||||
column_name: 'radio',
|
||||
column_comment: t('radio'),
|
||||
column_type: 'int',
|
||||
is_required: 1,
|
||||
is_pk: 0,
|
||||
is_insert: 1,
|
||||
is_update: 1,
|
||||
is_lists: 1,
|
||||
is_query: 1,
|
||||
is_search: 1,
|
||||
query_type: '=',
|
||||
view_type: 'radio'
|
||||
},
|
||||
{
|
||||
column_name: 'checkbox',
|
||||
column_comment: t('checkbox'),
|
||||
column_type: 'string',
|
||||
is_required: 1,
|
||||
is_pk: 0,
|
||||
is_insert: 1,
|
||||
is_update: 1,
|
||||
is_lists: 1,
|
||||
is_query: 1,
|
||||
is_search: 1,
|
||||
query_type: '=',
|
||||
view_type: 'checkbox'
|
||||
},
|
||||
{
|
||||
column_name: 'select',
|
||||
column_comment: t('select'),
|
||||
column_type: 'string',
|
||||
is_required: 1,
|
||||
is_pk: 0,
|
||||
is_insert: 1,
|
||||
is_update: 1,
|
||||
is_lists: 1,
|
||||
is_query: 1,
|
||||
is_search: 1,
|
||||
query_type: '=',
|
||||
view_type: 'select'
|
||||
},
|
||||
{
|
||||
column_name: 'editor',
|
||||
column_comment: t('editor'),
|
||||
column_type: 'string',
|
||||
is_required: 1,
|
||||
is_pk: 0,
|
||||
is_insert: 1,
|
||||
is_update: 1,
|
||||
is_lists: 1,
|
||||
is_query: 1,
|
||||
is_search: 1,
|
||||
query_type: '=',
|
||||
view_type: 'editor'
|
||||
},
|
||||
{
|
||||
column_name: 'datetime',
|
||||
column_comment: t('dateTime'),
|
||||
column_type: 'string',
|
||||
is_required: 1,
|
||||
is_pk: 0,
|
||||
is_insert: 1,
|
||||
is_update: 1,
|
||||
is_lists: 1,
|
||||
is_query: 1,
|
||||
is_search: 1,
|
||||
query_type: '=',
|
||||
view_type: 'datetime'
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
const queryType = ['=', '!=', '>', '>=', '<', '<=', 'LIKE', 'BETWEEN']
|
||||
const viewType = [
|
||||
{
|
||||
label: t('formInput'),
|
||||
value: 'input'
|
||||
},
|
||||
{
|
||||
label: t('formTextarea'),
|
||||
value: 'textarea'
|
||||
},
|
||||
{
|
||||
label: t('formSelect'),
|
||||
value: 'select'
|
||||
},
|
||||
{
|
||||
label: t('formRadio'),
|
||||
value: 'radio'
|
||||
},
|
||||
{
|
||||
label: t('formCheckbox'),
|
||||
value: 'checkbox'
|
||||
},
|
||||
{
|
||||
label: t('formDateTime'),
|
||||
value: 'datetime'
|
||||
},
|
||||
{
|
||||
label: t('formImageSelect'),
|
||||
value: 'imageSelect'
|
||||
},
|
||||
{
|
||||
label: t('formEditor'),
|
||||
value: 'editor'
|
||||
}
|
||||
]
|
||||
|
||||
interface SortableEvt extends SortableEvent {
|
||||
originalEvent?: DragEvent
|
||||
}
|
||||
|
||||
const onActivateField = (idx: number) => {
|
||||
formData.editFiledIndex = idx
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const sortable = Sortable.create(fieldBoxRef.value, {
|
||||
group: 'design-field',
|
||||
animation: 200,
|
||||
onAdd: (evt: SortableEvt) => {
|
||||
const name = evt.originalEvent?.dataTransfer?.getData('name')
|
||||
const field = fieldList[name]
|
||||
|
||||
if (field && field[evt.oldIndex!]) {
|
||||
const data = cloneDeep(field[evt.oldIndex!])
|
||||
|
||||
if (data.is_pk) {
|
||||
const is_pk = formData.table_column.find((item: { is_pk: any; }) => {
|
||||
return item.is_pk
|
||||
})
|
||||
if (is_pk) {
|
||||
ElNotification({
|
||||
type: 'error',
|
||||
message: t('pkRepeatTip')
|
||||
})
|
||||
return evt.item.remove()
|
||||
}
|
||||
formData.table_column.defaultSortField = data.name
|
||||
formData.table_column.quickSearchField.push(data.name)
|
||||
}
|
||||
|
||||
const isRepeat = getArrayKey(formData.table_column, 'column_name', data.column_name)
|
||||
if (isRepeat) {
|
||||
data.column_name = data.column_name + nameRepeatCount
|
||||
nameRepeatCount++
|
||||
}
|
||||
formData.table_column.splice(evt.newIndex!, 0, data)
|
||||
}
|
||||
evt.item.remove()
|
||||
nextTick(() => {
|
||||
sortable.sort(range(formData.table_column.length).map((value) => value.toString()))
|
||||
})
|
||||
},
|
||||
onEnd: (evt) => {
|
||||
const temp = formData.table_column[evt.oldIndex!]
|
||||
formData.table_column.splice(evt.oldIndex!, 1)
|
||||
formData.table_column.splice(evt.newIndex!, 0, temp)
|
||||
|
||||
nextTick(() => {
|
||||
sortable.sort(range(formData.table_column.length).map((value) => value.toString()))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
tabsRefs.value.forEach((item, index) => {
|
||||
Sortable.create(item, {
|
||||
sort: false,
|
||||
group: {
|
||||
name: 'design-field',
|
||||
pull: 'clone',
|
||||
put: false
|
||||
},
|
||||
animation: 200,
|
||||
setData: (dataTransfer) => {
|
||||
dataTransfer.setData('name', Object.keys(fieldList)[index])
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const getArrayKey = (arr: any, pk: string, value: string): any => {
|
||||
for (const key in arr) {
|
||||
if (arr[key][pk] == value) {
|
||||
return key
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
|
||||
const setFormData = async (id: number = 0) => {
|
||||
Object.assign(formData, initialFormData)
|
||||
const data = await (await getGenerateTableInfo(id)).data
|
||||
Object.keys(formData).forEach((key: string) => {
|
||||
if (data[key] != undefined) formData[key] = data[key]
|
||||
})
|
||||
|
||||
loading.value = false
|
||||
}
|
||||
if (id) setFormData(id)
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const validataVarName = (val: string) => {
|
||||
return /^([a-zA-Z_$])([a-zA-Z0-9_$])*$/.test(val)
|
||||
}
|
||||
|
||||
// 表单验证规则
|
||||
const formRules = computed(() => {
|
||||
return {
|
||||
table_name: [
|
||||
{ required: true, message: t('tableNamePlaceholder'), trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
if (!validataVarName(value)) {
|
||||
callback(new Error(t('tableNameValidata')))
|
||||
}
|
||||
|
||||
callback()
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
|
||||
],
|
||||
table_content: [
|
||||
{ required: true, message: t('tableContentPlaceholder'), trigger: 'blur' }
|
||||
]
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
const onSave = async (formEl: FormInstance | undefined) => {
|
||||
if (loading.value || !formEl) return
|
||||
let msg = ''
|
||||
formData.table_column.find((item) => {
|
||||
if (!validataVarName(item.column_name)) {
|
||||
msg = item.column_name + ' ' + t('fieldNameValidata')
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
if (msg) {
|
||||
ElNotification({
|
||||
type: 'error',
|
||||
message: msg
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
const data = cloneDeep(formData)
|
||||
data.table_column = JSON.stringify(data.table_column)
|
||||
editGenerateTable(data).then((res: any) => {
|
||||
loading.value = false
|
||||
}).catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
const onDel = (index: number) => {
|
||||
if (!formData.table_column[index]) return
|
||||
if (formData.editFiledIndex == index) formData.editFiledIndex = 0
|
||||
formData.table_column.splice(index, 1)
|
||||
}
|
||||
const back = () => {
|
||||
router.push({ path: '/tools/code' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dashed-border {
|
||||
border-color: var(--el-border-color-light);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
&.activate {
|
||||
border-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.icon-btn {
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
</style>
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="main-container attachment-container" v-loading="loadingArr.server_load">
|
||||
<el-card class="box-card !border-none" shadow="never" v-if="systemService">
|
||||
<div class="main-container attachment-container min-h-[80vh]" v-loading="loadingArr.server_load">
|
||||
<el-card class="box-card !border-none" shadow="never" v-if="systemService && !loadingArr.server_load">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-[20px]">{{ pageName }}</span>
|
||||
</div>
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<span class="text-sm truncate w-[190px]">{{t('refreshMenu')}}</span>
|
||||
<span class="text-xs text-gray-400 mt-1 truncate w-[190px]" :title="t('refreshMenuDesc')">{{t('refreshMenuDesc')}}</span>
|
||||
</div>
|
||||
<span class="plug-item-operate" @click="refreshMenu()">{{t('refresh')}}</span>
|
||||
<span class="plug-item-operate" @click="refreshMenu()">{{t('resetting')}}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center bg-[#F7F8FA] p-3 w-[295px] relative plug-item mr-4 mb-4 cursor-pointer">
|
||||
@ -23,39 +23,37 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { clearSchemaCache, menuRefresh } from '@/app/api/sys'
|
||||
import { clearSchemaCache, menuRefresh } from '@/app/api/sys'
|
||||
|
||||
let loading = ref<Boolean>(false);
|
||||
const loading = ref<Boolean>(false)
|
||||
|
||||
// 数据缓存
|
||||
const schemaCache = () => {
|
||||
loading.value = true;
|
||||
loading.value = true
|
||||
clearSchemaCache({}).then(res => {
|
||||
loading.value = false;
|
||||
loading.value = false
|
||||
setTimeout(() => {
|
||||
//需要定时执行的代码
|
||||
// 需要定时执行的代码
|
||||
location.reload()
|
||||
}, 500)
|
||||
}, 500)
|
||||
}).catch(() => {
|
||||
loading.value = false;
|
||||
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
// 更新菜单
|
||||
const refreshMenu = ()=> {
|
||||
loading.value = true;
|
||||
menuRefresh({}).then(res => {
|
||||
loading.value = false;
|
||||
const refreshMenu = () => {
|
||||
loading.value = true
|
||||
menuRefresh({}).then(res => {
|
||||
loading.value = false
|
||||
setTimeout(() => {
|
||||
//需要定时执行的代码
|
||||
// 需要定时执行的代码
|
||||
location.reload()
|
||||
}, 500)
|
||||
}).catch(() => {
|
||||
loading.value = false;
|
||||
})
|
||||
}, 500)
|
||||
}).catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -10,8 +10,8 @@
|
||||
{{ t('selectPlaceholder') }}
|
||||
</div>
|
||||
<div class="group-item px-[10px] text-xs rounded cursor-pointer flex" v-for="(item, index) in attachmentCategory.data" :key="index" :class="{ active: attachmentParam.cate_id == item.id }">
|
||||
<div class="flex-1 leading-none truncate py-[10px]" @click="attachmentParam.cate_id = item.id">{{item.name }}</div>
|
||||
<div class="leading-none operate py-[10px]" v-if="scene == 'attachment' && prop.type !='icon' ">
|
||||
<div class="flex-1 leading-none truncate py-[10px] h-[34px]" @click="attachmentParam.cate_id = item.id">{{item.name }}</div>
|
||||
<div class="leading-none operate py-[10px] h-[34px]" v-if="scene == 'attachment' && prop.type !='icon' ">
|
||||
<!-- 图片操作 -->
|
||||
<el-dropdown :hide-on-click="false" v-if="scene == 'attachment'">
|
||||
<icon name="element-MoreFilled" class="cursor-pointer ml-[10px]" size="14px"/>
|
||||
|
||||
@ -75,6 +75,7 @@
|
||||
"layoutSetting": "主题设置",
|
||||
"darkMode": "黑暗模式",
|
||||
"sidebarMode": "主题风格",
|
||||
"sidebarStyle": "主题样式",
|
||||
"themeColor": "主题颜色",
|
||||
"detectionLoginOperation": "确定",
|
||||
"detectionLoginContent": "已检测到有其他账号登录,需要刷新后才能继续操作。",
|
||||
@ -125,5 +126,6 @@
|
||||
"generateEmail":"请输入正确的邮箱号",
|
||||
"generateMax":"超过最多输入字符数",
|
||||
"generateMin":"少于最少输入字符数",
|
||||
"generateBetween":"请输入正确的字符信息"
|
||||
"generateBetween":"请输入正确的字符信息",
|
||||
"emptyAppData":"暂无应用"
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div :class="[{'group-hover:flex': props.isShowHover},'hidden fixed left-0 top-[65px] z-[5555] bg-[#fff] w-[640px] px-[28px] py-[20px] flex-wrap box-border shadow-lg ']">
|
||||
<div v-for="(item, index) in data" :key="index" @click="toLink(item, props.hoverType)" class="flex items-center cursor-pointer text-[#6d7278] hover:bg-[#f1f2f6] whitespace-nowrap py-[10px] px-[15px] box-border w-[165px]">
|
||||
<img :src="img(item.icon)" class="w-[44px] h-[44px] rounded-full mr-[5px]" alt="" :title="item.title">
|
||||
<span>{{ item.title }}</span>
|
||||
</div>
|
||||
<div v-if="!data.length" class="flex-1 flex flex-col justify-center items-center pb-[30px]">
|
||||
<div class="w-[130px]"><img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt=""></div>
|
||||
<div class="text-[14px] text-[#909399]">暂无安装任何应用或插件,马上去<a href="https://www.niucloud.com/product/" target="_blank" class="text-[var(--el-color-primary)]">官方应用市场</a>逛逛</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { img } from '@/utils/common'
|
||||
const props = defineProps(['isShowHover','data','hoverType'])
|
||||
console.log();
|
||||
let data = ref([]);
|
||||
if(props.data){
|
||||
props.data.forEach((item,index) => {
|
||||
if(item.type == "app"){
|
||||
data.value.push(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
const emit = defineEmits(['child-click'])
|
||||
const toLink = (data,type)=>{
|
||||
emit('child-click',data,type)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
543
admin/src/layout/business/components/aside/index.vue
Normal file
543
admin/src/layout/business/components/aside/index.vue
Normal file
@ -0,0 +1,543 @@
|
||||
<template>
|
||||
<div :class="['flex', { 'two-type': sidebar == 'twoType' }, { 'three-type': sidebar == 'threeType' }]" v-if="isLoad">
|
||||
<div class="w-[124px] overflow-hidden">
|
||||
<!-- , { 'bright': !dark } -->
|
||||
<el-aside :class="['h-screen layout-aside w-[124px] pb-[30px] px-[8px] bg-[#202033] ease-in duration-200']">
|
||||
<div class="h-full flex flex-col relative">
|
||||
<div class="group flex items-center justify-center h-[64px] cursor-pointer" v-if="!globalAppKey" @mouseenter="threefloatMenuHover">
|
||||
<span class="iconfont iconyun1 !text-[32px] !w-auto text-[#fff]"></span>
|
||||
<app-menu :isShowHover="threefloatMenu" :data="applyList" @child-click="toLink" hoverType='threefloatMenu'></app-menu>
|
||||
</div>
|
||||
|
||||
<template v-for="(item, index) in menus" :key="index">
|
||||
<template v-if="globalAppKey == item.meta.app && item.meta.parentTitle">
|
||||
<div class="group flex items-center justify-center h-[64px] cursor-pointer" @mouseenter="threefloatMenuHover">
|
||||
<img v-if="item.meta.parentIcon" :src="img(item.meta.parentIcon)" class="w-[40px] h-[40px]" alt="">
|
||||
<div class="flex items-center justify-center w-[30px] h-[30px]" v-else>
|
||||
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto" size="24px" />
|
||||
</div>
|
||||
<app-menu :isShowHover="threefloatMenu" :data="applyList" @child-click="toLink" hoverType='threefloatMenu'></app-menu>
|
||||
</div>
|
||||
<div v-for="(appItem, appIndex) in item.children" :key="appIndex" @click="toLink(appItem)"
|
||||
:class="['rounded-sm flex items-center px-[8px] mb-[4px] h-[40px] cursor-pointer text-[#b9b9bf] hover:bg-[var(--el-color-primary)] hover:!text-[#fff] menu-item hover:text-color whitespace-nowrap', { 'bg-[var(--el-color-primary)] !text-[#fff] menu-item-active ': localMenuKey == appItem.meta.key}]">
|
||||
<icon v-if="appItem.meta.icon" :name="appItem.meta.icon" class="!w-auto" size="20px" :title="appItem.meta.title" />
|
||||
<span class="text-[14px] ml-[8px]">{{appItem.meta.shortTitle}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<template v-for="(item, index) in menus" :key="index">
|
||||
<div v-if="!item.meta.app && (item.meta.attr == 'common' || item.meta.attr == 'system')" @click="toLink(item)"
|
||||
:class="['rounded-sm flex items-center px-[8px] mb-[4px] h-[40px] cursor-pointer text-[#b9b9bf] hover:bg-[var(--el-color-primary)] hover:!text-[#fff] menu-item hover:text-color whitespace-nowrap', { 'bg-[var(--el-color-primary)] !text-[#fff] menu-item-active ': (item.path == currentRoute.path || (currentRoute.path == '/admin' && item.path == '/index') || (currentRoute.meta.app && item.path == '/index')) }]">
|
||||
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto" size="20px" :title="item.meta.title" />
|
||||
<span class="text-[14px] ml-[8px]">{{item.meta.shortTitle}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-aside>
|
||||
</div>
|
||||
|
||||
<template v-for="(item, index) in menus" :key="index">
|
||||
<div v-if="isTwoMenuFn(item)" class="w-[155px] box-border border-r-[1px] border-solid second-menu">
|
||||
<div class="group flex flex-col items-center justify-center h-[64px] border-b-[1px] border-solid second-head cursor-pointer relative" @mouseenter="twofloatMenuHover">
|
||||
{{ item.meta.title }}
|
||||
</div>
|
||||
|
||||
<el-scrollbar class="overflow-y-auto menus-wrap">
|
||||
<el-menu class="apply-menu !border-0" :router="true" unique-opened="true" :default-active="String(route.name)">
|
||||
<template v-for="(twoMenu, twoIndex) in item.children">
|
||||
<el-sub-menu :index="String(twoMenu.meta.title)" v-if="twoMenu.children && twoMenu.meta.show">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(threeMenu, threeIndex) in twoMenu.children" :key="threeIndex">
|
||||
<!-- 三级菜单 -->
|
||||
<el-sub-menu :index="String(threeMenu.meta.title)" class="three-menu"
|
||||
v-if="threeMenu.children && threeMenu.meta.show">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(fourMenu, fourIndex) in threeMenu.children" :key="fourIndex">
|
||||
<el-sub-menu :index="String(fourMenu.meta.title)"
|
||||
v-if="fourMenu.children && fourMenu.meta.show">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ fourMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(fiveMenu, fiveIndex) in fourMenu.children"
|
||||
:key="fiveIndex">
|
||||
<el-menu-item v-if="fiveMenu.meta.show" class="!h-[52px] !pl-[55px]"
|
||||
:index="String(fiveMenu.name)" @click="toLink(fiveMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ fiveMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-else-if="fourMenu.meta.show" class="!h-[52px] !pl-[35px]"
|
||||
:index="String(fourMenu.name)" @click="toLink(fourMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ fourMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
|
||||
<!-- 二级菜单 -->
|
||||
<el-menu-item v-else-if="threeMenu.meta.show" class="!h-[52px] !pl-[42px]"
|
||||
:index="String(threeMenu.name)" @click="toLink(threeMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
|
||||
<el-menu-item v-else-if="twoMenu.meta.show && twoMenu.meta.key != 'official_market'"
|
||||
class="!pl-[25px] text-[#333]" :index="String(twoMenu.name)" @click="toLink(twoMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
<div class="flex items-center !px-[25px] h-[56px] cursor-pointer text-[#333] el-menu-item"
|
||||
v-else-if="twoMenu.meta.show && twoMenu.meta.key == 'official_market'"
|
||||
@click="toLink(twoMenu)">
|
||||
<span class="text-[14px]">{{ twoMenu.meta.title }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-menu-item v-if="!item.children" class="!pl-[25px] text-[#333]" :index="String(item.name)" @click="toLink(item)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ item.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
<!-- 插件菜单 -->
|
||||
<template v-if="plugMenuType && localMenuKey == 'app_center'">
|
||||
<template v-for="(twoMenu, twoIndex) in menus">
|
||||
<el-sub-menu :index="String(twoMenu.meta.title)" v-if="twoMenu.meta.app && twoMenu.meta.app == plugMenuType && twoMenu.children">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(threeMenu, threeIndex) in twoMenu.children" :key="threeIndex">
|
||||
<!-- 三级菜单 -->
|
||||
<el-sub-menu :index="String(threeMenu.meta.title)"
|
||||
v-if="threeMenu.children && threeMenu.meta.show">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(fourMenu, fourIndex) in threeMenu.children"
|
||||
:key="fourIndex">
|
||||
<el-menu-item v-if="fourMenu.meta.show"
|
||||
class="!h-[52px] !pl-[55px]"
|
||||
:index="String(fourMenu.name)"
|
||||
@click="toLink(fourMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ fourMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-else-if="threeMenu.meta.show"
|
||||
class="!h-[52px] !pl-[35px]"
|
||||
:index="String(threeMenu.name)" @click="toLink(threeMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-else-if="twoMenu.meta.app && twoMenu.meta.app == plugMenuType"
|
||||
class="!pl-[25px] text-[#333]" :index="String(twoMenu.name)"
|
||||
@click="toLink(twoMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</template>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import side from './side.vue'
|
||||
import appMenu from './components/app-menu.vue'
|
||||
import { img } from '@/utils/common'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import storage from '@/utils/storage'
|
||||
import { CollectionTag } from '@element-plus/icons-vue'
|
||||
import { findFirstValidRoute } from '@/router/routers'
|
||||
import { getAddonByKey } from '@/app/api/addon'
|
||||
import { getApply } from '@/app/api/apply'
|
||||
|
||||
|
||||
const userStore = useUserStore()
|
||||
const systemStore = useSystemStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const globalAppKey = ref('') // 菜单类型
|
||||
const localMenuKey = ref('') // 菜单类型
|
||||
globalAppKey.value = storage.get('menuAppStorage')
|
||||
localMenuKey.value = storage.get('menuAppStorage')
|
||||
const isLoad = ref(false);
|
||||
|
||||
|
||||
// 应用跳转 start
|
||||
const applyList = ref([])
|
||||
const applyTypeList = ref([])
|
||||
const otherTypeList = ref([]) // 存着插件\会员\应用管理
|
||||
const getApplelist = async () => {
|
||||
const res = await getApply()
|
||||
applyList.value = applyList.value.concat(res.data)
|
||||
applyList.value.forEach((item, index) => {
|
||||
if (item.type == 'app') { applyTypeList.value.push(item.key) }
|
||||
if (item.type == 'addon') { otherTypeList.value.push(item.key) }
|
||||
})
|
||||
isLoad.value = true;
|
||||
}
|
||||
getApplelist()
|
||||
|
||||
// 应用跳转 end
|
||||
|
||||
// 菜单
|
||||
const appLink = ref({})
|
||||
const menus = computed(() => {
|
||||
const menus = []
|
||||
userStore.routers.forEach((item, index) => {
|
||||
if (item.children && item.children.length) {
|
||||
item.name = findFirstValidRoute(item.children)
|
||||
appLink.value[item.meta.app] = findFirstValidRoute(item.children)
|
||||
menus.push(item)
|
||||
} else {
|
||||
appLink.value[item.meta.app] = item.name
|
||||
menus.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
if(applyList.value && applyList.value.length){
|
||||
applyList.value.forEach((item,index) =>{
|
||||
menus.forEach((menuItem,menuIndex)=>{
|
||||
if(item.key == menuItem.meta.key){
|
||||
menuItem.meta.parentTitle = item.title;
|
||||
menuItem.meta.parentIcon = item.icon;
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 用于插件的卸载或安装
|
||||
if(!applyList.value.length && !globalAppKey.value){
|
||||
storage.set({ key: 'menuAppStorage', data: '' })
|
||||
globalAppKey.value = ""
|
||||
}
|
||||
if(applyList.value.length && !globalAppKey.value){
|
||||
storage.set({ key: 'menuAppStorage', data: applyTypeList.value[0] })
|
||||
globalAppKey.value = applyTypeList.value[0]
|
||||
}
|
||||
menus.forEach((item,index)=>{
|
||||
if(globalAppKey.value && item.meta.app == globalAppKey.value){
|
||||
item.children.forEach((childItem,childIndex) => {
|
||||
menus.push(childItem);
|
||||
|
||||
if(childItem.children){
|
||||
let parentKey = childItem.meta.key;
|
||||
childItem.children.forEach((grandItem,grandIndex) => {
|
||||
grandItem.parentKey = parentKey;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
return menus
|
||||
})
|
||||
|
||||
const dark = computed(() => {
|
||||
return systemStore.dark
|
||||
})
|
||||
|
||||
// 用于插件的卸载或安装
|
||||
watch(() =>userStore.globalAppKey, (val,old) => {
|
||||
getApplelist();
|
||||
},{deep: true})
|
||||
|
||||
|
||||
// 监听路由
|
||||
let currMetaAppType = ''
|
||||
const plugMenuType = ref('') // 插件类型
|
||||
const currentRoute = ref('') // 当前路由
|
||||
watch(route, () => {
|
||||
plugMenuType.value = storage.get('plugMenuTypeStorage')
|
||||
|
||||
const data = route.matched[1]
|
||||
currentRoute.value = route.matched[1]
|
||||
|
||||
if(route.meta.app && route.meta.app == globalAppKey.value){
|
||||
menus.value.forEach((item,index)=>{
|
||||
if(item.children && item.name != route.name){
|
||||
item.children.forEach((childItem,childIndex) => {
|
||||
if(childItem.name == route.name) localMenuKey.value = childItem.parentKey;
|
||||
});
|
||||
}else if(item.name == route.name){
|
||||
localMenuKey.value = item.name;
|
||||
}
|
||||
})
|
||||
}else{
|
||||
localMenuKey.value = data.meta.key
|
||||
}
|
||||
|
||||
if(otherTypeList.value.includes(localMenuKey.value) && plugMenuType.value){
|
||||
localMenuKey.value = "app_center"
|
||||
}
|
||||
|
||||
systemStore.$patch(state => {
|
||||
state.menuDrawer = false
|
||||
})
|
||||
}, { immediate: true })
|
||||
|
||||
let threefloatMenu = ref(true);
|
||||
const threefloatMenuHover = ()=>{
|
||||
threefloatMenu.value = true;
|
||||
}
|
||||
const toLink = (data, type) => {
|
||||
if(type == 'threefloatMenu') threefloatMenu.value = false;
|
||||
if (!data.meta && data.type == 'app' || data.meta.key != 'official_market') {
|
||||
let name = data.name;
|
||||
if(data.type == 'app'){
|
||||
globalAppKey.value = data.key
|
||||
localMenuKey.value = data.key
|
||||
|
||||
storage.set({ key: 'menuAppStorage', data: data.key })
|
||||
storage.set({ key: 'plugMenuTypeStorage', data: '' })
|
||||
|
||||
const appMenuList = userStore.appMenuList
|
||||
appMenuList.push(data.key)
|
||||
userStore.setAppMenuList(appMenuList)
|
||||
|
||||
name = appLink.value[data.key];
|
||||
}else if(data.meta.app){
|
||||
name = getLinkName(data);
|
||||
}
|
||||
router.push({ name: name })
|
||||
} else {
|
||||
window.open('https://www.niucloud.com/product/', '_blank')
|
||||
}
|
||||
}
|
||||
|
||||
const getLinkName = (res)=>{
|
||||
if(res.children && res.children.length){
|
||||
return getLinkName(res.children[0])
|
||||
}
|
||||
return res.name
|
||||
}
|
||||
|
||||
// 主题风格
|
||||
const sidebar = computed(() => {
|
||||
return systemStore.sidebar
|
||||
})
|
||||
|
||||
// 控制二级菜单的显示
|
||||
const isTwoMenuFn = (item) => {
|
||||
let bool = (otherTypeList.value.includes(localMenuKey.value) && globalAppKey.value == item.meta.app)
|
||||
|| (!otherTypeList.value.includes(localMenuKey.value) && (item.meta.key == localMenuKey.value || item.meta.app == localMenuKey.value) && !item.meta.app)
|
||||
|| (item.meta.app && !otherTypeList.value.includes(localMenuKey.value) && item.meta.key == localMenuKey.value && localMenuKey.value.indexOf('index') == -1)
|
||||
|
||||
return bool;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.layout-aside {
|
||||
&.bright {
|
||||
background-color: #F5F7F9;
|
||||
|
||||
li {
|
||||
background-color: #F5F7F9;
|
||||
|
||||
&.is-active:not(.is-opened) {
|
||||
position: relative;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 2px;
|
||||
background-color: var(--el-menu-active-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.second-menu .el-sub-menu .el-sub-menu__title {
|
||||
padding-left: 25px !important;
|
||||
padding-right: 25px !important;
|
||||
|
||||
.el-icon.el-sub-menu__icon-arrow {
|
||||
right: 25px;
|
||||
font-weight: bolder;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.three-menu.el-sub-menu .el-sub-menu__title {
|
||||
padding-left: 45px !important;
|
||||
}
|
||||
|
||||
.text-color {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.aside-drawer {
|
||||
.el-drawer__body {
|
||||
padding: 0px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.cut-style {
|
||||
color: #6d7278;
|
||||
|
||||
}
|
||||
|
||||
.cut-style.qx {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
// 主题二
|
||||
.two-type {
|
||||
.logo-wrap {
|
||||
.logo span {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
background-color: #F5F7F9;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #273de3;
|
||||
font-size: 25px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.layout-aside {
|
||||
background-color: #2b303b;
|
||||
.menu-item {
|
||||
color: #fff;
|
||||
|
||||
&.menu-item-active,
|
||||
&:hover {
|
||||
background-color: var(--el-color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.second-menu {
|
||||
background-color: #F5F7F9;
|
||||
|
||||
.el-menu {
|
||||
background-color: transparent;
|
||||
|
||||
.el-menu-item:hover {
|
||||
background-color: #fff;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.el-menu-item.is-active {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.el-sub-menu__title:hover {
|
||||
background-color: #fff;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.cut-style {
|
||||
color: #FFF;
|
||||
}
|
||||
}
|
||||
|
||||
// 主题三
|
||||
.three-type {
|
||||
.logo-wrap {
|
||||
.logo span {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
background-color: #F5F7F9;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #2E7BFD;
|
||||
font-size: 25px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.layout-aside {
|
||||
background-color: #2b303b;
|
||||
|
||||
.menu-item {
|
||||
color: #fff;
|
||||
|
||||
&.menu-item-active,
|
||||
&:hover {
|
||||
background-color: #303848;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.second-menu {
|
||||
background-color: #303848;
|
||||
|
||||
.second-head {
|
||||
color: #fff;
|
||||
border-color: #364059;
|
||||
}
|
||||
|
||||
.el-menu {
|
||||
background-color: transparent;
|
||||
|
||||
.el-menu-item {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.el-menu-item:hover,
|
||||
.el-menu-item.is-active {
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.el-sub-menu__title:hover {
|
||||
background-color: var(--el-color-primary);
|
||||
;
|
||||
}
|
||||
|
||||
.el-sub-menu__title {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.cut-style {
|
||||
color: #FFF;
|
||||
}
|
||||
}
|
||||
|
||||
.menus-wrap {
|
||||
height: calc(100vh - 64px);
|
||||
}
|
||||
</style>
|
||||
@ -3,10 +3,6 @@
|
||||
<el-row class="w-100 h-full w-full">
|
||||
<el-col :span="12">
|
||||
<div class="left-panel h-full flex items-center">
|
||||
<!-- 刷新当前页 -->
|
||||
<div v-if="floatMenuStyle" class="navbar-item flex items-center h-full cursor-pointer" @click="cutMenuStyleFn(false)">
|
||||
<a href="javascript:;" title="切换" class="iconfont iconqiehuan2"></a>
|
||||
</div>
|
||||
<!-- 刷新当前页 -->
|
||||
<div class="navbar-item flex items-center h-full cursor-pointer" @click="refreshRouter">
|
||||
<icon name="element-Refresh" />
|
||||
@ -176,15 +172,6 @@ const submitIndex = () => {
|
||||
router.go(0)
|
||||
})
|
||||
}
|
||||
|
||||
// 切换风格
|
||||
let floatMenuStyle = ref(false);
|
||||
floatMenuStyle.value = storage.get('floatMenuStyle') || false;
|
||||
const cutMenuStyleFn = (bool)=>{
|
||||
floatMenuStyle.value = bool;
|
||||
storage.set({ key: 'floatMenuStyle', data: bool });
|
||||
location.reload();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@ -5,6 +5,16 @@
|
||||
</div>
|
||||
<el-drawer v-model="drawer" :title="t('layout.layoutSetting')" size="300px">
|
||||
<el-scrollbar>
|
||||
<div class="setting-item flex items-baseline justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary whitespace-nowrap">{{ t('layout.sidebarStyle') }}</div>
|
||||
<div class="">
|
||||
<el-radio-group v-model="sidebarStyle" class="ml-4">
|
||||
<el-radio label="oneType" size="large">样式一</el-radio>
|
||||
<el-radio label="twoType" size="large">样式二</el-radio>
|
||||
<el-radio label="threeType" size="large">样式三</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 风格切换 -->
|
||||
<div class="setting-item flex items-baseline justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary whitespace-nowrap">{{ t('layout.sidebarMode') }}</div>
|
||||
@ -75,6 +85,16 @@ const sidebar = computed({
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const sidebarStyle = computed({
|
||||
get() {
|
||||
return systemStore.sidebarStyle
|
||||
},
|
||||
set(val) {
|
||||
systemStore.setTheme('sidebarStyle', val)
|
||||
}
|
||||
})
|
||||
|
||||
const theme = computed({
|
||||
get() {
|
||||
return systemStore.theme
|
||||
@ -3,14 +3,24 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, markRaw, defineAsyncComponent } from 'vue'
|
||||
|
||||
import { ref,computed, watch, markRaw, defineAsyncComponent } from 'vue'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
const systemStore = useSystemStore()
|
||||
const modules = import.meta.glob('./*/index.vue')
|
||||
const siteLayout = 'default'
|
||||
const layout = ref<any>(null)
|
||||
|
||||
// 主题样式
|
||||
let themeStyle = {
|
||||
'oneType': 'standard',
|
||||
'twoType': 'profession',
|
||||
'threeType': 'business'
|
||||
}
|
||||
|
||||
watch(() =>systemStore.sidebarStyle, () => {location.reload();})
|
||||
|
||||
const adminLayout = themeStyle[systemStore.sidebarStyle]
|
||||
const layout = ref<any>(null)
|
||||
Object.keys(modules).forEach(key => {
|
||||
key.indexOf(siteLayout) !== -1 && (layout.value = markRaw(defineAsyncComponent(modules[key])))
|
||||
key.indexOf(adminLayout) !== -1 && (layout.value = markRaw(defineAsyncComponent(modules[key])))
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div :class="[{'group-hover:flex': props.isShowHover},'hidden fixed left-0 top-[65px] z-[5555] bg-[#fff] w-[640px] px-[28px] py-[20px] flex-wrap box-border shadow-lg ']">
|
||||
<div v-for="(item, index) in data" :key="index" @click="toLink(item, props.hoverType)" class="flex items-center cursor-pointer text-[#6d7278] hover:bg-[#f1f2f6] whitespace-nowrap py-[10px] px-[15px] box-border w-[165px]">
|
||||
<img :src="img(item.icon)" class="w-[44px] h-[44px] rounded-full mr-[5px]" alt="" :title="item.title">
|
||||
<span>{{ item.title }}</span>
|
||||
</div>
|
||||
<div v-if="!data.length" class="flex-1 flex flex-col justify-center items-center pb-[30px]">
|
||||
<div class="w-[130px]"><img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt=""></div>
|
||||
<div class="text-[14px] text-[#909399]">暂无安装任何应用或插件,马上去<a href="https://www.niucloud.com/product/" target="_blank" class="text-[var(--el-color-primary)]">官方应用市场</a>逛逛</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { img } from '@/utils/common'
|
||||
const props = defineProps(['isShowHover','data','hoverType'])
|
||||
console.log();
|
||||
let data = ref([]);
|
||||
if(props.data){
|
||||
props.data.forEach((item,index) => {
|
||||
if(item.type == "app"){
|
||||
data.value.push(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
const emit = defineEmits(['child-click'])
|
||||
const toLink = (data,type)=>{
|
||||
emit('child-click',data,type)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
@ -1,86 +1,24 @@
|
||||
<template>
|
||||
<div :class="['flex', { 'two-type': sidebar == 'twoType' }, { 'three-type': sidebar == 'threeType' }]" v-if="isLoad">
|
||||
|
||||
<div class="w-[65px] overflow-hidden" v-if="!floatMenuStyle">
|
||||
<el-aside
|
||||
:class="['h-screen layout-aside w-[65px] pb-[30px] bg-[#F7F8FA] ease-in duration-200', { 'bright': !dark }]">
|
||||
<!-- 一级菜单 -->
|
||||
<div class="h-full flex flex-col relative">
|
||||
<div class=" flex items-center justify-center h-[64px] cursor-pointer cut-style"
|
||||
@click="floatActive = !floatActive">
|
||||
<span class="iconfont icontuodong !text-[30px] "></span>
|
||||
</div>
|
||||
<div @click="homeClick"
|
||||
class="flex items-center justify-center h-[56px] cursor-pointer text-[#6d7278] hover:bg-[#f1f2f6] menu-item hover:text-color whitespace-nowrap">
|
||||
<span class="iconfont iconshouye !text-[24px] "></span>
|
||||
</div>
|
||||
<div class="mb-[20px]">
|
||||
<template v-for="(item, index) in menus" :key="index">
|
||||
<div v-if="item.meta.app == '' && item.meta.attr == 'common'" @click="toLink(item)"
|
||||
:class="['flex items-center justify-center h-[56px] cursor-pointer text-[#6d7278] hover:bg-[#f1f2f6] menu-item hover:text-color whitespace-nowrap', { 'bg-[#f1f2f6] text-color menu-item-active ': (item.path == currentRoute.path || (currentRoute.path == '/admin' && item.path == '/index') || (currentRoute.meta.app && item.path == '/index')) }]">
|
||||
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto" size="24px"
|
||||
:title="item.meta.title" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<a href="javascript:;"
|
||||
class="absolute -bottom-[20px] left-[50%] cut-style iconfont icongengduo !text-[30px] qx"
|
||||
@click="cutMenuStyleFn" title="切换"></a>
|
||||
</div>
|
||||
</el-aside>
|
||||
</div>
|
||||
<!-- 浮动样式的应用菜单 -->
|
||||
<div class="one-menus-float-style">
|
||||
<el-dialog v-model="floatActive" :show-close="false">
|
||||
<div v-if="!floatMenuStyle && applyList.filter(el => { return el.type === 'app' }).length"
|
||||
class="flex bg-[#fff] w-[640px] px-[28px] py-[20px] flex-wrap box-border shadow-lg one-menus-wrap">
|
||||
<template v-for="(item, index) in applyList" :key="index">
|
||||
<div v-if="item.type == 'app'" @click="toLink(item)" class="flex items-center cursor-pointer text-[#6d7278] hover:bg-[#f1f2f6] whitespace-nowrap py-[10px] px-[15px] box-border w-[165px]">
|
||||
<img :src="img(item.icon)" class="w-[44px] h-[44px] rounded-full mr-[5px]" alt="" :title="item.title">
|
||||
<span>{{ item.title }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="!applyList.length" class="flex-1 text-center">暂无安装应用</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<!-- 二级菜单 -->
|
||||
<template v-for="(item, index) in menus" :key="index">
|
||||
<div v-if="isTwoMenuFn(item)" :class="[(floatMenuStyle ? 'w-[210px]' : 'w-[189px]'),'box-border border-r-[1px] border-solid second-menu']">
|
||||
<div
|
||||
class="group flex flex-col items-center justify-center h-[64px] border-b-[1px] border-solid second-head cursor-pointer relative">
|
||||
<div v-if="isTwoMenuFn(item)" class="w-[210px] box-border border-r-[1px] border-solid second-menu">
|
||||
<div class="group flex flex-col items-center justify-center h-[64px] border-b-[1px] border-solid second-head cursor-pointer relative" @mouseenter="twofloatMenuHover">
|
||||
<div class="flex items-center">
|
||||
<template v-if="floatMenuStyle">
|
||||
<img v-if="item.meta.parentIcon" :src="img(item.meta.parentIcon)" class="w-[40px] h-[40px] mr-[8px]" alt="">
|
||||
<div class="flex items-center justify-center w-[30px] h-[30px]" v-else>
|
||||
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto" size="24px" />
|
||||
</div>
|
||||
</template>
|
||||
<img v-if="item.meta.parentIcon" :src="img(item.meta.parentIcon)" class="w-[40px] h-[40px] mr-[8px]" alt="">
|
||||
<div class="flex items-center justify-center w-[30px] h-[30px]" v-else>
|
||||
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto" size="24px" />
|
||||
</div>
|
||||
<span>{{ item.meta.app ? item.meta.parentTitle : item.meta.title }}</span>
|
||||
</div>
|
||||
<!-- 浮动样式的应用菜单 -->
|
||||
<div v-if="floatMenuStyle && applyList.filter(el => { return el.type === 'app' }).length"
|
||||
class="hidden group-hover:flex absolute bg-[#fff] w-[640px] px-[28px] py-[20px] flex-wrap left-0 top-[65px] z-[5555] box-border shadow-lg">
|
||||
<template v-for="(item, index) in applyList" :key="index">
|
||||
<div v-if="item.type == 'app'" @click="toLink(item)"
|
||||
class="flex items-center cursor-pointer text-[#6d7278] hover:bg-[#f1f2f6] whitespace-nowrap py-[10px] px-[15px] w-[165px] box-border">
|
||||
<img :src="img(item.icon)" class="w-[44px] h-[44px] rounded-full mr-[5px]" alt=""
|
||||
:title="item.title">
|
||||
<span>{{ item.title }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="!applyList.length" class="flex-1 text-center">暂无安装应用</div>
|
||||
</div>
|
||||
<app-menu :isShowHover="twofloatMenu" :data="applyList" @child-click="toLink" hoverType='twofloatMenu'></app-menu>
|
||||
</div>
|
||||
|
||||
<el-scrollbar class="overflow-y-auto menus-wrap">
|
||||
<el-menu class="apply-menu !border-0" :router="true" unique-opened="true"
|
||||
:default-active="String(route.name)">
|
||||
<template v-if="!floatMenuStyle || floatMenuStyle && applyTypeList.length">
|
||||
<el-menu class="apply-menu !border-0" :router="true" unique-opened="true" :default-active="String(route.name)">
|
||||
<template v-if="applyTypeList.length">
|
||||
<template v-for="(twoMenu, twoIndex) in item.children">
|
||||
<el-sub-menu :index="String(twoMenu.meta.title)"
|
||||
v-if="twoMenu.children && twoMenu.meta.show">
|
||||
<el-sub-menu :index="String(twoMenu.meta.title)" v-if="twoMenu.children && twoMenu.meta.show">
|
||||
<template #title>
|
||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
||||
@ -94,10 +32,8 @@
|
||||
v-if="threeMenu.children && threeMenu.meta.show">
|
||||
<template #title>
|
||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="threeMenu.meta.icon && floatMenuStyle"
|
||||
<icon v-if="threeMenu.meta.icon"
|
||||
:name="threeMenu.meta.icon" class="absolute !w-auto" size="18px" />
|
||||
<span v-if="!floatMenuStyle"
|
||||
class="iconfont icondian !text-[25px]"></span>
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
@ -164,7 +100,7 @@
|
||||
|
||||
<!-- 系统菜单 -->
|
||||
<template
|
||||
v-if="applyTypeList.includes(localMenuKey) || otherTypeList.includes(localMenuKey) || floatMenuStyle">
|
||||
v-if="applyTypeList.includes(localMenuKey) || otherTypeList.includes(localMenuKey)">
|
||||
<div class="!border-0 !border-t-[1px] border-solid mx-[25px] bg-[#f7f7f7] my-[5px]"></div>
|
||||
<template v-for="(twoMenu, twoIndex) in menus">
|
||||
<el-sub-menu :index="String(twoMenu.meta.title)"
|
||||
@ -180,9 +116,8 @@
|
||||
<el-sub-menu :index="String(threeMenu.meta.title)"
|
||||
v-if="threeMenu.meta.app && threeMenu.children">
|
||||
<template #title>
|
||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="threeMenu.meta.icon" :name="threeMenu.meta.icon"
|
||||
class="absolute !w-auto" size="18px" />
|
||||
<div class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||
<span class="iconfont iconyuanquan_huaban1 !text-[20px]"></span>
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
@ -229,29 +164,25 @@
|
||||
</template>
|
||||
|
||||
<!-- 插件菜单 -->
|
||||
<template v-if="otherTypeList.includes(localMenuKey) && plugMenuType">
|
||||
<template v-if="otherTypeList.includes(localMenuKey) && twoMenu.meta.key == 'app_center' && plugMenuType">
|
||||
<template v-for="(twoMenu, twoIndex) in menus">
|
||||
<el-sub-menu :index="String(twoMenu.meta.title)"
|
||||
v-if="twoMenu.meta.app && twoMenu.meta.app == plugMenuType && twoMenu.children">
|
||||
<template #title>
|
||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
||||
class="absolute !w-auto" size="18px" />
|
||||
<div class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||
<span class="iconfont iconyuanquan_huaban1 !text-[20px]"></span>
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(threeMenu, threeIndex) in twoMenu.children"
|
||||
:key="threeIndex">
|
||||
<template v-for="(threeMenu, threeIndex) in twoMenu.children" :key="threeIndex">
|
||||
<!-- 三级菜单 -->
|
||||
<el-sub-menu :index="String(threeMenu.meta.title)"
|
||||
v-if="threeMenu.children && threeMenu.meta.show">
|
||||
<template #title>
|
||||
<div
|
||||
class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||
<div class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||
<span class="iconfont icondian !text-[25px]"></span>
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title
|
||||
}}</span>
|
||||
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(fourMenu, fourIndex) in threeMenu.children"
|
||||
:key="fourIndex">
|
||||
@ -307,85 +238,82 @@
|
||||
</template>
|
||||
</template>
|
||||
<!-- 浮动样式 -->
|
||||
<template v-if="floatMenuStyle">
|
||||
<div
|
||||
:class="['!border-0 border-solid mx-[25px] bg-[#f7f7f7] my-[5px]', floatMenuStyle && !applyTypeList.length ? '' : '!border-t-[1px]']">
|
||||
</div>
|
||||
<template v-for="(twoMenu, twoIndex) in menus">
|
||||
<el-sub-menu :index="String(twoMenu.meta.title)"
|
||||
v-if="twoMenu.meta.attr == 'common' && !twoMenu.meta.app && twoMenu.children">
|
||||
<template #title>
|
||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
||||
class="absolute !w-auto" size="18px" />
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(threeMenu, threeIndex) in twoMenu.children" :key="threeIndex">
|
||||
<el-sub-menu :index="String(threeMenu.meta.title)"
|
||||
v-if="threeMenu.children && threeMenu.meta.show">
|
||||
<template #title>
|
||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="threeMenu.meta.icon" :name="threeMenu.meta.icon"
|
||||
class="absolute !w-auto" size="18px" />
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(fourMenu, fourIndex) in threeMenu.children" :key="fourIndex">
|
||||
<el-sub-menu :index="String(fourMenu.meta.title)"
|
||||
v-if="fourMenu.children && fourMenu.meta.show">
|
||||
<template #title>
|
||||
<div
|
||||
class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||
<span class="iconfont icondian !text-[25px]"></span>
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ fourMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(fiveMenu, fiveIndex) in threeMenu.children"
|
||||
:key="fiveIndex">
|
||||
<el-menu-item v-if="fiveMenu.meta.show" class="!h-[52px] !pl-[55px]"
|
||||
:index="String(fiveMenu.name)" @click="toLink(fiveMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ fiveMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-else-if="fourMenu.meta.show" class="!h-[52px] !pl-[55px]"
|
||||
:index="String(fourMenu.name)" @click="toLink(fourMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ fourMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
<div
|
||||
:class="['!border-0 border-solid mx-[25px] bg-[#f7f7f7] my-[5px]', !applyTypeList.length ? '' : '!border-t-[1px]']">
|
||||
</div>
|
||||
<template v-for="(twoMenu, twoIndex) in menus">
|
||||
<el-sub-menu :index="String(twoMenu.meta.title)"
|
||||
v-if="twoMenu.meta.attr == 'common' && !twoMenu.meta.app && twoMenu.children">
|
||||
<template #title>
|
||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
||||
class="absolute !w-auto" size="18px" />
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(threeMenu, threeIndex) in twoMenu.children" :key="threeIndex">
|
||||
<el-sub-menu :index="String(threeMenu.meta.title)"
|
||||
v-if="threeMenu.children && threeMenu.meta.show">
|
||||
<template #title>
|
||||
<div class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||
<span class="iconfont iconyuanquan_huaban1 !text-[20px]"></span>
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(fourMenu, fourIndex) in threeMenu.children" :key="fourIndex">
|
||||
<el-sub-menu :index="String(fourMenu.meta.title)"
|
||||
v-if="fourMenu.children && fourMenu.meta.show">
|
||||
<template #title>
|
||||
<div
|
||||
class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||
<span class="iconfont icondian !text-[25px]"></span>
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ fourMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(fiveMenu, fiveIndex) in threeMenu.children"
|
||||
:key="fiveIndex">
|
||||
<el-menu-item v-if="fiveMenu.meta.show" class="!h-[52px] !pl-[55px]"
|
||||
:index="String(fiveMenu.name)" @click="toLink(fiveMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ fiveMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-else-if="fourMenu.meta.show" class="!h-[52px] !pl-[55px]"
|
||||
:index="String(fourMenu.name)" @click="toLink(fourMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ fourMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
|
||||
<el-menu-item
|
||||
v-else-if="threeMenu.meta.show && threeMenu.meta.key != 'official_market'"
|
||||
class="!h-[52px] !pl-[52px]" :index="String(threeMenu.name)"
|
||||
@click="toLink(threeMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
<div class="flex items-center !px-[52px] h-[56px] cursor-pointer text-[#333] el-menu-item"
|
||||
v-else-if="threeMenu.meta.show && threeMenu.meta.key == 'official_market'"
|
||||
@click="toLink(threeMenu)">
|
||||
<span class="text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-else-if="twoMenu.meta.attr == 'common'" class="!pl-[35px] text-[#333]"
|
||||
:index="String(twoMenu.name)" @click="toLink(twoMenu)">
|
||||
<template #title>
|
||||
<div v-if="twoMenu.meta.icon" class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
||||
class="absolute !w-auto" size="18px" />
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
<el-menu-item
|
||||
v-else-if="threeMenu.meta.show && threeMenu.meta.key != 'official_market'"
|
||||
class="!h-[52px] !pl-[52px]" :index="String(threeMenu.name)"
|
||||
@click="toLink(threeMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
<div class="flex items-center !px-[52px] h-[56px] cursor-pointer text-[#333] el-menu-item"
|
||||
v-else-if="threeMenu.meta.show && threeMenu.meta.key == 'official_market'"
|
||||
@click="toLink(threeMenu)">
|
||||
<span class="text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-else-if="twoMenu.meta.attr == 'common'" class="!pl-[35px] text-[#333]"
|
||||
:index="String(twoMenu.name)" @click="toLink(twoMenu)">
|
||||
<template #title>
|
||||
<div v-if="twoMenu.meta.icon" class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
||||
class="absolute !w-auto" size="18px" />
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
@ -398,6 +326,7 @@
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import side from './side.vue'
|
||||
import appMenu from './components/app-menu.vue'
|
||||
import { img } from '@/utils/common'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
@ -407,6 +336,7 @@ import { findFirstValidRoute } from '@/router/routers'
|
||||
import { getAddonByKey } from '@/app/api/addon'
|
||||
import { getApply } from '@/app/api/apply'
|
||||
|
||||
|
||||
const userStore = useUserStore()
|
||||
const systemStore = useSystemStore()
|
||||
const route = useRoute()
|
||||
@ -432,12 +362,6 @@ const getApplelist = async () => {
|
||||
isLoad.value = true;
|
||||
}
|
||||
getApplelist()
|
||||
|
||||
const floatActive = ref(false)
|
||||
const homeClick = () => {
|
||||
const key = storage.get('menuAppStorage')
|
||||
key ? router.push({ name: appLink.value[key] }) : router.push({ path: '/' })
|
||||
}
|
||||
// 应用跳转 end
|
||||
|
||||
// 菜单
|
||||
@ -454,7 +378,7 @@ const menus = computed(() => {
|
||||
menus.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
if(applyList.value && applyList.value.length){
|
||||
applyList.value.forEach((item,index) =>{
|
||||
menus.forEach((menuItem,menuIndex)=>{
|
||||
@ -465,6 +389,17 @@ const menus = computed(() => {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 用于插件的卸载或安装
|
||||
if(!applyList.value.length){
|
||||
storage.set({ key: 'menuAppStorage', data: '' })
|
||||
globalAppKey.value = ""
|
||||
}
|
||||
|
||||
if(applyList.value.length && !globalAppKey.value){
|
||||
storage.set({ key: 'menuAppStorage', data: applyTypeList.value[0] })
|
||||
globalAppKey.value = applyTypeList.value[0]
|
||||
}
|
||||
return menus
|
||||
})
|
||||
|
||||
@ -472,6 +407,12 @@ const dark = computed(() => {
|
||||
return systemStore.dark
|
||||
})
|
||||
|
||||
// 用于插件的卸载或安装
|
||||
watch(() =>userStore.globalAppKey, (val,old) => {
|
||||
getApplelist();
|
||||
},{deep: true})
|
||||
|
||||
|
||||
// 监听路由
|
||||
let currMetaAppType = ''
|
||||
const plugMenuType = ref('') // 插件类型
|
||||
@ -481,14 +422,22 @@ watch(route, () => {
|
||||
|
||||
const data = route.matched[1]
|
||||
currentRoute.value = route.matched[1]
|
||||
localMenuKey.value = data.meta.key
|
||||
localMenuKey.value = data.meta.key || 'overview'
|
||||
|
||||
systemStore.$patch(state => {
|
||||
state.menuDrawer = false
|
||||
})
|
||||
}, { immediate: true })
|
||||
|
||||
const toLink = (data) => {
|
||||
|
||||
|
||||
let twofloatMenu = ref(true);
|
||||
const twofloatMenuHover = ()=>{
|
||||
twofloatMenu.value = true;
|
||||
}
|
||||
const toLink = (data, type) => {
|
||||
if(type == 'twofloatMenu') twofloatMenu.value = false;
|
||||
|
||||
if (!data.meta && data.type == 'app' || data.meta.key != 'official_market') {
|
||||
let name = data.name;
|
||||
if(data.type == 'app'){
|
||||
@ -501,7 +450,6 @@ const toLink = (data) => {
|
||||
const appMenuList = userStore.appMenuList
|
||||
appMenuList.push(data.key)
|
||||
userStore.setAppMenuList(appMenuList)
|
||||
floatActive.value = false
|
||||
|
||||
name = appLink.value[data.key];
|
||||
}
|
||||
@ -516,31 +464,18 @@ const sidebar = computed(() => {
|
||||
return systemStore.sidebar
|
||||
})
|
||||
|
||||
// 切换风格
|
||||
const floatMenuStyle = ref(false)
|
||||
floatMenuStyle.value = storage.get('floatMenuStyle') || false
|
||||
const cutMenuStyleFn = () => {
|
||||
floatMenuStyle.value = true
|
||||
storage.set({ key: 'floatMenuStyle', data: true })
|
||||
location.reload()
|
||||
}
|
||||
|
||||
// 控制二级菜单的显示
|
||||
const isTwoMenuFn = (item) => {
|
||||
let bool = (otherTypeList.value.includes(localMenuKey.value) && globalAppKey.value == item.meta.app)
|
||||
|| (floatMenuStyle.value && !applyTypeList.value.includes(localMenuKey.value) && !otherTypeList.value.includes(localMenuKey.value) && globalAppKey.value == item.meta.app)
|
||||
|| (floatMenuStyle.value && applyTypeList.value.includes(localMenuKey.value) && (item.meta.key == localMenuKey.value || item.meta.app == localMenuKey.value))
|
||||
|| (floatMenuStyle.value && !applyTypeList.value.length && (item.meta.key == localMenuKey.value || item.meta.app == localMenuKey.value))
|
||||
|| (!floatMenuStyle.value && !otherTypeList.value.includes(localMenuKey.value) && (item.meta.key == localMenuKey.value || item.meta.app == localMenuKey.value))
|
||||
|
||||
|| (!applyTypeList.value.includes(localMenuKey.value) && !otherTypeList.value.includes(localMenuKey.value) && globalAppKey.value && globalAppKey.value == item.meta.app)
|
||||
|| (applyTypeList.value.includes(localMenuKey.value) && (item.meta.key == localMenuKey.value || item.meta.app == localMenuKey.value))
|
||||
|| (!applyTypeList.value.length && (item.meta.key == localMenuKey.value || item.meta.app == localMenuKey.value))
|
||||
return bool;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.layout-aside {
|
||||
// border-right: 1px solid var(--el-border-color-lighter);
|
||||
|
||||
&.bright {
|
||||
background-color: #F5F7F9;
|
||||
|
||||
@ -732,17 +667,3 @@ const isTwoMenuFn = (item) => {
|
||||
height: calc(100vh - 64px);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.one-menus-float-style .el-overlay{
|
||||
background-color: transparent;
|
||||
}
|
||||
.one-menus-float-style .el-dialog__header, .one-menus-float-style .el-dialog__body{
|
||||
padding: 0;
|
||||
}
|
||||
.one-menus-float-style .one-menus-wrap{
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 65px;
|
||||
z-index: 5555;
|
||||
}
|
||||
</style>
|
||||
200
admin/src/layout/profession/components/header/index.vue
Normal file
200
admin/src/layout/profession/components/header/index.vue
Normal file
@ -0,0 +1,200 @@
|
||||
<template>
|
||||
<el-container :class="['h-full px-[10px]', { 'layout-header border-b border-color': !dark }]">
|
||||
<el-row class="w-100 h-full w-full">
|
||||
<el-col :span="12">
|
||||
<div class="left-panel h-full flex items-center">
|
||||
<!-- 刷新当前页 -->
|
||||
<div class="navbar-item flex items-center h-full cursor-pointer" @click="refreshRouter">
|
||||
<icon name="element-Refresh" />
|
||||
</div>
|
||||
<!-- 面包屑导航 -->
|
||||
<div class="flex items-center h-full pl-[10px] hidden-xs-only">
|
||||
<el-breadcrumb separator="/">
|
||||
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index">{{ route.meta.title }}</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="right-panel h-full flex items-center justify-end">
|
||||
<!-- 预览 只有站点时展示-->
|
||||
|
||||
<i class="iconfont iconlingdang-xianxing cursor-pointer px-[8px]" :title="t('newInfo')" v-if="appType == 'site'"></i>
|
||||
<!-- 切换首页 -->
|
||||
<div class="navbar-item flex items-center h-full cursor-pointer" v-if="appType == 'site'" @click="checkIndexList">
|
||||
<icon name="iconfont-iconqiehuan" :title="t('indexSwitch')" />
|
||||
</div>
|
||||
<!-- 切换语言 -->
|
||||
<div class="navbar-item !px-[0] flex items-center h-full cursor-pointer">
|
||||
<switch-lang />
|
||||
</div>
|
||||
<!-- 切换全屏 -->
|
||||
<div class="navbar-item flex items-center h-full cursor-pointer" @click="toggleFullscreen">
|
||||
<icon name="iconfont-icontuichuquanping" v-if="isFullscreen" />
|
||||
<icon name="iconfont-iconquanping" v-else />
|
||||
</div>
|
||||
<!-- 布局设置 -->
|
||||
<div class="navbar-item !px-[0] flex items-center h-full cursor-pointer">
|
||||
<layout-setting />
|
||||
</div>
|
||||
<!-- 用户信息 -->
|
||||
<div class="navbar-item flex items-center h-full cursor-pointer">
|
||||
<user-info />
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<input type="hidden" v-model="comparisonToken">
|
||||
|
||||
<el-dialog v-model="detectionLoginDialog" :title="t('layout.detectionLoginTip')" width="30%" :close-on-click-modal="false" :close-on-press-escape="false" :show-close="false">
|
||||
<span>{{ t('layout.detectionLoginContent') }}</span>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="detectionLoginFn">{{ t('layout.detectionLoginOperation') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="showDialog" :title="t('indexTemplate')" width="550px" :destroy-on-close="true">
|
||||
<div class="flex flex-wrap">
|
||||
<div v-for="(items, index) in indexList" :key="index" v-if="index_path == ''">
|
||||
<div @click="index_path = items.view_path" class="index-item py-[5px] px-[10px] mr-[10px] rounded-[3px] cursor-pointer" :class="items.is_use == 1 ? 'bg-primary text-[#fff]' : ''">
|
||||
<span>{{ items.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="(itemTo, indexTo) in indexList" :key="indexTo" v-else>
|
||||
<div @click="index_path = itemTo.view_path" class="index-item py-[5px] px-[10px] mr-[10px] rounded-[3px] cursor-pointer" :class="index_path == itemTo.view_path ? 'bg-primary text-[#fff]' : ''">
|
||||
<span>{{ itemTo.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button type="primary" @click="submitIndex">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, onMounted, watch } from 'vue'
|
||||
import layoutSetting from './layout-setting.vue'
|
||||
import switchLang from './switch-lang.vue'
|
||||
import userInfo from './user-info.vue'
|
||||
import { useFullscreen } from '@vueuse/core'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
import storage from '@/utils/storage'
|
||||
import { getIndexList, setIndexList } from '@/app/api/sys'
|
||||
|
||||
const router = useRouter()
|
||||
const appType = storage.get('app_type')
|
||||
const { toggle: toggleFullscreen, isFullscreen } = useFullscreen()
|
||||
const systemStore = useSystemStore()
|
||||
const appStore = useAppStore()
|
||||
const route = useRoute()
|
||||
const screenWidth = ref(window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth)
|
||||
|
||||
const dark = computed(() => {
|
||||
return systemStore.dark
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 监听窗体宽度变化
|
||||
window.onresize = () => {
|
||||
return (() => {
|
||||
screenWidth.value = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
|
||||
})()
|
||||
}
|
||||
})
|
||||
|
||||
watch(screenWidth, () => {
|
||||
if (screenWidth.value < 992) {
|
||||
if (!systemStore.menuIsCollapse) systemStore.toggleMenuCollapse(true)
|
||||
} else {
|
||||
if (systemStore.menuIsCollapse) systemStore.toggleMenuCollapse(false)
|
||||
}
|
||||
})
|
||||
|
||||
// 菜单栏展开折叠
|
||||
const toggleMenuCollapse = () => {
|
||||
systemStore.$patch((state) => {
|
||||
if (screenWidth.value < 768) {
|
||||
state.menuDrawer = true
|
||||
state.menuIsCollapse = false
|
||||
} else {
|
||||
systemStore.toggleMenuCollapse(!systemStore.menuIsCollapse)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 刷新路由
|
||||
const refreshRouter = () => {
|
||||
if (!appStore.routeRefreshTag) return
|
||||
appStore.refreshRouterView()
|
||||
}
|
||||
|
||||
// 面包屑导航
|
||||
const breadcrumb = computed(() => {
|
||||
const matched = route.matched.filter(item => { return item.meta.title })
|
||||
if (matched[0] && matched[0].path == '/') matched.splice(0, 1)
|
||||
return matched
|
||||
})
|
||||
|
||||
// 返回上一页
|
||||
const backFn = () => {
|
||||
router.go(-1)
|
||||
}
|
||||
|
||||
const indexList = ref()
|
||||
const showDialog = ref(false)
|
||||
const checkIndexList = () => {
|
||||
getIndexList().then(res => {
|
||||
showDialog.value = true
|
||||
indexList.value = res.data
|
||||
for (let i = 0; i < indexList.value.length; i++) {
|
||||
if (indexList.value[i].is_use == 1) {
|
||||
index_path.value = indexList.value[i].view_path
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const index_path = ref('')
|
||||
const submitIndex = () => {
|
||||
setIndexList({
|
||||
view_path: index_path.value
|
||||
}).then(() => {
|
||||
showDialog.value = false
|
||||
router.go(0)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.layout-header {
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
box-shadow: 0px 0px 4px 0px rgba(0, 145, 255, 0.1);
|
||||
}
|
||||
|
||||
.navbar-item {
|
||||
padding: 0 8px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--el-bg-color-page);
|
||||
}
|
||||
}
|
||||
|
||||
.index-item {
|
||||
border: 1px solid;
|
||||
border-color: var(--el-color-primary);
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
}</style>
|
||||
119
admin/src/layout/profession/components/header/layout-setting.vue
Normal file
119
admin/src/layout/profession/components/header/layout-setting.vue
Normal file
@ -0,0 +1,119 @@
|
||||
<template>
|
||||
<div class="flex w-[100%] h-[100%]" @click="drawer = true">
|
||||
<div class="h-[100%] w-[100%] flex items-center justify-center px-[8px]">
|
||||
<icon name="element-Setting" />
|
||||
</div>
|
||||
<el-drawer v-model="drawer" :title="t('layout.layoutSetting')" size="300px">
|
||||
<el-scrollbar>
|
||||
<div class="setting-item flex items-baseline justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary whitespace-nowrap">{{ t('layout.sidebarStyle') }}</div>
|
||||
<div class="">
|
||||
<el-radio-group v-model="sidebarStyle" class="ml-4">
|
||||
<el-radio label="oneType" size="large">样式一</el-radio>
|
||||
<el-radio label="twoType" size="large">样式二</el-radio>
|
||||
<el-radio label="threeType" size="large">样式三</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 风格切换 -->
|
||||
<div class="setting-item flex items-baseline justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary whitespace-nowrap">{{ t('layout.sidebarMode') }}</div>
|
||||
<div class="">
|
||||
<el-radio-group v-model="sidebar" class="ml-4">
|
||||
<el-radio label="oneType" size="large">
|
||||
<img class="w-[35px] h-[35px]" src="@/app/assets/images/one_type.png" alt="">
|
||||
</el-radio>
|
||||
<el-radio label="twoType" size="large">
|
||||
<img class="w-[35px] h-[35px]" src="@/app/assets/images/two_type.png" alt="">
|
||||
</el-radio>
|
||||
<el-radio label="threeType" size="large">
|
||||
<img class="w-[35px] h-[35px]" src="@/app/assets/images/three_type.png" alt="">
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 黑暗模式 -->
|
||||
<div class="setting-item flex items-center justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary">{{ t('layout.darkMode') }}</div>
|
||||
<div class="">
|
||||
<el-switch v-model="dark" :active-value="true" :inactive-value="false" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 主题颜色 -->
|
||||
<div class="setting-item flex items-center justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary">{{ t('layout.themeColor') }}</div>
|
||||
<div class="">
|
||||
<el-color-picker v-model="theme" />
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import { useDark, useToggle } from '@vueuse/core'
|
||||
import { setThemeColor } from '@/utils/common'
|
||||
import { t } from '@/lang'
|
||||
|
||||
const drawer = ref(false)
|
||||
const systemStore = useSystemStore()
|
||||
|
||||
const isDark = useDark()
|
||||
const toggleDark = useToggle(isDark)
|
||||
|
||||
const dark = computed({
|
||||
get() {
|
||||
return systemStore.dark
|
||||
},
|
||||
set(val) {
|
||||
systemStore.setTheme('dark', val)
|
||||
toggleDark(val)
|
||||
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||
}
|
||||
})
|
||||
|
||||
const sidebar = computed({
|
||||
get() {
|
||||
return systemStore.sidebar
|
||||
},
|
||||
set(val) {
|
||||
systemStore.setTheme('sidebar', val)
|
||||
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const sidebarStyle = computed({
|
||||
get() {
|
||||
return systemStore.sidebarStyle
|
||||
},
|
||||
set(val) {
|
||||
systemStore.setTheme('sidebarStyle', val)
|
||||
}
|
||||
})
|
||||
|
||||
const theme = computed({
|
||||
get() {
|
||||
return systemStore.theme
|
||||
},
|
||||
set(val) {
|
||||
systemStore.setTheme('theme', val)
|
||||
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-drawer__header) {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.layout-style {
|
||||
&>div:nth-child(2n+2) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<el-dropdown @command="switchLang" :tabindex="1" class="h-[100%] w-[100%]">
|
||||
<div class="h-[100%] w-[100%] flex items-center justify-center px-[8px]">
|
||||
<icon name="iconfont-iconfanyi" />
|
||||
</div>
|
||||
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="zh-cn" :disabled="systemStore.lang == 'zh-cn'">简体中文</el-dropdown-item>
|
||||
<el-dropdown-item command="en" :disabled="systemStore.lang == 'en'">English</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import { language } from '@/lang'
|
||||
import { useRoute } from 'vue-router'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
const route = useRoute()
|
||||
const systemStore = useSystemStore()
|
||||
|
||||
const switchLang = (command: string) => {
|
||||
systemStore.$patch((state) => {
|
||||
state.lang = command
|
||||
storage.set({ key: 'lang', data: command })
|
||||
})
|
||||
language.loadLocaleMessages(route.meta.app || '', route.path, systemStore.lang)
|
||||
location.reload()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
32
admin/src/layout/profession/components/header/user-info.vue
Normal file
32
admin/src/layout/profession/components/header/user-info.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<el-dropdown @command="clickEvent" :tabindex="1">
|
||||
<div class="userinfo flex h-full items-center">
|
||||
<el-avatar :size="25" :icon="UserFilled" />
|
||||
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
||||
<icon name="element-ArrowDown" class="ml-[5px]" />
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="usercenter"><router-link to="/user/center">个人中心</router-link></el-dropdown-item>
|
||||
<el-dropdown-item command="logout">退出登录</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { UserFilled } from '@element-plus/icons-vue'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const clickEvent = (command: string) => {
|
||||
switch (command) {
|
||||
case 'logout':
|
||||
userStore.logout()
|
||||
break
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
40
admin/src/layout/profession/index.vue
Normal file
40
admin/src/layout/profession/index.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div class="common-layout min-w-[1200px]" >
|
||||
<el-container class="w-100 h-screen">
|
||||
<layout-aside></layout-aside>
|
||||
|
||||
<el-container>
|
||||
<el-header>
|
||||
<layout-header></layout-header>
|
||||
</el-header>
|
||||
|
||||
<el-main :class="['main-wrap h-full p-0',{'bg-page': dark}]">
|
||||
<el-scrollbar>
|
||||
<div>
|
||||
<router-view v-slot="{ Component, route }" v-if="appStore.routeRefreshTag">
|
||||
<component :is="Component" :key="route.fullPath" />
|
||||
</router-view>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-main>
|
||||
|
||||
</el-container>
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import layoutHeader from './components/header/index.vue'
|
||||
import layoutAside from './components/aside/index.vue'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
|
||||
const appStore = useAppStore()
|
||||
const systemStore = useSystemStore()
|
||||
const dark = computed(()=>{
|
||||
return systemStore.dark
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div :class="[{'group-hover:flex': props.isShowHover},'hidden fixed left-0 top-[65px] z-[5555] bg-[#fff] w-[640px] px-[28px] py-[20px] flex-wrap box-border shadow-lg ']">
|
||||
<div v-for="(item, index) in data" :key="index" @click="toLink(item, props.hoverType)" class="flex items-center cursor-pointer text-[#6d7278] hover:bg-[#f1f2f6] whitespace-nowrap py-[10px] px-[15px] box-border w-[165px]">
|
||||
<img :src="img(item.icon)" class="w-[44px] h-[44px] rounded-full mr-[5px]" alt="" :title="item.title">
|
||||
<span>{{ item.title }}</span>
|
||||
</div>
|
||||
<div v-if="!data.length" class="flex-1 flex flex-col justify-center items-center pb-[30px]">
|
||||
<div class="w-[130px]"><img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt=""></div>
|
||||
<div class="text-[14px] text-[#909399]">暂无安装任何应用或插件,马上去<a href="https://www.niucloud.com/product/" target="_blank" class="text-[var(--el-color-primary)]">官方应用市场</a>逛逛</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { img } from '@/utils/common'
|
||||
const props = defineProps(['isShowHover','data','hoverType'])
|
||||
let data = ref([]);
|
||||
if(props.data){
|
||||
props.data.forEach((item,index) => {
|
||||
if(item.type == "app"){
|
||||
data.value.push(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
const emit = defineEmits(['child-click'])
|
||||
const toLink = (data,type)=>{
|
||||
emit('child-click',data,type)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
613
admin/src/layout/standard/components/aside/index.vue
Normal file
613
admin/src/layout/standard/components/aside/index.vue
Normal file
@ -0,0 +1,613 @@
|
||||
<template>
|
||||
<div :class="['flex', { 'two-type': sidebar == 'twoType' }, { 'three-type': sidebar == 'threeType' }]" v-if="isLoad">
|
||||
<div class="w-[65px] overflow-hidden">
|
||||
<el-aside
|
||||
:class="['h-screen layout-aside w-[65px] pb-[30px] bg-[#F7F8FA] ease-in duration-200', { 'bright': !dark }]">
|
||||
<div class="h-full flex flex-col relative">
|
||||
<div class="group flex items-center justify-center h-[64px] cursor-pointer cut-style" @mouseenter="onefloatMenuHover">
|
||||
<span class="iconfont icontuodong !text-[30px] "></span>
|
||||
<app-menu :isShowHover="onefloatMenu" :data="applyList" @child-click="toLink" hoverType='onefloatMenu'></app-menu>
|
||||
</div>
|
||||
<div @click="homeClick"
|
||||
class="flex items-center justify-center h-[56px] cursor-pointer text-[#6d7278] hover:bg-[#f1f2f6] menu-item hover:text-color whitespace-nowrap">
|
||||
<span class="iconfont iconshouye !text-[24px] "></span>
|
||||
</div>
|
||||
<div class="mb-[20px]">
|
||||
<template v-for="(item, index) in menus" :key="index">
|
||||
<div v-if="item.meta.app == '' && item.meta.attr == 'common'" @click="toLink(item)"
|
||||
:class="['flex items-center justify-center h-[56px] cursor-pointer text-[#6d7278] hover:bg-[#f1f2f6] menu-item hover:text-color whitespace-nowrap', { 'bg-[#f1f2f6] text-color menu-item-active ': (item.path == currentRoute.path || (currentRoute.path == '/admin' && item.path == '/index') || (currentRoute.meta.app && item.path == '/index')) }]">
|
||||
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto" size="24px" :title="item.meta.title" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</el-aside>
|
||||
</div>
|
||||
|
||||
<template v-for="(item, index) in menus" :key="index">
|
||||
<div v-if="isTwoMenuFn(item)" class="w-[189px] box-border border-r-[1px] border-solid second-menu">
|
||||
<div class="group flex flex-col items-center justify-center h-[64px] border-b-[1px] border-solid second-head cursor-pointer relative">
|
||||
{{ item.meta.app ? item.meta.parentTitle : item.meta.title }}
|
||||
</div>
|
||||
|
||||
<el-scrollbar class="overflow-y-auto menus-wrap">
|
||||
<el-menu class="apply-menu !border-0" :router="true" unique-opened="true" :default-active="String(route.name)">
|
||||
<template v-for="(twoMenu, twoIndex) in item.children">
|
||||
<el-sub-menu :index="String(twoMenu.meta.title)" v-if="twoMenu.children && twoMenu.meta.show">
|
||||
<template #title>
|
||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
||||
class="absolute !w-auto" size="18px" />
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(threeMenu, threeIndex) in twoMenu.children" :key="threeIndex">
|
||||
<!-- 三级菜单 -->
|
||||
<el-sub-menu :index="String(threeMenu.meta.title)" class="three-menu"
|
||||
v-if="threeMenu.children && threeMenu.meta.show">
|
||||
<template #title>
|
||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
||||
<span class="iconfont icondian !text-[25px]"></span>
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(fourMenu, fourIndex) in threeMenu.children" :key="fourIndex">
|
||||
<el-sub-menu :index="String(fourMenu.meta.title)"
|
||||
v-if="fourMenu.children && fourMenu.meta.show">
|
||||
<template #title>
|
||||
<div
|
||||
class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||
<span class="iconfont icondian !text-[25px]"></span>
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ fourMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(fiveMenu, fiveIndex) in fourMenu.children"
|
||||
:key="fiveIndex">
|
||||
<el-menu-item v-if="fiveMenu.meta.show" class="!h-[52px] !pl-[55px]"
|
||||
:index="String(fiveMenu.name)" @click="toLink(fiveMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ fiveMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-else-if="fourMenu.meta.show" class="!h-[52px] !pl-[35px]"
|
||||
:index="String(fourMenu.name)" @click="toLink(fourMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ fourMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
|
||||
<!-- 二级菜单 -->
|
||||
<el-menu-item v-else-if="threeMenu.meta.show" class="!h-[52px] !pl-[52px]"
|
||||
:index="String(threeMenu.name)" @click="toLink(threeMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
|
||||
</el-sub-menu>
|
||||
|
||||
<el-menu-item v-else-if="twoMenu.meta.show && twoMenu.meta.key != 'official_market'"
|
||||
class="!pl-[25px] text-[#333]" :index="String(twoMenu.name)" @click="toLink(twoMenu)">
|
||||
<template #title>
|
||||
<div v-if="twoMenu.meta.icon" class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
||||
class="absolute !w-auto" size="18px" />
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
<div class="flex items-center !px-[25px] h-[56px] cursor-pointer text-[#333] el-menu-item"
|
||||
v-else-if="twoMenu.meta.show && twoMenu.meta.key == 'official_market'"
|
||||
@click="toLink(twoMenu)">
|
||||
<div v-if="twoMenu.meta.icon" class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon" class="absolute !w-auto"
|
||||
size="18px" />
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 系统菜单 -->
|
||||
<template v-if="applyTypeList.includes(localMenuKey) || otherTypeList.includes(localMenuKey)">
|
||||
<div class="!border-0 !border-t-[1px] border-solid mx-[25px] bg-[#f7f7f7] my-[5px]"></div>
|
||||
<template v-for="(twoMenu, twoIndex) in menus">
|
||||
<el-sub-menu :index="String(twoMenu.meta.title)"
|
||||
v-if="twoMenu.meta.attr == 'system' && !twoMenu.meta.app && twoMenu.children">
|
||||
<template #title>
|
||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
||||
class="absolute !w-auto" size="18px" />
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(threeMenu, threeIndex) in twoMenu.children" :key="threeIndex">
|
||||
<el-sub-menu :index="String(threeMenu.meta.title)"
|
||||
v-if="threeMenu.meta.app && threeMenu.children">
|
||||
<template #title>
|
||||
<div class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||
<span class="iconfont iconyuanquan_huaban1 !text-[20px]"></span>
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(fourMenu, fourIndex) in threeMenu.children"
|
||||
:key="fourIndex">
|
||||
<!-- 三级菜单 -->
|
||||
<el-sub-menu :index="String(fourMenu.meta.title)"
|
||||
v-if="fourMenu.children && fourMenu.meta.show">
|
||||
<template #title>
|
||||
<div
|
||||
class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||
<span class="iconfont icondian !text-[25px]"></span>
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ fourMenu.meta.title
|
||||
}}</span>
|
||||
</template>
|
||||
<template v-for="(fiveMenu, fiveIndex) in fourMenu.children"
|
||||
:key="fiveIndex">
|
||||
<el-menu-item v-if="fiveMenu.meta.show"
|
||||
class="!h-[52px] !pl-[55px]" :index="String(fiveMenu.name)"
|
||||
@click="toLink(fiveMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ fiveMenu.meta.title
|
||||
}}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-else-if="fourMenu.meta.show"
|
||||
class="!ml-[30px] !h-[52px] !pl-[35px]"
|
||||
:index="String(fourMenu.name)" @click="toLink(fourMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ fourMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-if="threeMenu.meta.show" class="!h-[52px] !pl-[52px]"
|
||||
:index="String(threeMenu.name)" @click="toLink(threeMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
|
||||
<!-- 插件菜单 -->
|
||||
<template v-if="otherTypeList.includes(localMenuKey) && twoMenu.meta.key == 'app_center' && plugMenuType">
|
||||
<template v-for="(twoMenu, twoIndex) in menus">
|
||||
<el-sub-menu :index="String(twoMenu.meta.title)"
|
||||
v-if="twoMenu.meta.app && twoMenu.meta.app == plugMenuType && twoMenu.children">
|
||||
<template #title>
|
||||
<div class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||
<span class="iconfont iconyuanquan_huaban1 !text-[20px]"></span>
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="(threeMenu, threeIndex) in twoMenu.children"
|
||||
:key="threeIndex">
|
||||
<!-- 三级菜单 -->
|
||||
<el-sub-menu :index="String(threeMenu.meta.title)"
|
||||
v-if="threeMenu.children && threeMenu.meta.show">
|
||||
<template #title>
|
||||
<div
|
||||
class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||
<span class="iconfont icondian !text-[25px]"></span>
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title
|
||||
}}</span>
|
||||
</template>
|
||||
<template v-for="(fourMenu, fourIndex) in threeMenu.children"
|
||||
:key="fourIndex">
|
||||
<el-menu-item v-if="fourMenu.meta.show"
|
||||
class="!h-[52px] !pl-[55px]"
|
||||
:index="String(fourMenu.name)"
|
||||
@click="toLink(fourMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ fourMenu.meta.title
|
||||
}}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-else-if="threeMenu.meta.show"
|
||||
class="!ml-[30px] !h-[52px] !pl-[35px]"
|
||||
:index="String(threeMenu.name)" @click="toLink(threeMenu)">
|
||||
<template #title>
|
||||
<span class="text-[14px]">{{ threeMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
<el-menu-item
|
||||
v-else-if="twoMenu.meta.app && twoMenu.meta.app == plugMenuType"
|
||||
class="!pl-[25px] text-[#333]" :index="String(twoMenu.name)"
|
||||
@click="toLink(twoMenu)">
|
||||
<template #title>
|
||||
<div v-if="twoMenu.meta.icon"
|
||||
class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
||||
class="absolute !w-auto" size="18px" />
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-else-if="twoMenu.meta.attr == 'system' && !twoMenu.meta.app"
|
||||
class="!pl-[25px] text-[#333]" :index="String(twoMenu.name)"
|
||||
@click="toLink(twoMenu)">
|
||||
<template #title>
|
||||
<div v-if="twoMenu.meta.icon"
|
||||
class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
||||
class="absolute !w-auto" size="18px" />
|
||||
</div>
|
||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</template>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import side from './side.vue'
|
||||
import appMenu from './components/app-menu.vue'
|
||||
import { img } from '@/utils/common'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import storage from '@/utils/storage'
|
||||
import { CollectionTag } from '@element-plus/icons-vue'
|
||||
import { findFirstValidRoute } from '@/router/routers'
|
||||
import { getAddonByKey } from '@/app/api/addon'
|
||||
import { getApply } from '@/app/api/apply'
|
||||
|
||||
|
||||
const userStore = useUserStore()
|
||||
const systemStore = useSystemStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const globalAppKey = ref('') // 菜单类型
|
||||
const localMenuKey = ref('') // 菜单类型
|
||||
globalAppKey.value = storage.get('menuAppStorage')
|
||||
localMenuKey.value = storage.get('menuAppStorage')
|
||||
const isLoad = ref(false);
|
||||
|
||||
// 应用跳转 start
|
||||
const applyList = ref([])
|
||||
const applyTypeList = ref([])
|
||||
const otherTypeList = ref([]) // 存着插件\会员\应用管理
|
||||
const getApplelist = async () => {
|
||||
const res = await getApply()
|
||||
applyList.value = applyList.value.concat(res.data)
|
||||
applyList.value.forEach((item, index) => {
|
||||
if (item.type == 'app') { applyTypeList.value.push(item.key) }
|
||||
if (item.type == 'addon') { otherTypeList.value.push(item.key) }
|
||||
})
|
||||
otherTypeList.value = otherTypeList.value.concat(['member', 'app_center'])
|
||||
isLoad.value = true;
|
||||
}
|
||||
getApplelist()
|
||||
|
||||
const homeClick = () => {
|
||||
const key = storage.get('menuAppStorage')
|
||||
key ? router.push({ name: appLink.value[key] }) : router.push({ path: '/' })
|
||||
}
|
||||
// 应用跳转 end
|
||||
|
||||
// 菜单
|
||||
const appLink = ref({})
|
||||
const menus = computed(() => {
|
||||
const menus = []
|
||||
userStore.routers.forEach((item, index) => {
|
||||
if (item.children && item.children.length) {
|
||||
item.name = findFirstValidRoute(item.children)
|
||||
appLink.value[item.meta.app] = findFirstValidRoute(item.children)
|
||||
menus.push(item)
|
||||
} else {
|
||||
appLink.value[item.meta.app] = item.name
|
||||
menus.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
if(applyList.value && applyList.value.length){
|
||||
applyList.value.forEach((item,index) =>{
|
||||
menus.forEach((menuItem,menuIndex)=>{
|
||||
if(item.key == menuItem.meta.key){
|
||||
menuItem.meta.parentTitle = item.title;
|
||||
menuItem.meta.parentIcon = item.icon;
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 用于插件的卸载或安装
|
||||
if(!applyList.value.length){
|
||||
storage.set({ key: 'menuAppStorage', data: '' })
|
||||
globalAppKey.value = ""
|
||||
}
|
||||
if(applyList.value.length && !globalAppKey.value){
|
||||
storage.set({ key: 'menuAppStorage', data: applyTypeList.value[0] })
|
||||
globalAppKey.value = applyTypeList.value[0]
|
||||
}
|
||||
return menus
|
||||
})
|
||||
|
||||
const dark = computed(() => {
|
||||
return systemStore.dark
|
||||
})
|
||||
|
||||
// 用于插件的卸载或安装
|
||||
watch(() =>userStore.globalAppKey, (val,old) => {
|
||||
getApplelist();
|
||||
},{deep: true})
|
||||
|
||||
|
||||
// 监听路由
|
||||
let currMetaAppType = ''
|
||||
const plugMenuType = ref('') // 插件类型
|
||||
const currentRoute = ref('') // 当前路由
|
||||
watch(route, () => {
|
||||
plugMenuType.value = storage.get('plugMenuTypeStorage')
|
||||
|
||||
const data = route.matched[1]
|
||||
currentRoute.value = route.matched[1]
|
||||
localMenuKey.value = data.meta.key
|
||||
|
||||
systemStore.$patch(state => {
|
||||
state.menuDrawer = false
|
||||
})
|
||||
}, { immediate: true })
|
||||
|
||||
|
||||
|
||||
let onefloatMenu = ref(true);
|
||||
let threefloatMenu = ref(true);
|
||||
const onefloatMenuHover = ()=>{
|
||||
onefloatMenu.value = true;
|
||||
}
|
||||
const threefloatMenuHover = ()=>{
|
||||
threefloatMenu.value = true;
|
||||
}
|
||||
const toLink = (data, type) => {
|
||||
if(type == 'onefloatMenu') onefloatMenu.value = false;
|
||||
|
||||
if (!data.meta && data.type == 'app' || data.meta.key != 'official_market') {
|
||||
let name = data.name;
|
||||
if(data.type == 'app'){
|
||||
globalAppKey.value = data.key
|
||||
localMenuKey.value = data.key
|
||||
|
||||
storage.set({ key: 'menuAppStorage', data: data.key })
|
||||
storage.set({ key: 'plugMenuTypeStorage', data: '' })
|
||||
|
||||
const appMenuList = userStore.appMenuList
|
||||
appMenuList.push(data.key)
|
||||
userStore.setAppMenuList(appMenuList)
|
||||
|
||||
name = appLink.value[data.key];
|
||||
}
|
||||
router.push({ name: name })
|
||||
} else {
|
||||
window.open('https://www.niucloud.com/product/', '_blank')
|
||||
}
|
||||
}
|
||||
|
||||
// 主题风格
|
||||
const sidebar = computed(() => {
|
||||
return systemStore.sidebar
|
||||
})
|
||||
|
||||
// 控制二级菜单的显示
|
||||
const isTwoMenuFn = (item) => {
|
||||
let bool = (otherTypeList.value.includes(localMenuKey.value) && globalAppKey.value == item.meta.app)
|
||||
|| (!otherTypeList.value.includes(localMenuKey.value) && (item.meta.key == localMenuKey.value || item.meta.app == localMenuKey.value))
|
||||
return bool;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.layout-aside {
|
||||
|
||||
&.bright {
|
||||
background-color: #F5F7F9;
|
||||
|
||||
li {
|
||||
background-color: #F5F7F9;
|
||||
|
||||
&.is-active:not(.is-opened) {
|
||||
position: relative;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 2px;
|
||||
background-color: var(--el-menu-active-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.second-menu .el-sub-menu .el-sub-menu__title {
|
||||
padding-left: 25px !important;
|
||||
padding-right: 25px !important;
|
||||
|
||||
.el-icon.el-sub-menu__icon-arrow {
|
||||
right: 25px;
|
||||
font-weight: bolder;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.three-menu.el-sub-menu .el-sub-menu__title {
|
||||
padding-left: 45px !important;
|
||||
}
|
||||
|
||||
.text-color {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.aside-drawer {
|
||||
.el-drawer__body {
|
||||
padding: 0px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.cut-style {
|
||||
color: #6d7278;
|
||||
|
||||
}
|
||||
|
||||
.cut-style.qx {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
// 主题二
|
||||
.two-type {
|
||||
.logo-wrap {
|
||||
.logo span {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
background-color: #F5F7F9;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #273de3;
|
||||
font-size: 25px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.layout-aside {
|
||||
// background-color: #12192D;
|
||||
background-color: #2b303b;
|
||||
|
||||
.menu-item {
|
||||
color: #fff;
|
||||
|
||||
&.menu-item-active,
|
||||
&:hover {
|
||||
background-color: var(--el-color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.second-menu {
|
||||
background-color: #F5F7F9;
|
||||
|
||||
.el-menu {
|
||||
background-color: transparent;
|
||||
|
||||
.el-menu-item:hover {
|
||||
background-color: #fff;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.el-menu-item.is-active {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.el-sub-menu__title:hover {
|
||||
background-color: #fff;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.cut-style {
|
||||
color: #FFF;
|
||||
}
|
||||
}
|
||||
|
||||
// 主题三
|
||||
.three-type {
|
||||
.logo-wrap {
|
||||
.logo span {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
background-color: #F5F7F9;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #2E7BFD;
|
||||
font-size: 25px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.layout-aside {
|
||||
background-color: #2b303b;
|
||||
|
||||
.menu-item {
|
||||
color: #fff;
|
||||
|
||||
&.menu-item-active,
|
||||
&:hover {
|
||||
background-color: #303848;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.second-menu {
|
||||
background-color: #303848;
|
||||
|
||||
.second-head {
|
||||
color: #fff;
|
||||
border-color: #364059;
|
||||
}
|
||||
|
||||
.el-menu {
|
||||
background-color: transparent;
|
||||
|
||||
.el-menu-item {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.el-menu-item:hover,
|
||||
.el-menu-item.is-active {
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.el-sub-menu__title:hover {
|
||||
background-color: var(--el-color-primary);
|
||||
;
|
||||
}
|
||||
|
||||
.el-sub-menu__title {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.cut-style {
|
||||
color: #FFF;
|
||||
}
|
||||
}
|
||||
|
||||
.menus-wrap {
|
||||
height: calc(100vh - 64px);
|
||||
}
|
||||
</style>
|
||||
200
admin/src/layout/standard/components/header/index.vue
Normal file
200
admin/src/layout/standard/components/header/index.vue
Normal file
@ -0,0 +1,200 @@
|
||||
<template>
|
||||
<el-container :class="['h-full px-[10px]', { 'layout-header border-b border-color': !dark }]">
|
||||
<el-row class="w-100 h-full w-full">
|
||||
<el-col :span="12">
|
||||
<div class="left-panel h-full flex items-center">
|
||||
<!-- 刷新当前页 -->
|
||||
<div class="navbar-item flex items-center h-full cursor-pointer" @click="refreshRouter">
|
||||
<icon name="element-Refresh" />
|
||||
</div>
|
||||
<!-- 面包屑导航 -->
|
||||
<div class="flex items-center h-full pl-[10px] hidden-xs-only">
|
||||
<el-breadcrumb separator="/">
|
||||
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index">{{ route.meta.title }}</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="right-panel h-full flex items-center justify-end">
|
||||
<!-- 预览 只有站点时展示-->
|
||||
|
||||
<i class="iconfont iconlingdang-xianxing cursor-pointer px-[8px]" :title="t('newInfo')" v-if="appType == 'site'"></i>
|
||||
<!-- 切换首页 -->
|
||||
<div class="navbar-item flex items-center h-full cursor-pointer" v-if="appType == 'site'" @click="checkIndexList">
|
||||
<icon name="iconfont-iconqiehuan" :title="t('indexSwitch')" />
|
||||
</div>
|
||||
<!-- 切换语言 -->
|
||||
<div class="navbar-item !px-[0] flex items-center h-full cursor-pointer">
|
||||
<switch-lang />
|
||||
</div>
|
||||
<!-- 切换全屏 -->
|
||||
<div class="navbar-item flex items-center h-full cursor-pointer" @click="toggleFullscreen">
|
||||
<icon name="iconfont-icontuichuquanping" v-if="isFullscreen" />
|
||||
<icon name="iconfont-iconquanping" v-else />
|
||||
</div>
|
||||
<!-- 布局设置 -->
|
||||
<div class="navbar-item !px-[0] flex items-center h-full cursor-pointer">
|
||||
<layout-setting />
|
||||
</div>
|
||||
<!-- 用户信息 -->
|
||||
<div class="navbar-item flex items-center h-full cursor-pointer">
|
||||
<user-info />
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<input type="hidden" v-model="comparisonToken">
|
||||
|
||||
<el-dialog v-model="detectionLoginDialog" :title="t('layout.detectionLoginTip')" width="30%" :close-on-click-modal="false" :close-on-press-escape="false" :show-close="false">
|
||||
<span>{{ t('layout.detectionLoginContent') }}</span>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="detectionLoginFn">{{ t('layout.detectionLoginOperation') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="showDialog" :title="t('indexTemplate')" width="550px" :destroy-on-close="true">
|
||||
<div class="flex flex-wrap">
|
||||
<div v-for="(items, index) in indexList" :key="index" v-if="index_path == ''">
|
||||
<div @click="index_path = items.view_path" class="index-item py-[5px] px-[10px] mr-[10px] rounded-[3px] cursor-pointer" :class="items.is_use == 1 ? 'bg-primary text-[#fff]' : ''">
|
||||
<span>{{ items.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="(itemTo, indexTo) in indexList" :key="indexTo" v-else>
|
||||
<div @click="index_path = itemTo.view_path" class="index-item py-[5px] px-[10px] mr-[10px] rounded-[3px] cursor-pointer" :class="index_path == itemTo.view_path ? 'bg-primary text-[#fff]' : ''">
|
||||
<span>{{ itemTo.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button type="primary" @click="submitIndex">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, onMounted, watch } from 'vue'
|
||||
import layoutSetting from './layout-setting.vue'
|
||||
import switchLang from './switch-lang.vue'
|
||||
import userInfo from './user-info.vue'
|
||||
import { useFullscreen } from '@vueuse/core'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
import storage from '@/utils/storage'
|
||||
import { getIndexList, setIndexList } from '@/app/api/sys'
|
||||
|
||||
const router = useRouter()
|
||||
const appType = storage.get('app_type')
|
||||
const { toggle: toggleFullscreen, isFullscreen } = useFullscreen()
|
||||
const systemStore = useSystemStore()
|
||||
const appStore = useAppStore()
|
||||
const route = useRoute()
|
||||
const screenWidth = ref(window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth)
|
||||
|
||||
const dark = computed(() => {
|
||||
return systemStore.dark
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 监听窗体宽度变化
|
||||
window.onresize = () => {
|
||||
return (() => {
|
||||
screenWidth.value = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
|
||||
})()
|
||||
}
|
||||
})
|
||||
|
||||
watch(screenWidth, () => {
|
||||
if (screenWidth.value < 992) {
|
||||
if (!systemStore.menuIsCollapse) systemStore.toggleMenuCollapse(true)
|
||||
} else {
|
||||
if (systemStore.menuIsCollapse) systemStore.toggleMenuCollapse(false)
|
||||
}
|
||||
})
|
||||
|
||||
// 菜单栏展开折叠
|
||||
const toggleMenuCollapse = () => {
|
||||
systemStore.$patch((state) => {
|
||||
if (screenWidth.value < 768) {
|
||||
state.menuDrawer = true
|
||||
state.menuIsCollapse = false
|
||||
} else {
|
||||
systemStore.toggleMenuCollapse(!systemStore.menuIsCollapse)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 刷新路由
|
||||
const refreshRouter = () => {
|
||||
if (!appStore.routeRefreshTag) return
|
||||
appStore.refreshRouterView()
|
||||
}
|
||||
|
||||
// 面包屑导航
|
||||
const breadcrumb = computed(() => {
|
||||
const matched = route.matched.filter(item => { return item.meta.title })
|
||||
if (matched[0] && matched[0].path == '/') matched.splice(0, 1)
|
||||
return matched
|
||||
})
|
||||
|
||||
// 返回上一页
|
||||
const backFn = () => {
|
||||
router.go(-1)
|
||||
}
|
||||
|
||||
const indexList = ref()
|
||||
const showDialog = ref(false)
|
||||
const checkIndexList = () => {
|
||||
getIndexList().then(res => {
|
||||
showDialog.value = true
|
||||
indexList.value = res.data
|
||||
for (let i = 0; i < indexList.value.length; i++) {
|
||||
if (indexList.value[i].is_use == 1) {
|
||||
index_path.value = indexList.value[i].view_path
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const index_path = ref('')
|
||||
const submitIndex = () => {
|
||||
setIndexList({
|
||||
view_path: index_path.value
|
||||
}).then(() => {
|
||||
showDialog.value = false
|
||||
router.go(0)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.layout-header {
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
box-shadow: 0px 0px 4px 0px rgba(0, 145, 255, 0.1);
|
||||
}
|
||||
|
||||
.navbar-item {
|
||||
padding: 0 8px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--el-bg-color-page);
|
||||
}
|
||||
}
|
||||
|
||||
.index-item {
|
||||
border: 1px solid;
|
||||
border-color: var(--el-color-primary);
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
}</style>
|
||||
119
admin/src/layout/standard/components/header/layout-setting.vue
Normal file
119
admin/src/layout/standard/components/header/layout-setting.vue
Normal file
@ -0,0 +1,119 @@
|
||||
<template>
|
||||
<div class="flex w-[100%] h-[100%]" @click="drawer = true">
|
||||
<div class="h-[100%] w-[100%] flex items-center justify-center px-[8px]">
|
||||
<icon name="element-Setting" />
|
||||
</div>
|
||||
<el-drawer v-model="drawer" :title="t('layout.layoutSetting')" size="300px">
|
||||
<el-scrollbar>
|
||||
<div class="setting-item flex items-baseline justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary whitespace-nowrap">{{ t('layout.sidebarStyle') }}</div>
|
||||
<div class="">
|
||||
<el-radio-group v-model="sidebarStyle" class="ml-4">
|
||||
<el-radio label="oneType" size="large">样式一</el-radio>
|
||||
<el-radio label="twoType" size="large">样式二</el-radio>
|
||||
<el-radio label="threeType" size="large">样式三</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 风格切换 -->
|
||||
<div class="setting-item flex items-baseline justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary whitespace-nowrap">{{ t('layout.sidebarMode') }}</div>
|
||||
<div class="">
|
||||
<el-radio-group v-model="sidebar" class="ml-4">
|
||||
<el-radio label="oneType" size="large">
|
||||
<img class="w-[35px] h-[35px]" src="@/app/assets/images/one_type.png" alt="">
|
||||
</el-radio>
|
||||
<el-radio label="twoType" size="large">
|
||||
<img class="w-[35px] h-[35px]" src="@/app/assets/images/two_type.png" alt="">
|
||||
</el-radio>
|
||||
<el-radio label="threeType" size="large">
|
||||
<img class="w-[35px] h-[35px]" src="@/app/assets/images/three_type.png" alt="">
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 黑暗模式 -->
|
||||
<div class="setting-item flex items-center justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary">{{ t('layout.darkMode') }}</div>
|
||||
<div class="">
|
||||
<el-switch v-model="dark" :active-value="true" :inactive-value="false" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 主题颜色 -->
|
||||
<div class="setting-item flex items-center justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary">{{ t('layout.themeColor') }}</div>
|
||||
<div class="">
|
||||
<el-color-picker v-model="theme" />
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import { useDark, useToggle } from '@vueuse/core'
|
||||
import { setThemeColor } from '@/utils/common'
|
||||
import { t } from '@/lang'
|
||||
|
||||
const drawer = ref(false)
|
||||
const systemStore = useSystemStore()
|
||||
|
||||
const isDark = useDark()
|
||||
const toggleDark = useToggle(isDark)
|
||||
|
||||
const dark = computed({
|
||||
get() {
|
||||
return systemStore.dark
|
||||
},
|
||||
set(val) {
|
||||
systemStore.setTheme('dark', val)
|
||||
toggleDark(val)
|
||||
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||
}
|
||||
})
|
||||
|
||||
const sidebar = computed({
|
||||
get() {
|
||||
return systemStore.sidebar
|
||||
},
|
||||
set(val) {
|
||||
systemStore.setTheme('sidebar', val)
|
||||
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const sidebarStyle = computed({
|
||||
get() {
|
||||
return systemStore.sidebarStyle
|
||||
},
|
||||
set(val) {
|
||||
systemStore.setTheme('sidebarStyle', val)
|
||||
}
|
||||
})
|
||||
|
||||
const theme = computed({
|
||||
get() {
|
||||
return systemStore.theme
|
||||
},
|
||||
set(val) {
|
||||
systemStore.setTheme('theme', val)
|
||||
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-drawer__header) {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.layout-style {
|
||||
&>div:nth-child(2n+2) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
35
admin/src/layout/standard/components/header/switch-lang.vue
Normal file
35
admin/src/layout/standard/components/header/switch-lang.vue
Normal file
@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<el-dropdown @command="switchLang" :tabindex="1" class="h-[100%] w-[100%]">
|
||||
<div class="h-[100%] w-[100%] flex items-center justify-center px-[8px]">
|
||||
<icon name="iconfont-iconfanyi" />
|
||||
</div>
|
||||
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="zh-cn" :disabled="systemStore.lang == 'zh-cn'">简体中文</el-dropdown-item>
|
||||
<el-dropdown-item command="en" :disabled="systemStore.lang == 'en'">English</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import { language } from '@/lang'
|
||||
import { useRoute } from 'vue-router'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
const route = useRoute()
|
||||
const systemStore = useSystemStore()
|
||||
|
||||
const switchLang = (command: string) => {
|
||||
systemStore.$patch((state) => {
|
||||
state.lang = command
|
||||
storage.set({ key: 'lang', data: command })
|
||||
})
|
||||
language.loadLocaleMessages(route.meta.app || '', route.path, systemStore.lang)
|
||||
location.reload()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
32
admin/src/layout/standard/components/header/user-info.vue
Normal file
32
admin/src/layout/standard/components/header/user-info.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<el-dropdown @command="clickEvent" :tabindex="1">
|
||||
<div class="userinfo flex h-full items-center">
|
||||
<el-avatar :size="25" :icon="UserFilled" />
|
||||
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
||||
<icon name="element-ArrowDown" class="ml-[5px]" />
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="usercenter"><router-link to="/user/center">个人中心</router-link></el-dropdown-item>
|
||||
<el-dropdown-item command="logout">退出登录</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { UserFilled } from '@element-plus/icons-vue'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const clickEvent = (command: string) => {
|
||||
switch (command) {
|
||||
case 'logout':
|
||||
userStore.logout()
|
||||
break
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
40
admin/src/layout/standard/index.vue
Normal file
40
admin/src/layout/standard/index.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div class="common-layout min-w-[1200px]" >
|
||||
<el-container class="w-100 h-screen">
|
||||
<layout-aside></layout-aside>
|
||||
|
||||
<el-container>
|
||||
<el-header>
|
||||
<layout-header></layout-header>
|
||||
</el-header>
|
||||
|
||||
<el-main :class="['main-wrap h-full p-0',{'bg-page': dark}]">
|
||||
<el-scrollbar>
|
||||
<div>
|
||||
<router-view v-slot="{ Component, route }" v-if="appStore.routeRefreshTag">
|
||||
<component :is="Component" :key="route.fullPath" />
|
||||
</router-view>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-main>
|
||||
|
||||
</el-container>
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import layoutHeader from './components/header/index.vue'
|
||||
import layoutAside from './components/aside/index.vue'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
|
||||
const appStore = useAppStore()
|
||||
const systemStore = useSystemStore()
|
||||
const dark = computed(()=>{
|
||||
return systemStore.dark
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -55,7 +55,7 @@ router.beforeEach(async (to, from, next) => {
|
||||
} else {
|
||||
ROOT_ROUTER.redirect = { name: firstRoute }
|
||||
}
|
||||
console.log(currApp, ROOT_ROUTER.redirect)
|
||||
// console.log(currApp, ROOT_ROUTER.redirect)
|
||||
router.addRoute(ROOT_ROUTER)
|
||||
|
||||
// 添加动态路由
|
||||
|
||||
@ -67,6 +67,7 @@ const addonModules = import.meta.glob('@/**/views/**/*.vue')
|
||||
|
||||
interface Route {
|
||||
menu_name: string,
|
||||
menu_short_name: string,
|
||||
router_path: string,
|
||||
view_path: string
|
||||
menu_type: number,
|
||||
@ -93,6 +94,7 @@ const createRoute = function (route: Route, parentRoute: RouteRecordRaw | null =
|
||||
name: route.menu_key,
|
||||
meta: {
|
||||
title: route.menu_name,
|
||||
shortTitle: route.menu_short_name,
|
||||
icon: route.icon,
|
||||
type: route.menu_type,
|
||||
show: route.is_show,
|
||||
|
||||
@ -8,7 +8,8 @@ interface System {
|
||||
dark: boolean,
|
||||
theme: string,
|
||||
lang: string,
|
||||
sidebar: string
|
||||
sidebar: string,
|
||||
sidebarStyle: string
|
||||
}
|
||||
|
||||
const theme = storage.get('theme') ?? {}
|
||||
@ -21,6 +22,7 @@ const useSystemStore = defineStore('system', {
|
||||
dark: theme.dark ?? false,
|
||||
theme: theme.theme ?? '#273de3',
|
||||
sidebar: theme.sidebar ?? 'oneType',
|
||||
sidebarStyle: theme.sidebarStyle ?? 'oneType',
|
||||
lang: storage.get('lang') ?? 'zh-cn'
|
||||
}
|
||||
},
|
||||
|
||||
@ -3,6 +3,7 @@ import { getToken, setToken, removeToken, getAppType } from '@/utils/common'
|
||||
import { login, getAuthMenus } from '@/app/api/auth'
|
||||
import storage from '@/utils/storage'
|
||||
import router from '@/router'
|
||||
import { getApply } from '@/app/api/apply'
|
||||
import { formatRouters, findFirstValidRoute } from '@/router/routers'
|
||||
|
||||
interface User {
|
||||
@ -11,10 +12,11 @@ interface User {
|
||||
routers: any[],
|
||||
addonIndexRoute: Record<string, symbol>,
|
||||
rules: any[],
|
||||
appMenuList: any[]
|
||||
appMenuList: any[],
|
||||
globalAppKey: string
|
||||
}
|
||||
|
||||
const useSystemStore = defineStore('user', {
|
||||
const useUserStore = defineStore('user', {
|
||||
state: (): User => {
|
||||
return {
|
||||
token: getToken() || '',
|
||||
@ -22,6 +24,7 @@ const useSystemStore = defineStore('user', {
|
||||
routers: [],
|
||||
addonIndexRoute: {},
|
||||
rules: [],
|
||||
globalAppKey: '',
|
||||
appMenuList: storage.get('appMenuList' + (storage.get('userinfo') ? storage.get('userinfo').username : '')) || []
|
||||
}
|
||||
},
|
||||
@ -74,8 +77,33 @@ const useSystemStore = defineStore('user', {
|
||||
setAppMenuList(data: any) {
|
||||
this.appMenuList = data
|
||||
storage.set({ key: 'appMenuList' + (this.userInfo.username ? this.userInfo.username : ''), data })
|
||||
},
|
||||
getAppList() {
|
||||
let applyList = [];
|
||||
let applyTypeList = [];
|
||||
let appKey = storage.get('menuAppStorage');
|
||||
return new Promise((resolve, reject) => {
|
||||
getApply()
|
||||
.then((res) => {
|
||||
applyList = applyList.concat(res.data);
|
||||
applyList.forEach((item, index) => {
|
||||
if (item.type == 'app') { applyTypeList.push(item.key) }
|
||||
});
|
||||
// 用于插件的卸载或安装
|
||||
if (!applyList.length) {
|
||||
this.globalAppKey = '';
|
||||
}
|
||||
if (applyList.length && !appKey) {
|
||||
this.globalAppKey = applyTypeList[0];
|
||||
}
|
||||
resolve(res)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default useSystemStore
|
||||
export default useUserStore
|
||||
|
||||
@ -224,6 +224,10 @@ html.dark {
|
||||
.el-button:not(.is-round){
|
||||
border-radius: 2px !important;
|
||||
}
|
||||
// 修改表格中上传图片样式冲突的问题
|
||||
.el-table .el-table__cell{
|
||||
position: inherit !important;
|
||||
}
|
||||
|
||||
// /* 多行超出隐藏 */
|
||||
.multi-hidden {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 3883393 */
|
||||
src: url('//at.alicdn.com/t/c/font_3883393_bq3in2lb5mh.woff2?t=1695086543767') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_bq3in2lb5mh.woff?t=1695086543767') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_bq3in2lb5mh.ttf?t=1695086543767') format('truetype');
|
||||
src: url('//at.alicdn.com/t/c/font_3883393_yevzijodb3.woff2?t=1695808853045') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_yevzijodb3.woff?t=1695808853045') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_yevzijodb3.ttf?t=1695808853045') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@ -13,6 +13,50 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icongonggao:before {
|
||||
content: "\e629";
|
||||
}
|
||||
|
||||
.iconshangpinliebiao:before {
|
||||
content: "\e628";
|
||||
}
|
||||
|
||||
.icongouwuche1:before {
|
||||
content: "\e680";
|
||||
}
|
||||
|
||||
.icongouwuche:before {
|
||||
content: "\e6c8";
|
||||
}
|
||||
|
||||
.iconyun1:before {
|
||||
content: "\e67e";
|
||||
}
|
||||
|
||||
.iconicon-selected:before {
|
||||
content: "\e626";
|
||||
}
|
||||
|
||||
.iconshangpinguanli:before {
|
||||
content: "\e67c";
|
||||
}
|
||||
|
||||
.iconyuanquan_huaban1:before {
|
||||
content: "\e66c";
|
||||
}
|
||||
|
||||
.iconzhankai:before {
|
||||
content: "\e67b";
|
||||
}
|
||||
|
||||
.iconjiantou:before {
|
||||
content: "\e67a";
|
||||
}
|
||||
|
||||
.iconchajian1:before {
|
||||
content: "\e679";
|
||||
}
|
||||
|
||||
.iconicon_huojian:before {
|
||||
content: "\e677";
|
||||
}
|
||||
|
||||
@ -5,6 +5,76 @@
|
||||
"css_prefix_text": "icon",
|
||||
"description": "系统图标",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "37443500",
|
||||
"name": "展开",
|
||||
"font_class": "zhankai",
|
||||
"unicode": "e67b",
|
||||
"unicode_decimal": 59003
|
||||
},
|
||||
{
|
||||
"icon_id": "37443497",
|
||||
"name": "箭头",
|
||||
"font_class": "jiantou",
|
||||
"unicode": "e67a",
|
||||
"unicode_decimal": 59002
|
||||
},
|
||||
{
|
||||
"icon_id": "37440097",
|
||||
"name": "插件",
|
||||
"font_class": "chajian1",
|
||||
"unicode": "e679",
|
||||
"unicode_decimal": 59001
|
||||
},
|
||||
{
|
||||
"icon_id": "37401589",
|
||||
"name": "icon_火箭",
|
||||
"font_class": "icon_huojian",
|
||||
"unicode": "e677",
|
||||
"unicode_decimal": 58999
|
||||
},
|
||||
{
|
||||
"icon_id": "37396974",
|
||||
"name": "安装",
|
||||
"font_class": "anzhuang",
|
||||
"unicode": "e676",
|
||||
"unicode_decimal": 58998
|
||||
},
|
||||
{
|
||||
"icon_id": "37394752",
|
||||
"name": "首页",
|
||||
"font_class": "shouye",
|
||||
"unicode": "e675",
|
||||
"unicode_decimal": 58997
|
||||
},
|
||||
{
|
||||
"icon_id": "2023693",
|
||||
"name": "首页-首页",
|
||||
"font_class": "shouye-shouye",
|
||||
"unicode": "e638",
|
||||
"unicode_decimal": 58936
|
||||
},
|
||||
{
|
||||
"icon_id": "4933869",
|
||||
"name": "点",
|
||||
"font_class": "dian",
|
||||
"unicode": "ec1e",
|
||||
"unicode_decimal": 60446
|
||||
},
|
||||
{
|
||||
"icon_id": "5387931",
|
||||
"name": "箭头_向左两次_o",
|
||||
"font_class": "jiantou_xiangzuoliangci_o",
|
||||
"unicode": "eb93",
|
||||
"unicode_decimal": 60307
|
||||
},
|
||||
{
|
||||
"icon_id": "781940",
|
||||
"name": "分类",
|
||||
"font_class": "fenlei",
|
||||
"unicode": "e6c3",
|
||||
"unicode_decimal": 59075
|
||||
},
|
||||
{
|
||||
"icon_id": "37134174",
|
||||
"name": "切换",
|
||||
|
||||
@ -161,4 +161,39 @@ export function urlToRouteRaw(url: string) {
|
||||
})
|
||||
|
||||
return { path, query }
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一字符
|
||||
* @param {Number} len
|
||||
* @param {Boolean} firstU
|
||||
* @param {Nubmer} radix
|
||||
*/
|
||||
export function guid(len = 10, firstU = true, radix = null) {
|
||||
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
|
||||
const uuid = []
|
||||
radix = radix || chars.length
|
||||
|
||||
if (len) {
|
||||
// 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
|
||||
for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]
|
||||
} else {
|
||||
let r
|
||||
// rfc4122标准要求返回的uuid中,某些位为固定的字符
|
||||
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
|
||||
uuid[14] = '4'
|
||||
|
||||
for (let i = 0; i < 36; i++) {
|
||||
if (!uuid[i]) {
|
||||
r = 0 | Math.random() * 16
|
||||
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]
|
||||
}
|
||||
}
|
||||
}
|
||||
// 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class
|
||||
if (firstU) {
|
||||
uuid.shift()
|
||||
return `u${uuid.join('')}`
|
||||
}
|
||||
return uuid.join('')
|
||||
}
|
||||
180
admin/src/utils/qqmap.ts
Normal file
180
admin/src/utils/qqmap.ts
Normal file
@ -0,0 +1,180 @@
|
||||
import { jsonp } from 'vue-jsonp'
|
||||
|
||||
const geometry: any = {}
|
||||
|
||||
/**
|
||||
* 在地图上创建一个圆形
|
||||
*/
|
||||
export const createCircle = (map: any, geometriesData: any) => {
|
||||
const TMap = (window as any).TMap
|
||||
const LatLng = TMap.LatLng
|
||||
|
||||
geometriesData.radius = geometriesData.radius ?? 1000
|
||||
geometriesData.center = geometriesData.center ?? { lat: map.getCenter().lat, lng: map.getCenter().lng }
|
||||
|
||||
const color = [
|
||||
Math.floor(Math.random() * 255),
|
||||
Math.floor(Math.random() * 255),
|
||||
Math.floor(Math.random() * 255)
|
||||
]
|
||||
|
||||
// 创建图形
|
||||
const multiCircle = new TMap.MultiCircle({
|
||||
map,
|
||||
styles: { // 设置圆形样式
|
||||
circle: new TMap.CircleStyle({
|
||||
color: `rgba(${color.toString()}, .4)`,
|
||||
showBorder: true,
|
||||
borderColor: `rgb(${color.toString()})`,
|
||||
borderWidth: 2
|
||||
})
|
||||
},
|
||||
geometries: [
|
||||
{
|
||||
styleId: 'circle',
|
||||
center: new LatLng(geometriesData.center.lat, geometriesData.center.lng),
|
||||
radius: geometriesData.radius,
|
||||
id: geometriesData.key
|
||||
}
|
||||
]
|
||||
})
|
||||
geometry[geometriesData.key] = { graphical: multiCircle }
|
||||
|
||||
// 创建图形编辑器
|
||||
const editor = new TMap.tools.GeometryEditor({
|
||||
map: map,
|
||||
overlayList: [
|
||||
{
|
||||
overlay: multiCircle,
|
||||
id: geometriesData.key,
|
||||
}
|
||||
],
|
||||
actionMode: TMap.tools.constants.EDITOR_ACTION.INTERACT,
|
||||
activeOverlayId: geometriesData.key, // 激活图层
|
||||
selectable: true // 开启点选功能
|
||||
})
|
||||
|
||||
editor.on('adjust_complete', (data: any) => {
|
||||
geometriesData.center = data.center
|
||||
geometriesData.radius = data.radius
|
||||
})
|
||||
|
||||
geometry[geometriesData.key] = { graphical: multiCircle, editor }
|
||||
}
|
||||
|
||||
/**
|
||||
* 在地图上创建一个多边形
|
||||
* @param map
|
||||
* @param geometriesData
|
||||
*/
|
||||
export const createPolygon = (map: any, geometriesData: any) => {
|
||||
const TMap = (window as any).TMap
|
||||
const LatLng = TMap.LatLng
|
||||
|
||||
const { lat, lng } = map.getCenter();
|
||||
|
||||
geometriesData.paths = geometriesData.paths ?? [
|
||||
{ lat: lat + 0.01, lng: lng + 0.01 },
|
||||
{ lat: lat - 0.01, lng: lng + 0.01 },
|
||||
{ lat: lat - 0.01, lng: lng - 0.01 },
|
||||
{ lat: lat + 0.01, lng: lng - 0.01 }
|
||||
]
|
||||
|
||||
const color = [
|
||||
Math.floor(Math.random() * 255),
|
||||
Math.floor(Math.random() * 255),
|
||||
Math.floor(Math.random() * 255)
|
||||
]
|
||||
|
||||
const multiPolygon = new TMap.MultiPolygon({
|
||||
map: map,
|
||||
styles: {
|
||||
polygon: new TMap.PolygonStyle({
|
||||
color: `rgba(${color.toString()}, .4)`,
|
||||
showBorder: true,
|
||||
borderColor: `rgb(${color.toString()})`,
|
||||
borderWidth: 2
|
||||
})
|
||||
},
|
||||
geometries: [
|
||||
{
|
||||
id: geometriesData.key,
|
||||
styleId: 'polygon',
|
||||
paths: geometriesData.paths.map((item: any) => {
|
||||
return new LatLng(item.lat, item.lng)
|
||||
})
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const editor = new TMap.tools.GeometryEditor({
|
||||
map: map,
|
||||
overlayList: [
|
||||
{
|
||||
overlay: multiPolygon,
|
||||
id: geometriesData.key,
|
||||
}
|
||||
],
|
||||
actionMode: TMap.tools.constants.EDITOR_ACTION.INTERACT,
|
||||
activeOverlayId: geometriesData.key, // 激活图层
|
||||
selectable: true, // 开启点选功能
|
||||
})
|
||||
|
||||
editor.on('adjust_complete', (data: any) => {
|
||||
geometriesData.paths = data.paths
|
||||
})
|
||||
|
||||
geometry[geometriesData.key] = { graphical: multiPolygon, editor }
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除图形
|
||||
* @param key
|
||||
*/
|
||||
export const deleteGeometry = (key: string) => {
|
||||
geometry[key].graphical.remove(key)
|
||||
geometry[key].editor.delete()
|
||||
}
|
||||
|
||||
/**
|
||||
* 选中图形
|
||||
* @param key
|
||||
*/
|
||||
export const selectGeometry = (key: string) => {
|
||||
geometry[key].editor.select([key])
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建点标记
|
||||
* @param map
|
||||
* @returns
|
||||
*/
|
||||
export const createMarker = (map: any) => {
|
||||
const TMap = (window as any).TMap
|
||||
const LatLng = TMap.LatLng
|
||||
|
||||
return new TMap.MultiMarker({
|
||||
map,
|
||||
geometries: [
|
||||
{
|
||||
id: 'center',
|
||||
position: map.getCenter(),
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 逆地址解析
|
||||
* @param params
|
||||
*/
|
||||
export const latLngToAddress = (params: any) => {
|
||||
return jsonp(`https://apis.map.qq.com/ws/geocoder/v1/?key=${params.mapKey}&location=${params.lat},${params.lng}&output=jsonp&callback=callback`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 地址解析
|
||||
*/
|
||||
export const addressToLatLng = (params: any) => {
|
||||
return jsonp(`https://apis.map.qq.com/ws/geocoder/v1/?key=${params.mapKey}&address=${params.address}&output=jsonp&callback=callback`)
|
||||
}
|
||||
@ -7,11 +7,13 @@ import useUserStore from '@/stores/modules/user'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
interface RequestConfig extends AxiosRequestConfig {
|
||||
showSuccessMessage?: boolean
|
||||
showSuccessMessage?: boolean,
|
||||
showErrorMessage?: boolean
|
||||
}
|
||||
|
||||
interface InternalRequestConfig extends InternalAxiosRequestConfig {
|
||||
showSuccessMessage?: boolean
|
||||
showSuccessMessage?: boolean,
|
||||
showErrorMessage?: boolean
|
||||
}
|
||||
|
||||
interface requestResponse extends AxiosResponse {
|
||||
@ -48,18 +50,18 @@ class Request {
|
||||
// 全局响应拦截器
|
||||
this.instance.interceptors.response.use(
|
||||
(response: requestResponse) => {
|
||||
if (response.request.responseType != 'blob') {
|
||||
const res = response.data
|
||||
if (res.code != 1) {
|
||||
this.handleAuthError(res.code)
|
||||
if (res.code != 401) ElMessage({ message: res.msg, type: 'error' })
|
||||
return Promise.reject(new Error(res.msg || 'Error'))
|
||||
} else {
|
||||
if (response.config.showSuccessMessage) ElMessage({ message: res.msg, type: 'success' })
|
||||
return res
|
||||
}
|
||||
}
|
||||
return response.data
|
||||
if (response.request.responseType != 'blob') {
|
||||
const res = response.data
|
||||
if (res.code != 1) {
|
||||
this.handleAuthError(res.code)
|
||||
if (res.code != 401 && response.config.showErrorMessage !== false) ElMessage({ message: res.msg, type: 'error' })
|
||||
return Promise.reject(new Error(res.msg || 'Error'))
|
||||
} else {
|
||||
if (response.config.showSuccessMessage) ElMessage({ message: res.msg, type: 'success' })
|
||||
return res
|
||||
}
|
||||
}
|
||||
return response.data
|
||||
},
|
||||
(err: any) => {
|
||||
this.handleNetworkError(err)
|
||||
|
||||
@ -227,6 +227,12 @@ const test = {
|
||||
*/
|
||||
regExp(o) {
|
||||
return o && Object.prototype.toString.call(o) === '[object RegExp]'
|
||||
},
|
||||
/**
|
||||
* 验证必填
|
||||
*/
|
||||
require(value: string) {
|
||||
return /^\s*$/.test(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user