mirror of
https://gitee.com/niucloud-team/niucloud-admin.git
synced 2026-03-17 11:13:43 +00:00
update admin
This commit is contained in:
parent
63bf044a64
commit
992729a53d
@ -7,3 +7,7 @@ import request from '@/utils/request'
|
|||||||
export function getApply(params: Record<string, any>) {
|
export function getApply(params: Record<string, any>) {
|
||||||
return request.get(`auth/authaddon`, {params})
|
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')
|
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'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
// USER_CODE_BEGIN -- sys_dict
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取数据字典列表
|
* 获取数据字典列表
|
||||||
* @param params
|
* @param params
|
||||||
@ -32,7 +29,6 @@ export function addDict(params: Record<string, any>) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑数据字典
|
* 编辑数据字典
|
||||||
* @param id
|
|
||||||
* @param params
|
* @param params
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
@ -42,7 +38,6 @@ export function addDictData(params: Record<string, any>) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑数据字典
|
* 编辑数据字典
|
||||||
* @param id
|
|
||||||
* @param params
|
* @param params
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
@ -74,12 +69,10 @@ export function setDictData(id:number,params: Record<string, any>) {
|
|||||||
export function getDictAll() {
|
export function getDictAll() {
|
||||||
return request.get(`dict/all`)
|
return request.get(`dict/all`)
|
||||||
}
|
}
|
||||||
// USER_CODE_END -- sys_dict
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据字典关键词查询
|
* 数据字典关键词查询
|
||||||
* @param id
|
* @param type
|
||||||
* @param params
|
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function useDictionary(type: string) {
|
export function useDictionary(type: string) {
|
||||||
|
|||||||
@ -40,7 +40,7 @@ export function getModuleVersion() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载版本
|
* 下载版本
|
||||||
* @param addon
|
* @param params
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function downloadVersion(params: Record<string, any>) {
|
export function downloadVersion(params: Record<string, any>) {
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************** 账单列表 **************************************************/
|
/***************************************************** 账单列表 **************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -15,4 +15,3 @@ export function getUserInfo(type: string) {
|
|||||||
export function setUserInfo(params: Record<string, any>) {
|
export function setUserInfo(params: Record<string, any>) {
|
||||||
return request.put(`auth/edit`, params, {showSuccessMessage: true});
|
return request.put(`auth/edit`, params, {showSuccessMessage: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,7 @@ export function getUrl() {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getRoleList(params: Record<string, any>) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function addRole(params: Record<string, any>) {
|
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
|
* @param params
|
||||||
*/
|
*/
|
||||||
export function editRole(params: Record<string, any>) {
|
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
|
* @param roleId
|
||||||
*/
|
*/
|
||||||
export function deleteRole(roleId: number) {
|
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
|
* @param params
|
||||||
*/
|
*/
|
||||||
export function edstatus(params: Record<string, any>) {
|
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
|
* @returns
|
||||||
@ -83,12 +84,14 @@ export function allRole() {
|
|||||||
export function getSystem() {
|
export function getSystem() {
|
||||||
return request.get(`sys/menu/system_menu`)
|
return request.get(`sys/menu/system_menu`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应用权限列表
|
* 应用权限列表
|
||||||
*/
|
*/
|
||||||
export function getAddonList() {
|
export function getAddonList() {
|
||||||
return request.get(`app/getAddonList`)
|
return request.get(`app/getAddonList`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应用权限详情列表
|
* 应用权限详情列表
|
||||||
* @param key
|
* @param key
|
||||||
@ -96,6 +99,7 @@ export function getAddonList() {
|
|||||||
export function getaddonMenu(key: any) {
|
export function getaddonMenu(key: any) {
|
||||||
return request.get(`sys/menu/addon_menu/${key}`)
|
return request.get(`sys/menu/addon_menu/${key}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************** 全部菜单 ****************************************************/
|
/***************************************************** 全部菜单 ****************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,7 +124,7 @@ export function getMenuInfo(menu_key: string) {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function addMenu(params: Record<string, any>) {
|
export function addMenu(params: Record<string, any>) {
|
||||||
return request.post('sys/menu', params, { showSuccessMessage: true })
|
return request.post('sys/menu', params, {showSuccessMessage: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,15 +132,17 @@ export function addMenu(params: Record<string, any>) {
|
|||||||
* @param params
|
* @param params
|
||||||
*/
|
*/
|
||||||
export function editMenu(params: Record<string, any>) {
|
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
|
* @param menu_key
|
||||||
*/
|
*/
|
||||||
export function deleteMenu(menu_key: string) {
|
export function deleteMenu(menu_key: string) {
|
||||||
return request.delete(`sys/menu/${menu_key}`, { showSuccessMessage: true })
|
return request.delete(`sys/menu/${menu_key}`, {showSuccessMessage: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取系统菜单
|
* 获取系统菜单
|
||||||
*
|
*
|
||||||
@ -144,13 +150,15 @@ export function deleteMenu(menu_key: string) {
|
|||||||
export function getSystemMenu() {
|
export function getSystemMenu() {
|
||||||
return request.get(`sys/menu/system_menu`)
|
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}`)
|
return request.get(`sys/menu/addon_menu/${key}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************** 站点菜单 ****************************************************/
|
/***************************************************** 站点菜单 ****************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -186,7 +194,7 @@ export function getWebConfig() {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function setWebsite(params: Record<string, any>) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function setCopyright(params: Record<string, any>) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getAttachmentCategoryList(params: Record<string, any>) {
|
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
|
* @param params
|
||||||
*/
|
*/
|
||||||
export function addAttachmentCategory(params: Record<string, any>) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function editAttachmentCategory(params: Record<string, any>) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function deleteAttachmentCategory(id: number) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getAttachmentList(params: Record<string, any>) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function deleteAttachment(params: Record<string, any>) {
|
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>) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getIconCategoryList(params: Record<string, any>) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getIconList(params: Record<string, any>) {
|
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) {
|
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) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function editStorage(params: Record<string, any>) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function setPayConfig(params: Record<string, any>) {
|
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
|
* @param channel
|
||||||
*/
|
*/
|
||||||
export function getTransferInfo(channel) {
|
export function getTransferInfo(channel: string) {
|
||||||
return request.get(`pay/channel/lists/${channel}`)
|
return request.get(`pay/channel/lists/${channel}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,7 +441,7 @@ export function setTransferInfo(params: Record<string, any>) {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getCronList(params: any) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function addCron(params: Record<string, any>) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function editCron(params: Record<string, any>) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function deleteCron(id: string) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function editAgreement(params: Record<string, any>) {
|
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
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function setConfigLogin(params: Record<string, any>) {
|
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>) {
|
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>) {
|
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>) {
|
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
|
* 设置地图key
|
||||||
*/
|
*/
|
||||||
export function setMap(params: Record<string, any>) {
|
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,14 +619,14 @@ export function getIndexList() {
|
|||||||
* 设置首页模版
|
* 设置首页模版
|
||||||
*/
|
*/
|
||||||
export function setIndexList(params: Record<string, any>) {
|
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>) {
|
export function getPayAuditList(params: Record<string, any>) {
|
||||||
return request.get('pay/audit', { params })
|
return request.get('pay/audit', {params})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -618,7 +634,7 @@ export function getPayAuditList(params: Record<string, any>) {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function payAuditPass(outTradeNo: string) {
|
export function payAuditPass(outTradeNo: string) {
|
||||||
return request.put(`pay/pass/${outTradeNo}`, {}, { showSuccessMessage: true })
|
return request.put(`pay/pass/${outTradeNo}`, {}, {showSuccessMessage: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -626,7 +642,7 @@ export function payAuditPass(outTradeNo: string) {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function payAuditRefuse(params: Record<string, any>) {
|
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>) {
|
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'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
/***************************************************** 插件开发 ****************************************************/
|
/***************************************************** 插件开发 ****************************************************/
|
||||||
/**
|
/**
|
||||||
* 获取插件列表
|
* 获取插件列表
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getAddonDevelop(params: Record<string, any>) {
|
export function getAddonDevelop(params: Record<string, any>) {
|
||||||
return request.get(`addon_develop`,{params});
|
return request.get(`addon_develop`, {params});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取插件类型配置
|
* 获取插件类型配置
|
||||||
* @returns
|
* @returns
|
||||||
@ -14,60 +16,70 @@ export function getAddonDevelop(params: Record<string, any>) {
|
|||||||
export function getAddontype() {
|
export function getAddontype() {
|
||||||
return request.get(`addontype`);
|
return request.get(`addontype`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取插件详情
|
* 获取插件详情
|
||||||
|
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getAddonDevelopInfo(key:any) {
|
export function getAddonDevelopInfo(key: any) {
|
||||||
return request.get(`addon_develop/${key}`)
|
return request.get(`addon_develop/${key}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取插件key是否存在
|
* 获取插件key是否存在
|
||||||
|
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getAddonDevelopCheck(key:any) {
|
export function getAddonDevelopCheck(key: any) {
|
||||||
return request.get(`addon_develop/check/${key}`)
|
return request.get(`addon_develop/check/${key}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加插件
|
* 添加插件
|
||||||
|
* @param key
|
||||||
* @param params
|
* @param params
|
||||||
* @returns
|
* @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)
|
return request.post(`addon_develop/${key}`, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑插件
|
* 编辑插件
|
||||||
|
* @param key
|
||||||
* @param params
|
* @param params
|
||||||
* @returns
|
* @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)
|
return request.put(`addon_develop/${key}`, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除插件
|
* 删除插件
|
||||||
* @param id
|
* @param key
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function deleteAddonDevelop(key: any) {
|
export function deleteAddonDevelop(key: any) {
|
||||||
return request.delete(`addon_develop/${key}`, {showSuccessMessage: true})
|
return request.delete(`addon_develop/${key}`, {showSuccessMessage: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打包插件
|
* 打包插件
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function addonDevelopBuild(key:any) {
|
export function addonDevelopBuild(key: any) {
|
||||||
return request.post(`addon_develop/build/${key}`)
|
return request.post(`addon_develop/build/${key}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载插件
|
* 下载插件
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function addonDevelopDownload(key:any) {
|
export function addonDevelopDownload(key: any) {
|
||||||
return request.post(`addon_develop/download/${key}`,{},{ "responseType": "blob" })
|
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>) {
|
export function generateCreate(params: Record<string, any>) {
|
||||||
return request.post(`generator/download`, params)
|
return request.post(`generator/download`, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 代码生成预览
|
* 代码生成预览
|
||||||
* @param params
|
* @param id
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function generatePreview(id: number) {
|
export function generatePreview(id: number) {
|
||||||
return request.get(`generator/preview/${id}`)
|
return request.get(`generator/preview/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据表
|
* 数据表
|
||||||
*/
|
*/
|
||||||
@ -143,21 +157,24 @@ export function generateTable() {
|
|||||||
export function getSystem() {
|
export function getSystem() {
|
||||||
return request.get(`sys/system`)
|
return request.get(`sys/system`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取全部模型
|
* 获取全部模型
|
||||||
*/
|
*/
|
||||||
export function getGeneratorAllModel(params:any) {
|
export function getGeneratorAllModel(params: any) {
|
||||||
return request.get(`generator/all_model`,{params})
|
return request.get(`generator/all_model`, {params})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 表字段
|
* 获取 表字段
|
||||||
*/
|
*/
|
||||||
export function getGeneratorTableColumn(params:any){
|
export function getGeneratorTableColumn(params: any) {
|
||||||
return request.get(`generator/table_column`,{params})
|
return request.get(`generator/table_column`, {params})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步校验
|
* 同步校验
|
||||||
*/
|
*/
|
||||||
export function generatorCheckFile(params: Record<string, any>){
|
export function generatorCheckFile(params: Record<string, any>) {
|
||||||
return request.get(`generator/check_file`,{params})
|
return request.get(`generator/check_file`, {params})
|
||||||
}
|
}
|
||||||
@ -44,7 +44,6 @@ export function setWeappVersion(params: Record<string, any>) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信小程序预览码
|
* 微信小程序预览码
|
||||||
* @param params
|
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getWeappPreview() {
|
export function getWeappPreview() {
|
||||||
@ -100,7 +99,7 @@ export function getVersionList(params: Record<string, any>) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 版本详情
|
* 版本详情
|
||||||
* @param params
|
* @param id
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getVersionInfo(id: string) {
|
export function getVersionInfo(id: string) {
|
||||||
@ -118,7 +117,7 @@ export function editVersion(params: Record<string, any>) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 版本删除
|
* 版本删除
|
||||||
* @param params
|
* @param id
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function deleteVersion(id: string) {
|
export function deleteVersion(id: string) {
|
||||||
|
|||||||
@ -58,7 +58,3 @@ export function getTemplateList() {
|
|||||||
export function getBatchAcquisition(params: Record<string, any>) {
|
export function getBatchAcquisition(params: Record<string, any>) {
|
||||||
return request.put('wechat/template/sync', params, {showSuccessMessage: true})
|
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": "请输入组件路径",
|
"viewPathPlaceholder": "请输入组件路径",
|
||||||
"authIdPlaceholder": "请输入api路径",
|
"authIdPlaceholder": "请输入api路径",
|
||||||
"selectIconPlaceholder": "请选择菜单图标",
|
"selectIconPlaceholder": "请选择菜单图标",
|
||||||
"topLevel": "顶级"
|
"topLevel": "顶级",
|
||||||
|
"menuShortName":"菜单短标题",
|
||||||
|
"menuShortNamePlaceholder":"请输入菜单短标题"
|
||||||
}
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"app":"应用",
|
"app":"应用",
|
||||||
"noPlug":"暂无应用",
|
"descriptionLeft":"暂无安装任何应用或插件,马上去",
|
||||||
|
"link":"官方应用市场",
|
||||||
|
"descriptionRight":"逛逛",
|
||||||
"installApp":"安装应用"
|
"installApp":"安装应用"
|
||||||
}
|
}
|
||||||
@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"refresh":"刷新",
|
"refresh":"刷新",
|
||||||
"refreshMenu":"刷新菜单",
|
"resetting": "重置",
|
||||||
"refreshMenuDesc":"新增/修改插件菜单后,需要刷新插件菜单",
|
"refreshMenu":"重置菜单",
|
||||||
|
"refreshMenuDesc":"重置菜单会按照菜单的配置文件进行重置,针对用户自己添加的菜单不处理",
|
||||||
"dataCache":"数据缓存",
|
"dataCache":"数据缓存",
|
||||||
"dataCacheDesc":"新增/修改数据表后,需要清除数据表缓存"
|
"dataCacheDesc":"新增/修改数据表后,需要清除数据表缓存"
|
||||||
}
|
}
|
||||||
@ -24,7 +24,7 @@
|
|||||||
<span class="text-[14px] flex items-center text-[#797979]">
|
<span class="text-[14px] flex items-center text-[#797979]">
|
||||||
<span>授权码</span>
|
<span>授权码</span>
|
||||||
<em class="ml-[12px] mr-[10px] text-[12px] text-[#222222]">{{ authinfo.auth_code ? (isCheck ? authinfo.auth_code : hideAuthCode(authinfo.auth_code)) : '--' }}</em>
|
<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>
|
<el-icon v-else @click="isCheck = !isCheck" class="text-[12px] cursor-pointer"><Hide /></el-icon>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -33,7 +33,7 @@
|
|||||||
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary" @click="authCodeApproveFn">授权码认证</el-button>
|
<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]">
|
<el-popover ref="getAuthCodeDialog" placement="bottom" :width="478" trigger="click" class="mt-[8px]">
|
||||||
<div class="px-[18px] py-[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]">
|
<div class="flex justify-end mt-[36px]">
|
||||||
<el-button class="w-[182px] !h-[48px]" plain @click="market">去应用市场逛逛</el-button>
|
<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>
|
<el-button class="w-[100px] !h-[48px]" plain @click="getAuthCodeDialog.hide()">关闭</el-button>
|
||||||
@ -44,7 +44,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</div>
|
</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-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<el-form-item prop="auth_code">
|
<el-form-item prop="auth_code">
|
||||||
@ -96,12 +96,6 @@ const hideAuthCode = (res)=>{
|
|||||||
|
|
||||||
const authCodeApproveFn = ()=>{
|
const authCodeApproveFn = ()=>{
|
||||||
authCodeApproveDialog.value = true;
|
authCodeApproveDialog.value = true;
|
||||||
authinfo.value = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
const closeAuthCodeApproveDialogFn = ()=>{
|
|
||||||
loading.value = true;
|
|
||||||
checkAppMange();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const authinfo = ref("");
|
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) => {
|
const save = async (formEl: FormInstance | undefined) => {
|
||||||
if (saveLoading.value || !formEl) return;
|
if (saveLoading.value || !formEl) return;
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container h-[500px] w-full p-5 bg-white" v-loading="loading">
|
<div class="main-container h-[500px] w-full p-5 bg-white" v-loading="loading">
|
||||||
|
<div class="flex justify-between items-center h-[32px] mb-4">
|
||||||
<div class="flex mb-4">
|
<span class="text-[20px]">{{ t('localAppText') }}</span>
|
||||||
<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>
|
</div>
|
||||||
<div class="relative">
|
<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]"
|
<div class="flex item-center justify-center px-[6px] py-[4px]"
|
||||||
:class="{ 'bg-slate-200': showType == 'small' }" @click="showType = 'small'">
|
: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]">
|
<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 { img } from '@/utils/common'
|
||||||
import { Terminal, api as terminalApi } from 'vue-web-terminal'
|
import { Terminal, api as terminalApi } from 'vue-web-terminal'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
import useUserStore from '@/stores/modules/user'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const activeName = ref('installed')
|
const activeName = ref('installed')
|
||||||
@ -332,6 +329,7 @@ const loading = ref<Boolean>(false)
|
|||||||
const showType = ref('large')
|
const showType = ref('large')
|
||||||
const downloading = ref('')
|
const downloading = ref('')
|
||||||
const installAfterTips = ref<string[]>([])
|
const installAfterTips = ref<string[]>([])
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const downEvent = (param: Record<string, any>) => {
|
const downEvent = (param: Record<string, any>) => {
|
||||||
if (downloading.value) return
|
if (downloading.value) return
|
||||||
@ -475,6 +473,7 @@ const getInstallTask = (first: boolean = true) => {
|
|||||||
if (!first) {
|
if (!first) {
|
||||||
installStep.value = 3
|
installStep.value = 3
|
||||||
localListFn()
|
localListFn()
|
||||||
|
userStore.getAppList()
|
||||||
notificationEl.close()
|
notificationEl.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -498,6 +497,7 @@ const handleInstall = () => {
|
|||||||
installAddon({ addon: currAddon.value }).then(res => {
|
installAddon({ addon: currAddon.value }).then(res => {
|
||||||
installStep.value = 3
|
installStep.value = 3
|
||||||
localListFn()
|
localListFn()
|
||||||
|
userStore.getAppList()
|
||||||
localInstalling.value = false
|
localInstalling.value = false
|
||||||
if (res.data.length) installAfterTips.value = res.data
|
if (res.data.length) installAfterTips.value = res.data
|
||||||
}).catch((res) => {
|
}).catch((res) => {
|
||||||
@ -581,6 +581,7 @@ watch(currAddon, (nval) => {
|
|||||||
const uninstallAddonFn = (key: string) => {
|
const uninstallAddonFn = (key: string) => {
|
||||||
uninstallAddon({ addon: key }).then(res => {
|
uninstallAddon({ addon: key }).then(res => {
|
||||||
localListFn()
|
localListFn()
|
||||||
|
userStore.getAppList()
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { debounce } from '@/utils/common'
|
import { debounce } from '@/utils/common'
|
||||||
import { ref, computed, onMounted, nextTick, } from 'vue'
|
import { ref, computed, onMounted, nextTick, } from 'vue'
|
||||||
|
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -18,11 +19,9 @@ const prop = defineProps({
|
|||||||
let data = ref([])
|
let data = ref([])
|
||||||
data.value.push(prop.data)
|
data.value.push(prop.data)
|
||||||
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'change'])
|
const emit = defineEmits(['update:modelValue', 'change'])
|
||||||
const value = computed({
|
const value = computed({
|
||||||
get() {
|
get() {
|
||||||
|
|
||||||
return prop.modelValue
|
return prop.modelValue
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
@ -30,6 +29,7 @@ const value = computed({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
const treeRef = ref(null)
|
const treeRef = ref(null)
|
||||||
|
|
||||||
//选择控制
|
//选择控制
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
nextTick(()=>{
|
nextTick(()=>{
|
||||||
|
|||||||
@ -71,6 +71,10 @@
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</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-form-item :label="t('sort')">
|
||||||
<el-input-number v-model="formData.sort" :min="0" />
|
<el-input-number v-model="formData.sort" :min="0" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -92,6 +96,7 @@ import type { FormInstance } from 'element-plus'
|
|||||||
import selectMenuItem from './select-menu-item.vue'
|
import selectMenuItem from './select-menu-item.vue'
|
||||||
import { addMenu, editMenu, getMenuInfo, getSystemMenu,getAddonMenu } from '@/app/api/sys'
|
import { addMenu, editMenu, getMenuInfo, getSystemMenu,getAddonMenu } from '@/app/api/sys'
|
||||||
import { getAddonDevelop } from '@/app/api/tools'
|
import { getAddonDevelop } from '@/app/api/tools'
|
||||||
|
|
||||||
const showDialog = ref(false)
|
const showDialog = ref(false)
|
||||||
const method = ref('post')
|
const method = ref('post')
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@ -115,7 +120,8 @@ const initialFormData = {
|
|||||||
is_show: 1,
|
is_show: 1,
|
||||||
menu_key: '',
|
menu_key: '',
|
||||||
app_type: '',
|
app_type: '',
|
||||||
addon: ''
|
addon: '',
|
||||||
|
menu_short_name:''
|
||||||
}
|
}
|
||||||
const formData: Record<string, any> = reactive({ ...initialFormData })
|
const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||||
|
|
||||||
@ -168,23 +174,27 @@ const formRules = computed(() => {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
//获取插件列表
|
//获取插件列表
|
||||||
const getAddonDevelopFn = async () => {
|
const getAddonDevelopFn = async () => {
|
||||||
let { data } = await getAddonDevelop({})
|
let { data } = await getAddonDevelop({})
|
||||||
addonLst.value = [{ title: "系统", key: "" }]
|
addonLst.value = [{ title: "系统", key: "" }]
|
||||||
addonLst.value.push(...data)
|
addonLst.value.push(...data)
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取系统菜单列表
|
//获取系统菜单列表
|
||||||
const getSystemMenuFn = async () => {
|
const getSystemMenuFn = async () => {
|
||||||
let {data} = await getSystemMenu()
|
let {data} = await getSystemMenu()
|
||||||
sysMenuList.value = [{ menu_name: "顶级", menu_key: "" }]
|
sysMenuList.value = [{ menu_name: "顶级", menu_key: "" }]
|
||||||
sysMenuList.value.push(...data)
|
sysMenuList.value.push(...data)
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取系统应用列表
|
//获取系统应用列表
|
||||||
const getAddonMenuFn = async (key:any) => {
|
const getAddonMenuFn = async (key:any) => {
|
||||||
let {data} = await getAddonMenu(key)
|
let {data} = await getAddonMenu(key)
|
||||||
addonMenuList.value = data
|
addonMenuList.value = data
|
||||||
}
|
}
|
||||||
|
|
||||||
//选择应用
|
//选择应用
|
||||||
const addonChange =async(val:any)=>{
|
const addonChange =async(val:any)=>{
|
||||||
formData.parent_key = ''
|
formData.parent_key = ''
|
||||||
@ -193,6 +203,7 @@ const addonChange =async(val:any)=>{
|
|||||||
formData.parent_key = addonMenuList.value[0].menu_key
|
formData.parent_key = addonMenuList.value[0].menu_key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits(['complete'])
|
const emit = defineEmits(['complete'])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -41,8 +41,8 @@
|
|||||||
<el-table-column prop="sort" :label="t('sort')" min-width="100" />
|
<el-table-column prop="sort" :label="t('sort')" min-width="100" />
|
||||||
<el-table-column :label="t('operation')" fixed="right" align="right" width="130">
|
<el-table-column :label="t('operation')" fixed="right" align="right" width="130">
|
||||||
<template #default="{ row }">
|
<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="editEvent(row)" >{{ 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="deleteEvent(row.menu_key)" >{{ t('delete') }}</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -81,8 +81,8 @@
|
|||||||
<el-table-column prop="sort" :label="t('sort')" min-width="100" />
|
<el-table-column prop="sort" :label="t('sort')" min-width="100" />
|
||||||
<el-table-column :label="t('operation')" fixed="right" align="right" width="130">
|
<el-table-column :label="t('operation')" fixed="right" align="right" width="130">
|
||||||
<template #default="{ row }">
|
<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 v-if="row.menu_key.indexOf('1') ==-1" type="primary" link @click="editEvent(row)" >{{ 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="deleteEvent(row.menu_key)" >{{ t('delete') }}</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -102,6 +102,7 @@ import { t } from '@/lang'
|
|||||||
import EditMenu from '@/app/views/auth/components/edit-menu.vue'
|
import EditMenu from '@/app/views/auth/components/edit-menu.vue'
|
||||||
import { getSystem, getAddonList, deleteMenu, getMenus } from '@/app/api/sys'
|
import { getSystem, getAddonList, deleteMenu, getMenus } from '@/app/api/sys'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const pageName = route.meta.title
|
const pageName = route.meta.title
|
||||||
|
|
||||||
@ -112,7 +113,7 @@ const menusTableData = reactive({
|
|||||||
data:[],
|
data:[],
|
||||||
activeName: 'system'
|
activeName: 'system'
|
||||||
})
|
})
|
||||||
console.log(menusTableData.applicationDate)
|
|
||||||
/**
|
/**
|
||||||
* 获取菜单
|
* 获取菜单
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -55,6 +55,7 @@ import { t } from '@/lang'
|
|||||||
import { getRoleList, deleteRole, edstatus } from '@/app/api/sys'
|
import { getRoleList, deleteRole, edstatus } from '@/app/api/sys'
|
||||||
import { ElMessageBox, FormInstance } from 'element-plus'
|
import { ElMessageBox, FormInstance } from 'element-plus'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const pageName = route.meta.title;
|
const pageName = route.meta.title;
|
||||||
@ -106,9 +107,10 @@ const editRoleDialog: Record<string, any> | null = ref(null)
|
|||||||
const addEvent = () => {
|
const addEvent = () => {
|
||||||
router.push({ path: '/setting/auth/role_edit' })
|
router.push({ path: '/setting/auth/role_edit' })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑角色
|
* 编辑角色
|
||||||
* @param data
|
* @param role_id
|
||||||
*/
|
*/
|
||||||
const editEvent = (role_id: any) => {
|
const editEvent = (role_id: any) => {
|
||||||
router.push({
|
router.push({
|
||||||
|
|||||||
@ -61,6 +61,7 @@ import { debounce } from '@/utils/common'
|
|||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import addonRole from '@/app/views/auth/components/addon-role.vue'
|
import addonRole from '@/app/views/auth/components/addon-role.vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const pageName = route.meta.title
|
const pageName = route.meta.title
|
||||||
|
|||||||
@ -55,8 +55,8 @@ import { getMenus, deleteMenu } from '@/app/api/sys'
|
|||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox } from 'element-plus'
|
||||||
import EditMenu from '@/app/views/auth/components/edit-menu.vue'
|
import EditMenu from '@/app/views/auth/components/edit-menu.vue'
|
||||||
|
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const pageName = route.meta.title
|
const pageName = route.meta.title
|
||||||
|
|
||||||
|
|||||||
@ -226,6 +226,7 @@ import { useRouter } from 'vue-router'
|
|||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import {img} from '@/utils/common'
|
import {img} from '@/utils/common'
|
||||||
import { getAliappConfig } from '@/app/api/aliapp'
|
import { getAliappConfig } from '@/app/api/aliapp'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
let activeName = ref("/website/channel/aliapp");
|
let activeName = ref("/website/channel/aliapp");
|
||||||
let active = ref(2);
|
let active = ref(2);
|
||||||
|
|||||||
@ -120,7 +120,6 @@ const formData = reactive<Record<string, string>>({
|
|||||||
|
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取支付宝配置
|
* 获取支付宝配置
|
||||||
*/
|
*/
|
||||||
@ -135,7 +134,6 @@ getAliappStatic().then(res => {
|
|||||||
formData.request_url = res.data.domain
|
formData.request_url = res.data.domain
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 复制
|
* 复制
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -45,7 +45,6 @@ const formData = reactive<Record<string, string | boolean>>({
|
|||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取pc域名
|
* 获取pc域名
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -145,6 +145,7 @@ import { useRouter } from "vue-router";
|
|||||||
import { t } from "@/lang";
|
import { t } from "@/lang";
|
||||||
import {img} from '@/utils/common'
|
import {img} from '@/utils/common'
|
||||||
import { getWeappConfig } from '@/app/api/weapp'
|
import { getWeappConfig } from '@/app/api/weapp'
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
let activeName = ref("/website/channel/weapp");
|
let activeName = ref("/website/channel/weapp");
|
||||||
let active = ref(2);
|
let active = ref(2);
|
||||||
|
|||||||
@ -9,17 +9,10 @@
|
|||||||
<el-tab-pane :label="t('weappRelease')" name="/website/channel/weapp/code" />
|
<el-tab-pane :label="t('weappRelease')" name="/website/channel/weapp/code" />
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
<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]">
|
<div class="mt-[50px]">
|
||||||
<el-button type="primary" @click="insert" :loading="uploading">{{ t('cloudRelease') }}</el-button>
|
<el-button type="primary" @click="insert" :loading="uploading" :disabled="weappTableData.loading">{{
|
||||||
<el-button @click="localInsert">{{ t('localRelease') }}</el-button>
|
t('cloudRelease') }}</el-button>
|
||||||
|
<el-button @click="localInsert" :disabled="weappTableData.loading">{{ t('localRelease') }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table class="mt-[15px]" :data="weappTableData.data" v-loading="weappTableData.loading" size="default">
|
<el-table class="mt-[15px]" :data="weappTableData.data" v-loading="weappTableData.loading" size="default">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
@ -36,10 +29,9 @@
|
|||||||
<el-table-column prop="create_time" :label="t('createTime')" align="center" />
|
<el-table-column prop="create_time" :label="t('createTime')" align="center" />
|
||||||
<el-table-column :label="t('operation')" fixed="right" align="right" min-width="120">
|
<el-table-column :label="t('operation')" fixed="right" align="right" min-width="120">
|
||||||
<template #default="{ row, $index }">
|
<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-tooltip :content="previewContent" raw-content effect="light">
|
||||||
<el-button type="primary" link
|
<el-button type="primary" link>
|
||||||
v-if="previewContent && $index == 0 && weappTableData.page == 1">
|
|
||||||
{{ t('preview') }}</el-button>
|
{{ t('preview') }}</el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
@ -74,13 +66,6 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -147,7 +132,7 @@ const getWeappVersionListFn = (page: number = 1) => {
|
|||||||
weappTableData.loading = false
|
weappTableData.loading = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// loadWeappTemplateList()
|
|
||||||
getWeappVersionListFn()
|
getWeappVersionListFn()
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
@ -168,8 +153,11 @@ const insert = () => {
|
|||||||
if (uploading.value) return
|
if (uploading.value) return
|
||||||
uploading.value = true
|
uploading.value = true
|
||||||
|
|
||||||
|
previewContent.value = ''
|
||||||
|
|
||||||
setWeappVersion(form.value).then(res => {
|
setWeappVersion(form.value).then(res => {
|
||||||
getWeappVersionListFn()
|
getWeappVersionListFn()
|
||||||
|
getWeappPreviewImage()
|
||||||
uploading.value = false
|
uploading.value = false
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
uploading.value = false
|
uploading.value = false
|
||||||
|
|||||||
@ -64,6 +64,7 @@ import { getTemplateList, getBatchAcquisition } from '@/app/api/weapp'
|
|||||||
import { editNoticeStatus } from '@/app/api/notice'
|
import { editNoticeStatus } from '@/app/api/notice'
|
||||||
import { ElLoading } from 'element-plus'
|
import { ElLoading } from 'element-plus'
|
||||||
import { useRoute,useRouter } from 'vue-router'
|
import { useRoute,useRouter } from 'vue-router'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const pageName = route.meta.title
|
const pageName = route.meta.title
|
||||||
|
|||||||
@ -232,6 +232,7 @@ import { useRouter } from 'vue-router'
|
|||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import {img} from '@/utils/common'
|
import {img} from '@/utils/common'
|
||||||
import { getWechatConfig } from '@/app/api/wechat'
|
import { getWechatConfig } from '@/app/api/wechat'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
let activeName = ref("/website/channel/wechat");
|
let activeName = ref("/website/channel/wechat");
|
||||||
let active = ref(2);
|
let active = ref(2);
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<h3 class="mb-[10px]">{{ t('addonListSet') }}</h3>
|
<h3 class="mb-[10px]">{{ t('addonListSet') }}</h3>
|
||||||
<el-form label-width="100px" class="px-[10px]">
|
<el-form label-width="100px" class="px-[10px]">
|
||||||
<div ref="addonBoxRef">
|
<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]">
|
<div v-show="item.title" class="flex items-center pb-[10px]">
|
||||||
<img class="w-[60px] h-[60px] rounded-md" :src="img(item.icon)" />
|
<img class="w-[60px] h-[60px] rounded-md" :src="img(item.icon)" />
|
||||||
<div class="flex flex-col justify-center ml-[10px] leading-[1]">
|
<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>
|
<p class="text-sm text-gray-400 mb-[10px]">{{ t('graphicNavTips') }}</p>
|
||||||
|
|
||||||
<div ref="imageBoxRef">
|
<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'">
|
<el-form-item :label="t('image')" v-show="diyStore.editComponent.mode === 'graphic' || diyStore.editComponent.mode === 'img'">
|
||||||
<upload-image v-model="item.imageUrl" :limit="1"/>
|
<upload-image v-model="item.imageUrl" :limit="1"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<div ref="imageBoxRef">
|
<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')">
|
<el-form-item :label="t('image')">
|
||||||
<upload-image v-model="item.imageUrl" :limit="1" @change="selectImg" />
|
<upload-image v-model="item.imageUrl" :limit="1" @change="selectImg" />
|
||||||
</el-form-item>
|
</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-tabs v-model="activeName" class="demo-tabs mt-[15px]">
|
||||||
<el-tab-pane :label="t('navImage')" name="navPicture">
|
<el-tab-pane :label="t('navImage')" name="navPicture">
|
||||||
<div ref="navItemRef">
|
<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')">
|
<el-form-item :label="t('navIconOne')">
|
||||||
<div class="flex align-center">
|
<div class="flex align-center">
|
||||||
<div class="flex flex-col justify-center items-center">
|
<div class="flex flex-col justify-center items-center">
|
||||||
|
|||||||
@ -49,9 +49,6 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -65,7 +62,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive } from "vue";
|
import { ref, reactive } from "vue";
|
||||||
import { getApply } from "@/app/api/apply";
|
import { getApply } from "@/app/api/apply";
|
||||||
import { setStarAddon } from "@/app/api/auth";
|
|
||||||
import { img } from "@/utils/common";
|
import { img } from "@/utils/common";
|
||||||
import { findFirstValidRoute } from "@/router/routers";
|
import { findFirstValidRoute } from "@/router/routers";
|
||||||
import useUserStore from "@/stores/modules/user";
|
import useUserStore from "@/stores/modules/user";
|
||||||
@ -108,12 +104,6 @@ const toLink = (addon: string) => {
|
|||||||
userStore.setAppMenuList(data);
|
userStore.setAppMenuList(data);
|
||||||
router.push({ name: appLink.value[addon] });
|
router.push({ name: appLink.value[addon] });
|
||||||
};
|
};
|
||||||
|
|
||||||
const withEvent = (key: string) => {
|
|
||||||
setStarAddon({ key: key }).then(() => {
|
|
||||||
getApplelist();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -47,9 +47,6 @@
|
|||||||
<p class="app-text text-[14px] text-[#999] w-[200px]">{{ item.desc }}</p>
|
<p class="app-text text-[14px] text-[#999] w-[200px]">{{ item.desc }}</p>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
@ -63,7 +60,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive } from 'vue'
|
||||||
import { getApply } from '@/app/api/apply'
|
import { getApply } from '@/app/api/apply'
|
||||||
import { setStarAddon } from '@/app/api/auth'
|
|
||||||
import { img } from '@/utils/common'
|
import { img } from '@/utils/common'
|
||||||
import { findFirstValidRoute } from '@/router/routers'
|
import { findFirstValidRoute } from '@/router/routers'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
@ -102,12 +98,6 @@ getAppLink()
|
|||||||
const toLink = (addon: string) => {
|
const toLink = (addon: string) => {
|
||||||
router.push({ name: appLink.value[addon] })
|
router.push({ name: appLink.value[addon] })
|
||||||
}
|
}
|
||||||
|
|
||||||
const withEvent = (key: string) => {
|
|
||||||
setStarAddon({key: key}).then(() => {
|
|
||||||
getApplelist()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -29,14 +29,11 @@
|
|||||||
<p class="app-text w-[190px] text-[17px] text-[#222] pl-3">{{ item.title }}</p>
|
<p class="app-text w-[190px] text-[17px] text-[#222] pl-3">{{ item.title }}</p>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
<div class="empty flex items-center justify-center" v-if="!loading&&!applyList.list.length" >
|
<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>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
@ -46,24 +43,25 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive } from 'vue'
|
||||||
import { getApply } from '@/app/api/apply'
|
import { getApply } from '@/app/api/apply'
|
||||||
import { setStarAddon } from '@/app/api/auth'
|
|
||||||
import { img } from '@/utils/common'
|
import { img } from '@/utils/common'
|
||||||
import { findFirstValidRoute } from '@/router/routers'
|
import { findFirstValidRoute } from '@/router/routers'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import storage from '@/utils/storage'
|
import storage from '@/utils/storage'
|
||||||
|
var key = storage.get('menuAppStorage')
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const applyList = reactive({
|
const applyList = reactive({
|
||||||
list: [],
|
list: [],
|
||||||
search: {
|
search: {
|
||||||
title: ""
|
title: "",
|
||||||
|
key: key
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
let loading = ref(true)
|
let loading = ref(true)
|
||||||
const getApplelist = async () => {
|
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=>{
|
applyList.list = res.data.filter(el=>{
|
||||||
return appLink.value[el.key] &&el.type == 'addon'
|
return appLink.value[el.key] &&el.type == 'addon'
|
||||||
})
|
})
|
||||||
@ -97,12 +95,6 @@ const toLink = (addon: string) => {
|
|||||||
userStore.setAppMenuList(data)
|
userStore.setAppMenuList(data)
|
||||||
router.push({ name: appLink.value[addon] })
|
router.push({ name: appLink.value[addon] })
|
||||||
}
|
}
|
||||||
|
|
||||||
const withEvent = (key: string) => {
|
|
||||||
setStarAddon({key: key}).then(() => {
|
|
||||||
getApplelist()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -25,7 +25,14 @@
|
|||||||
<div class="font-500 text-[13px] text-[#6D7278] mt-[14px]">{{ item.desc }}</div>
|
<div class="font-500 text-[13px] text-[#6D7278] mt-[14px]">{{ item.desc }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</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>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -69,12 +76,15 @@ const itemPath = (key: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
const goRouter = ()=>{
|
||||||
|
window.open('https://www.niucloud.com/product/')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.main-container{
|
.main-container{
|
||||||
background: linear-gradient(180deg, rgba(253,253,253,0.24) 0%, #FAFAFA 100%);
|
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 {
|
.overview-top {
|
||||||
background-image: url('@/app/assets/images/index/overview.png');
|
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);
|
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.18);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<style>
|
||||||
|
.overview-empty .el-empty__image{
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -44,7 +44,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap">
|
<div class="flex flex-wrap">
|
||||||
<div class="flex flex-wrap" ref="shortcutModel" v-if="edit_menu">
|
<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)">
|
<div class="flex items-center h-[88px]" @click="editModel(items)">
|
||||||
<!-- <img class="ml-[24px] w-[40px]" :src="img(items.img)"/> -->
|
<!-- <img class="ml-[24px] w-[40px]" :src="img(items.img)"/> -->
|
||||||
<div class="ml-[24px] w-[40px]">
|
<div class="ml-[24px] w-[40px]">
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
<div class="flex justify-between items-center mb-4">
|
<div class="flex justify-between items-center mb-4">
|
||||||
<span class="text-[20px]">素材管理</span>
|
<span class="text-[20px]">素材管理</span>
|
||||||
</div>
|
</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">
|
<el-tab-pane :label="t(tab)" v-for="(tab, index) in attachmentType" :name="tab" :key="index">
|
||||||
<attachment scene="attachment" :type="tab" />
|
<attachment scene="attachment" :type="tab" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.attachment-container {
|
.attachment-container {
|
||||||
.el-card__body {
|
.el-card__body {
|
||||||
height: 100%;
|
height: 96%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-tabs {
|
.el-tabs {
|
||||||
|
|||||||
@ -52,7 +52,7 @@
|
|||||||
<el-table :data="formData.table_column" size="large" ref="tableRef" :key="toggleIndex">
|
<el-table :data="formData.table_column" size="large" ref="tableRef" :key="toggleIndex">
|
||||||
<el-table-column align="center" label="操作" width="80">
|
<el-table-column align="center" label="操作" width="80">
|
||||||
<template #default>
|
<template #default>
|
||||||
<i class="iconfont iconfenlei vues-rank cursor-pointer"></i>
|
<i class="iconfont icontuodong vues-rank cursor-move"></i>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="t('columnName')" prop="column_name" min-width="130px" />
|
<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>
|
<template>
|
||||||
<div class="main-container attachment-container" v-loading="loadingArr.server_load">
|
<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">
|
<el-card class="box-card !border-none" shadow="never" v-if="systemService && !loadingArr.server_load">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<span class="text-[20px]">{{ pageName }}</span>
|
<span class="text-[20px]">{{ pageName }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
<span class="text-sm truncate w-[190px]">{{t('refreshMenu')}}</span>
|
<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>
|
<span class="text-xs text-gray-400 mt-1 truncate w-[190px]" :title="t('refreshMenuDesc')">{{t('refreshMenuDesc')}}</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="plug-item-operate" @click="refreshMenu()">{{t('refresh')}}</span>
|
<span class="plug-item-operate" @click="refreshMenu()">{{t('resetting')}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center bg-[#F7F8FA] p-3 w-[295px] relative plug-item mr-4 mb-4 cursor-pointer">
|
<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>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { t } from '@/lang'
|
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 = () => {
|
const schemaCache = () => {
|
||||||
loading.value = true;
|
loading.value = true
|
||||||
clearSchemaCache({}).then(res => {
|
clearSchemaCache({}).then(res => {
|
||||||
loading.value = false;
|
loading.value = false
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
//需要定时执行的代码
|
// 需要定时执行的代码
|
||||||
location.reload()
|
location.reload()
|
||||||
}, 500)
|
}, 500)
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
loading.value = false;
|
loading.value = false
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 更新菜单
|
// 更新菜单
|
||||||
const refreshMenu = ()=> {
|
const refreshMenu = () => {
|
||||||
loading.value = true;
|
loading.value = true
|
||||||
menuRefresh({}).then(res => {
|
menuRefresh({}).then(res => {
|
||||||
loading.value = false;
|
loading.value = false
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
//需要定时执行的代码
|
// 需要定时执行的代码
|
||||||
location.reload()
|
location.reload()
|
||||||
}, 500)
|
}, 500)
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
loading.value = false;
|
loading.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -10,8 +10,8 @@
|
|||||||
{{ t('selectPlaceholder') }}
|
{{ t('selectPlaceholder') }}
|
||||||
</div>
|
</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="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="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]" v-if="scene == 'attachment' && prop.type !='icon' ">
|
<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'">
|
<el-dropdown :hide-on-click="false" v-if="scene == 'attachment'">
|
||||||
<icon name="element-MoreFilled" class="cursor-pointer ml-[10px]" size="14px"/>
|
<icon name="element-MoreFilled" class="cursor-pointer ml-[10px]" size="14px"/>
|
||||||
|
|||||||
@ -75,6 +75,7 @@
|
|||||||
"layoutSetting": "主题设置",
|
"layoutSetting": "主题设置",
|
||||||
"darkMode": "黑暗模式",
|
"darkMode": "黑暗模式",
|
||||||
"sidebarMode": "主题风格",
|
"sidebarMode": "主题风格",
|
||||||
|
"sidebarStyle": "主题样式",
|
||||||
"themeColor": "主题颜色",
|
"themeColor": "主题颜色",
|
||||||
"detectionLoginOperation": "确定",
|
"detectionLoginOperation": "确定",
|
||||||
"detectionLoginContent": "已检测到有其他账号登录,需要刷新后才能继续操作。",
|
"detectionLoginContent": "已检测到有其他账号登录,需要刷新后才能继续操作。",
|
||||||
@ -125,5 +126,6 @@
|
|||||||
"generateEmail":"请输入正确的邮箱号",
|
"generateEmail":"请输入正确的邮箱号",
|
||||||
"generateMax":"超过最多输入字符数",
|
"generateMax":"超过最多输入字符数",
|
||||||
"generateMin":"少于最少输入字符数",
|
"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-row class="w-100 h-full w-full">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<div class="left-panel h-full flex items-center">
|
<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">
|
<div class="navbar-item flex items-center h-full cursor-pointer" @click="refreshRouter">
|
||||||
<icon name="element-Refresh" />
|
<icon name="element-Refresh" />
|
||||||
@ -176,15 +172,6 @@ const submitIndex = () => {
|
|||||||
router.go(0)
|
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>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -5,6 +5,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<el-drawer v-model="drawer" :title="t('layout.layoutSetting')" size="300px">
|
<el-drawer v-model="drawer" :title="t('layout.layoutSetting')" size="300px">
|
||||||
<el-scrollbar>
|
<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="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="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({
|
const theme = computed({
|
||||||
get() {
|
get() {
|
||||||
return systemStore.theme
|
return systemStore.theme
|
||||||
@ -3,14 +3,24 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<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 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 => {
|
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>
|
</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>
|
<template>
|
||||||
<div :class="['flex', { 'two-type': sidebar == 'twoType' }, { 'three-type': sidebar == 'threeType' }]" v-if="isLoad">
|
<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">
|
<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 v-if="isTwoMenuFn(item)" class="w-[210px] box-border border-r-[1px] border-solid second-menu">
|
||||||
<div
|
<div class="group flex flex-col items-center justify-center h-[64px] border-b-[1px] border-solid second-head cursor-pointer relative" @mouseenter="twofloatMenuHover">
|
||||||
class="group flex flex-col items-center justify-center h-[64px] border-b-[1px] border-solid second-head cursor-pointer relative">
|
|
||||||
<div class="flex items-center">
|
<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="">
|
||||||
<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>
|
||||||
<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" />
|
||||||
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto" size="24px" />
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<span>{{ item.meta.app ? item.meta.parentTitle : item.meta.title }}</span>
|
<span>{{ item.meta.app ? item.meta.parentTitle : item.meta.title }}</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- 浮动样式的应用菜单 -->
|
<app-menu :isShowHover="twofloatMenu" :data="applyList" @child-click="toLink" hoverType='twofloatMenu'></app-menu>
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-scrollbar class="overflow-y-auto menus-wrap">
|
<el-scrollbar class="overflow-y-auto menus-wrap">
|
||||||
<el-menu class="apply-menu !border-0" :router="true" unique-opened="true"
|
<el-menu class="apply-menu !border-0" :router="true" unique-opened="true" :default-active="String(route.name)">
|
||||||
:default-active="String(route.name)">
|
<template v-if="applyTypeList.length">
|
||||||
<template v-if="!floatMenuStyle || floatMenuStyle && applyTypeList.length">
|
|
||||||
<template v-for="(twoMenu, twoIndex) in item.children">
|
<template v-for="(twoMenu, twoIndex) in item.children">
|
||||||
<el-sub-menu :index="String(twoMenu.meta.title)"
|
<el-sub-menu :index="String(twoMenu.meta.title)" v-if="twoMenu.children && twoMenu.meta.show">
|
||||||
v-if="twoMenu.children && twoMenu.meta.show">
|
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
<div class="w-[16px] h-[16px] relative flex items-center">
|
||||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
||||||
@ -94,10 +32,8 @@
|
|||||||
v-if="threeMenu.children && threeMenu.meta.show">
|
v-if="threeMenu.children && threeMenu.meta.show">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
<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" />
|
:name="threeMenu.meta.icon" class="absolute !w-auto" size="18px" />
|
||||||
<span v-if="!floatMenuStyle"
|
|
||||||
class="iconfont icondian !text-[25px]"></span>
|
|
||||||
</div>
|
</div>
|
||||||
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title }}</span>
|
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
@ -164,7 +100,7 @@
|
|||||||
|
|
||||||
<!-- 系统菜单 -->
|
<!-- 系统菜单 -->
|
||||||
<template
|
<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>
|
<div class="!border-0 !border-t-[1px] border-solid mx-[25px] bg-[#f7f7f7] my-[5px]"></div>
|
||||||
<template v-for="(twoMenu, twoIndex) in menus">
|
<template v-for="(twoMenu, twoIndex) in menus">
|
||||||
<el-sub-menu :index="String(twoMenu.meta.title)"
|
<el-sub-menu :index="String(twoMenu.meta.title)"
|
||||||
@ -180,9 +116,8 @@
|
|||||||
<el-sub-menu :index="String(threeMenu.meta.title)"
|
<el-sub-menu :index="String(threeMenu.meta.title)"
|
||||||
v-if="threeMenu.meta.app && threeMenu.children">
|
v-if="threeMenu.meta.app && threeMenu.children">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
<div class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||||
<icon v-if="threeMenu.meta.icon" :name="threeMenu.meta.icon"
|
<span class="iconfont iconyuanquan_huaban1 !text-[20px]"></span>
|
||||||
class="absolute !w-auto" size="18px" />
|
|
||||||
</div>
|
</div>
|
||||||
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title }}</span>
|
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
@ -229,29 +164,25 @@
|
|||||||
</template>
|
</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">
|
<template v-for="(twoMenu, twoIndex) in menus">
|
||||||
<el-sub-menu :index="String(twoMenu.meta.title)"
|
<el-sub-menu :index="String(twoMenu.meta.title)"
|
||||||
v-if="twoMenu.meta.app && twoMenu.meta.app == plugMenuType && twoMenu.children">
|
v-if="twoMenu.meta.app && twoMenu.meta.app == plugMenuType && twoMenu.children">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
<div class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
<span class="iconfont iconyuanquan_huaban1 !text-[20px]"></span>
|
||||||
class="absolute !w-auto" size="18px" />
|
|
||||||
</div>
|
</div>
|
||||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-for="(threeMenu, threeIndex) in twoMenu.children"
|
<template v-for="(threeMenu, threeIndex) in twoMenu.children" :key="threeIndex">
|
||||||
:key="threeIndex">
|
|
||||||
<!-- 三级菜单 -->
|
<!-- 三级菜单 -->
|
||||||
<el-sub-menu :index="String(threeMenu.meta.title)"
|
<el-sub-menu :index="String(threeMenu.meta.title)"
|
||||||
v-if="threeMenu.children && threeMenu.meta.show">
|
v-if="threeMenu.children && threeMenu.meta.show">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div
|
<div class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||||
class="w-[16px] h-[16px] relative flex items-center justify-center">
|
|
||||||
<span class="iconfont icondian !text-[25px]"></span>
|
<span class="iconfont icondian !text-[25px]"></span>
|
||||||
</div>
|
</div>
|
||||||
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title
|
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title }}</span>
|
||||||
}}</span>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-for="(fourMenu, fourIndex) in threeMenu.children"
|
<template v-for="(fourMenu, fourIndex) in threeMenu.children"
|
||||||
:key="fourIndex">
|
:key="fourIndex">
|
||||||
@ -307,85 +238,82 @@
|
|||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<!-- 浮动样式 -->
|
<!-- 浮动样式 -->
|
||||||
<template v-if="floatMenuStyle">
|
<div
|
||||||
<div
|
:class="['!border-0 border-solid mx-[25px] bg-[#f7f7f7] my-[5px]', !applyTypeList.length ? '' : '!border-t-[1px]']">
|
||||||
:class="['!border-0 border-solid mx-[25px] bg-[#f7f7f7] my-[5px]', floatMenuStyle && !applyTypeList.length ? '' : '!border-t-[1px]']">
|
</div>
|
||||||
</div>
|
<template v-for="(twoMenu, twoIndex) in menus">
|
||||||
<template v-for="(twoMenu, twoIndex) in menus">
|
<el-sub-menu :index="String(twoMenu.meta.title)"
|
||||||
<el-sub-menu :index="String(twoMenu.meta.title)"
|
v-if="twoMenu.meta.attr == 'common' && !twoMenu.meta.app && twoMenu.children">
|
||||||
v-if="twoMenu.meta.attr == 'common' && !twoMenu.meta.app && twoMenu.children">
|
<template #title>
|
||||||
<template #title>
|
<div class="w-[16px] h-[16px] relative flex items-center">
|
||||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
||||||
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
class="absolute !w-auto" size="18px" />
|
||||||
class="absolute !w-auto" size="18px" />
|
</div>
|
||||||
</div>
|
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
</template>
|
||||||
</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)"
|
||||||
<el-sub-menu :index="String(threeMenu.meta.title)"
|
v-if="threeMenu.children && threeMenu.meta.show">
|
||||||
v-if="threeMenu.children && threeMenu.meta.show">
|
<template #title>
|
||||||
<template #title>
|
<div class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||||
<div class="w-[16px] h-[16px] relative flex items-center">
|
<span class="iconfont iconyuanquan_huaban1 !text-[20px]"></span>
|
||||||
<icon v-if="threeMenu.meta.icon" :name="threeMenu.meta.icon"
|
</div>
|
||||||
class="absolute !w-auto" size="18px" />
|
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title }}</span>
|
||||||
</div>
|
</template>
|
||||||
<span class="ml-[11px] text-[15px]">{{ threeMenu.meta.title }}</span>
|
<template v-for="(fourMenu, fourIndex) in threeMenu.children" :key="fourIndex">
|
||||||
</template>
|
<el-sub-menu :index="String(fourMenu.meta.title)"
|
||||||
<template v-for="(fourMenu, fourIndex) in threeMenu.children" :key="fourIndex">
|
v-if="fourMenu.children && fourMenu.meta.show">
|
||||||
<el-sub-menu :index="String(fourMenu.meta.title)"
|
<template #title>
|
||||||
v-if="fourMenu.children && fourMenu.meta.show">
|
<div
|
||||||
<template #title>
|
class="w-[16px] h-[16px] relative flex items-center justify-center">
|
||||||
<div
|
<span class="iconfont icondian !text-[25px]"></span>
|
||||||
class="w-[16px] h-[16px] relative flex items-center justify-center">
|
</div>
|
||||||
<span class="iconfont icondian !text-[25px]"></span>
|
<span class="ml-[11px] text-[15px]">{{ fourMenu.meta.title }}</span>
|
||||||
</div>
|
</template>
|
||||||
<span class="ml-[11px] text-[15px]">{{ fourMenu.meta.title }}</span>
|
<template v-for="(fiveMenu, fiveIndex) in threeMenu.children"
|
||||||
</template>
|
:key="fiveIndex">
|
||||||
<template v-for="(fiveMenu, fiveIndex) in threeMenu.children"
|
<el-menu-item v-if="fiveMenu.meta.show" class="!h-[52px] !pl-[55px]"
|
||||||
:key="fiveIndex">
|
:index="String(fiveMenu.name)" @click="toLink(fiveMenu)">
|
||||||
<el-menu-item v-if="fiveMenu.meta.show" class="!h-[52px] !pl-[55px]"
|
<template #title>
|
||||||
:index="String(fiveMenu.name)" @click="toLink(fiveMenu)">
|
<span class="text-[14px]">{{ fiveMenu.meta.title }}</span>
|
||||||
<template #title>
|
</template>
|
||||||
<span class="text-[14px]">{{ fiveMenu.meta.title }}</span>
|
</el-menu-item>
|
||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-sub-menu>
|
||||||
</template>
|
<el-menu-item v-else-if="fourMenu.meta.show" class="!h-[52px] !pl-[55px]"
|
||||||
</el-sub-menu>
|
:index="String(fourMenu.name)" @click="toLink(fourMenu)">
|
||||||
<el-menu-item v-else-if="fourMenu.meta.show" class="!h-[52px] !pl-[55px]"
|
<template #title>
|
||||||
:index="String(fourMenu.name)" @click="toLink(fourMenu)">
|
<span class="text-[14px]">{{ fourMenu.meta.title }}</span>
|
||||||
<template #title>
|
</template>
|
||||||
<span class="text-[14px]">{{ fourMenu.meta.title }}</span>
|
</el-menu-item>
|
||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-sub-menu>
|
||||||
</template>
|
|
||||||
</el-sub-menu>
|
|
||||||
|
|
||||||
<el-menu-item
|
<el-menu-item
|
||||||
v-else-if="threeMenu.meta.show && threeMenu.meta.key != 'official_market'"
|
v-else-if="threeMenu.meta.show && threeMenu.meta.key != 'official_market'"
|
||||||
class="!h-[52px] !pl-[52px]" :index="String(threeMenu.name)"
|
class="!h-[52px] !pl-[52px]" :index="String(threeMenu.name)"
|
||||||
@click="toLink(threeMenu)">
|
@click="toLink(threeMenu)">
|
||||||
<template #title>
|
<template #title>
|
||||||
<span class="text-[14px]">{{ threeMenu.meta.title }}</span>
|
<span class="text-[14px]">{{ threeMenu.meta.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<div class="flex items-center !px-[52px] h-[56px] cursor-pointer text-[#333] 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'"
|
v-else-if="threeMenu.meta.show && threeMenu.meta.key == 'official_market'"
|
||||||
@click="toLink(threeMenu)">
|
@click="toLink(threeMenu)">
|
||||||
<span class="text-[15px]">{{ twoMenu.meta.title }}</span>
|
<span class="text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
<el-menu-item v-else-if="twoMenu.meta.attr == 'common'" class="!pl-[35px] text-[#333]"
|
<el-menu-item v-else-if="twoMenu.meta.attr == 'common'" class="!pl-[35px] text-[#333]"
|
||||||
:index="String(twoMenu.name)" @click="toLink(twoMenu)">
|
:index="String(twoMenu.name)" @click="toLink(twoMenu)">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div v-if="twoMenu.meta.icon" class="w-[16px] h-[16px] relative flex items-center">
|
<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"
|
<icon v-if="twoMenu.meta.icon" :name="twoMenu.meta.icon"
|
||||||
class="absolute !w-auto" size="18px" />
|
class="absolute !w-auto" size="18px" />
|
||||||
</div>
|
</div>
|
||||||
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
<span class="ml-[11px] text-[15px]">{{ twoMenu.meta.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
@ -398,6 +326,7 @@
|
|||||||
import { ref, watch, computed } from 'vue'
|
import { ref, watch, computed } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import side from './side.vue'
|
import side from './side.vue'
|
||||||
|
import appMenu from './components/app-menu.vue'
|
||||||
import { img } from '@/utils/common'
|
import { img } from '@/utils/common'
|
||||||
import useSystemStore from '@/stores/modules/system'
|
import useSystemStore from '@/stores/modules/system'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
@ -407,6 +336,7 @@ import { findFirstValidRoute } from '@/router/routers'
|
|||||||
import { getAddonByKey } from '@/app/api/addon'
|
import { getAddonByKey } from '@/app/api/addon'
|
||||||
import { getApply } from '@/app/api/apply'
|
import { getApply } from '@/app/api/apply'
|
||||||
|
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const systemStore = useSystemStore()
|
const systemStore = useSystemStore()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@ -432,12 +362,6 @@ const getApplelist = async () => {
|
|||||||
isLoad.value = true;
|
isLoad.value = true;
|
||||||
}
|
}
|
||||||
getApplelist()
|
getApplelist()
|
||||||
|
|
||||||
const floatActive = ref(false)
|
|
||||||
const homeClick = () => {
|
|
||||||
const key = storage.get('menuAppStorage')
|
|
||||||
key ? router.push({ name: appLink.value[key] }) : router.push({ path: '/' })
|
|
||||||
}
|
|
||||||
// 应用跳转 end
|
// 应用跳转 end
|
||||||
|
|
||||||
// 菜单
|
// 菜单
|
||||||
@ -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
|
return menus
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -472,6 +407,12 @@ const dark = computed(() => {
|
|||||||
return systemStore.dark
|
return systemStore.dark
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 用于插件的卸载或安装
|
||||||
|
watch(() =>userStore.globalAppKey, (val,old) => {
|
||||||
|
getApplelist();
|
||||||
|
},{deep: true})
|
||||||
|
|
||||||
|
|
||||||
// 监听路由
|
// 监听路由
|
||||||
let currMetaAppType = ''
|
let currMetaAppType = ''
|
||||||
const plugMenuType = ref('') // 插件类型
|
const plugMenuType = ref('') // 插件类型
|
||||||
@ -481,14 +422,22 @@ watch(route, () => {
|
|||||||
|
|
||||||
const data = route.matched[1]
|
const data = route.matched[1]
|
||||||
currentRoute.value = route.matched[1]
|
currentRoute.value = route.matched[1]
|
||||||
localMenuKey.value = data.meta.key
|
localMenuKey.value = data.meta.key || 'overview'
|
||||||
|
|
||||||
systemStore.$patch(state => {
|
systemStore.$patch(state => {
|
||||||
state.menuDrawer = false
|
state.menuDrawer = false
|
||||||
})
|
})
|
||||||
}, { immediate: true })
|
}, { 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') {
|
if (!data.meta && data.type == 'app' || data.meta.key != 'official_market') {
|
||||||
let name = data.name;
|
let name = data.name;
|
||||||
if(data.type == 'app'){
|
if(data.type == 'app'){
|
||||||
@ -501,7 +450,6 @@ const toLink = (data) => {
|
|||||||
const appMenuList = userStore.appMenuList
|
const appMenuList = userStore.appMenuList
|
||||||
appMenuList.push(data.key)
|
appMenuList.push(data.key)
|
||||||
userStore.setAppMenuList(appMenuList)
|
userStore.setAppMenuList(appMenuList)
|
||||||
floatActive.value = false
|
|
||||||
|
|
||||||
name = appLink.value[data.key];
|
name = appLink.value[data.key];
|
||||||
}
|
}
|
||||||
@ -516,31 +464,18 @@ const sidebar = computed(() => {
|
|||||||
return systemStore.sidebar
|
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) => {
|
const isTwoMenuFn = (item) => {
|
||||||
let bool = (otherTypeList.value.includes(localMenuKey.value) && globalAppKey.value == item.meta.app)
|
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)
|
|| (!applyTypeList.value.includes(localMenuKey.value) && !otherTypeList.value.includes(localMenuKey.value) && globalAppKey.value && globalAppKey.value == item.meta.app)
|
||||||
|| (floatMenuStyle.value && applyTypeList.value.includes(localMenuKey.value) && (item.meta.key == localMenuKey.value || item.meta.app == localMenuKey.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))
|
|| (!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))
|
|
||||||
|
|
||||||
return bool;
|
return bool;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.layout-aside {
|
.layout-aside {
|
||||||
// border-right: 1px solid var(--el-border-color-lighter);
|
|
||||||
|
|
||||||
&.bright {
|
&.bright {
|
||||||
background-color: #F5F7F9;
|
background-color: #F5F7F9;
|
||||||
|
|
||||||
@ -732,17 +667,3 @@ const isTwoMenuFn = (item) => {
|
|||||||
height: calc(100vh - 64px);
|
height: calc(100vh - 64px);
|
||||||
}
|
}
|
||||||
</style>
|
</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 {
|
} else {
|
||||||
ROOT_ROUTER.redirect = { name: firstRoute }
|
ROOT_ROUTER.redirect = { name: firstRoute }
|
||||||
}
|
}
|
||||||
console.log(currApp, ROOT_ROUTER.redirect)
|
// console.log(currApp, ROOT_ROUTER.redirect)
|
||||||
router.addRoute(ROOT_ROUTER)
|
router.addRoute(ROOT_ROUTER)
|
||||||
|
|
||||||
// 添加动态路由
|
// 添加动态路由
|
||||||
|
|||||||
@ -67,6 +67,7 @@ const addonModules = import.meta.glob('@/**/views/**/*.vue')
|
|||||||
|
|
||||||
interface Route {
|
interface Route {
|
||||||
menu_name: string,
|
menu_name: string,
|
||||||
|
menu_short_name: string,
|
||||||
router_path: string,
|
router_path: string,
|
||||||
view_path: string
|
view_path: string
|
||||||
menu_type: number,
|
menu_type: number,
|
||||||
@ -93,6 +94,7 @@ const createRoute = function (route: Route, parentRoute: RouteRecordRaw | null =
|
|||||||
name: route.menu_key,
|
name: route.menu_key,
|
||||||
meta: {
|
meta: {
|
||||||
title: route.menu_name,
|
title: route.menu_name,
|
||||||
|
shortTitle: route.menu_short_name,
|
||||||
icon: route.icon,
|
icon: route.icon,
|
||||||
type: route.menu_type,
|
type: route.menu_type,
|
||||||
show: route.is_show,
|
show: route.is_show,
|
||||||
|
|||||||
@ -8,7 +8,8 @@ interface System {
|
|||||||
dark: boolean,
|
dark: boolean,
|
||||||
theme: string,
|
theme: string,
|
||||||
lang: string,
|
lang: string,
|
||||||
sidebar: string
|
sidebar: string,
|
||||||
|
sidebarStyle: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const theme = storage.get('theme') ?? {}
|
const theme = storage.get('theme') ?? {}
|
||||||
@ -21,6 +22,7 @@ const useSystemStore = defineStore('system', {
|
|||||||
dark: theme.dark ?? false,
|
dark: theme.dark ?? false,
|
||||||
theme: theme.theme ?? '#273de3',
|
theme: theme.theme ?? '#273de3',
|
||||||
sidebar: theme.sidebar ?? 'oneType',
|
sidebar: theme.sidebar ?? 'oneType',
|
||||||
|
sidebarStyle: theme.sidebarStyle ?? 'oneType',
|
||||||
lang: storage.get('lang') ?? 'zh-cn'
|
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 { login, getAuthMenus } from '@/app/api/auth'
|
||||||
import storage from '@/utils/storage'
|
import storage from '@/utils/storage'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
|
import { getApply } from '@/app/api/apply'
|
||||||
import { formatRouters, findFirstValidRoute } from '@/router/routers'
|
import { formatRouters, findFirstValidRoute } from '@/router/routers'
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
@ -11,10 +12,11 @@ interface User {
|
|||||||
routers: any[],
|
routers: any[],
|
||||||
addonIndexRoute: Record<string, symbol>,
|
addonIndexRoute: Record<string, symbol>,
|
||||||
rules: any[],
|
rules: any[],
|
||||||
appMenuList: any[]
|
appMenuList: any[],
|
||||||
|
globalAppKey: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const useSystemStore = defineStore('user', {
|
const useUserStore = defineStore('user', {
|
||||||
state: (): User => {
|
state: (): User => {
|
||||||
return {
|
return {
|
||||||
token: getToken() || '',
|
token: getToken() || '',
|
||||||
@ -22,6 +24,7 @@ const useSystemStore = defineStore('user', {
|
|||||||
routers: [],
|
routers: [],
|
||||||
addonIndexRoute: {},
|
addonIndexRoute: {},
|
||||||
rules: [],
|
rules: [],
|
||||||
|
globalAppKey: '',
|
||||||
appMenuList: storage.get('appMenuList' + (storage.get('userinfo') ? storage.get('userinfo').username : '')) || []
|
appMenuList: storage.get('appMenuList' + (storage.get('userinfo') ? storage.get('userinfo').username : '')) || []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -74,8 +77,33 @@ const useSystemStore = defineStore('user', {
|
|||||||
setAppMenuList(data: any) {
|
setAppMenuList(data: any) {
|
||||||
this.appMenuList = data
|
this.appMenuList = data
|
||||||
storage.set({ key: 'appMenuList' + (this.userInfo.username ? this.userInfo.username : ''), 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){
|
.el-button:not(.is-round){
|
||||||
border-radius: 2px !important;
|
border-radius: 2px !important;
|
||||||
}
|
}
|
||||||
|
// 修改表格中上传图片样式冲突的问题
|
||||||
|
.el-table .el-table__cell{
|
||||||
|
position: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
// /* 多行超出隐藏 */
|
// /* 多行超出隐藏 */
|
||||||
.multi-hidden {
|
.multi-hidden {
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 3883393 */
|
font-family: "iconfont"; /* Project id 3883393 */
|
||||||
src: url('//at.alicdn.com/t/c/font_3883393_bq3in2lb5mh.woff2?t=1695086543767') format('woff2'),
|
src: url('//at.alicdn.com/t/c/font_3883393_yevzijodb3.woff2?t=1695808853045') format('woff2'),
|
||||||
url('//at.alicdn.com/t/c/font_3883393_bq3in2lb5mh.woff?t=1695086543767') format('woff'),
|
url('//at.alicdn.com/t/c/font_3883393_yevzijodb3.woff?t=1695808853045') format('woff'),
|
||||||
url('//at.alicdn.com/t/c/font_3883393_bq3in2lb5mh.ttf?t=1695086543767') format('truetype');
|
url('//at.alicdn.com/t/c/font_3883393_yevzijodb3.ttf?t=1695808853045') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -13,6 +13,50 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-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 {
|
.iconicon_huojian:before {
|
||||||
content: "\e677";
|
content: "\e677";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,76 @@
|
|||||||
"css_prefix_text": "icon",
|
"css_prefix_text": "icon",
|
||||||
"description": "系统图标",
|
"description": "系统图标",
|
||||||
"glyphs": [
|
"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",
|
"icon_id": "37134174",
|
||||||
"name": "切换",
|
"name": "切换",
|
||||||
|
|||||||
@ -162,3 +162,38 @@ export function urlToRouteRaw(url: string) {
|
|||||||
|
|
||||||
return { path, query }
|
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'
|
import storage from '@/utils/storage'
|
||||||
|
|
||||||
interface RequestConfig extends AxiosRequestConfig {
|
interface RequestConfig extends AxiosRequestConfig {
|
||||||
showSuccessMessage?: boolean
|
showSuccessMessage?: boolean,
|
||||||
|
showErrorMessage?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InternalRequestConfig extends InternalAxiosRequestConfig {
|
interface InternalRequestConfig extends InternalAxiosRequestConfig {
|
||||||
showSuccessMessage?: boolean
|
showSuccessMessage?: boolean,
|
||||||
|
showErrorMessage?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface requestResponse extends AxiosResponse {
|
interface requestResponse extends AxiosResponse {
|
||||||
@ -48,18 +50,18 @@ class Request {
|
|||||||
// 全局响应拦截器
|
// 全局响应拦截器
|
||||||
this.instance.interceptors.response.use(
|
this.instance.interceptors.response.use(
|
||||||
(response: requestResponse) => {
|
(response: requestResponse) => {
|
||||||
if (response.request.responseType != 'blob') {
|
if (response.request.responseType != 'blob') {
|
||||||
const res = response.data
|
const res = response.data
|
||||||
if (res.code != 1) {
|
if (res.code != 1) {
|
||||||
this.handleAuthError(res.code)
|
this.handleAuthError(res.code)
|
||||||
if (res.code != 401) ElMessage({ message: res.msg, type: 'error' })
|
if (res.code != 401 && response.config.showErrorMessage !== false) ElMessage({ message: res.msg, type: 'error' })
|
||||||
return Promise.reject(new Error(res.msg || 'Error'))
|
return Promise.reject(new Error(res.msg || 'Error'))
|
||||||
} else {
|
} else {
|
||||||
if (response.config.showSuccessMessage) ElMessage({ message: res.msg, type: 'success' })
|
if (response.config.showSuccessMessage) ElMessage({ message: res.msg, type: 'success' })
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return response.data
|
return response.data
|
||||||
},
|
},
|
||||||
(err: any) => {
|
(err: any) => {
|
||||||
this.handleNetworkError(err)
|
this.handleNetworkError(err)
|
||||||
|
|||||||
@ -227,6 +227,12 @@ const test = {
|
|||||||
*/
|
*/
|
||||||
regExp(o) {
|
regExp(o) {
|
||||||
return o && Object.prototype.toString.call(o) === '[object RegExp]'
|
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