mirror of
https://github.com/TangSengDaoDao/TangSengDaoDaoManager
synced 2025-06-02 07:12:58 +00:00
commit
42094a1e16
@ -13,6 +13,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.1.0",
|
||||
"@fancyapps/ui": "^5.0.22",
|
||||
"@icon-park/vue-next": "^1.4.2",
|
||||
"@lottiefiles/lottie-player": "^2.0.2",
|
||||
"@vueuse/core": "^10.1.2",
|
||||
|
26
pnpm-lock.yaml
generated
26
pnpm-lock.yaml
generated
@ -8,6 +8,9 @@ dependencies:
|
||||
'@element-plus/icons-vue':
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0(vue@3.3.4)
|
||||
'@fancyapps/ui':
|
||||
specifier: ^5.0.22
|
||||
version: 5.0.22
|
||||
'@icon-park/vue-next':
|
||||
specifier: ^1.4.2
|
||||
version: 1.4.2(vue@3.3.4)
|
||||
@ -1033,6 +1036,10 @@ packages:
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dev: true
|
||||
|
||||
/@fancyapps/ui@5.0.22:
|
||||
resolution: {integrity: sha512-44A5/Hm59mn53FqZRyM4HO/R7UWE79UxgNyHmaudSe+HuU5Kl1g6lxR4Ol1QFaqNS97Pbdytlu4SxYsOX1BTxw==}
|
||||
dev: false
|
||||
|
||||
/@floating-ui/core@1.3.1:
|
||||
resolution: {integrity: sha512-Bu+AMaXNjrpjh41znzHqaz3r2Nr8hHuHZT6V2LBKMhyMl0FgKA62PNYbqnfgmzOhoWZj70Zecisbo4H1rotP5g==}
|
||||
dev: false
|
||||
@ -3988,7 +3995,7 @@ packages:
|
||||
lodash-es: 4.17.21
|
||||
vanilla-jsoneditor: 0.17.8
|
||||
vue: 3.3.4
|
||||
vue-demi: 0.14.5(vue@3.3.4)
|
||||
vue-demi: 0.14.6(vue@3.3.4)
|
||||
vue-global-config: 0.4.0(vue@3.3.4)
|
||||
dev: true
|
||||
|
||||
@ -5750,6 +5757,21 @@ packages:
|
||||
dependencies:
|
||||
vue: 3.3.4
|
||||
|
||||
/vue-demi@0.14.6(vue@3.3.4):
|
||||
resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
peerDependencies:
|
||||
'@vue/composition-api': ^1.0.0-rc.1
|
||||
vue: ^3.0.0-0 || ^2.6.0
|
||||
peerDependenciesMeta:
|
||||
'@vue/composition-api':
|
||||
optional: true
|
||||
dependencies:
|
||||
vue: 3.3.4
|
||||
dev: true
|
||||
|
||||
/vue-eslint-parser@9.3.1(eslint@8.40.0):
|
||||
resolution: {integrity: sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==}
|
||||
engines: {node: ^14.17.0 || >=16.0.0}
|
||||
@ -5772,7 +5794,7 @@ packages:
|
||||
resolution: {integrity: sha512-283vpYOhVHJCpMkjNVEwZdgaAb+Y93zFaXGAWTI378MLoNuwQydjD/BAy1e81QYEmyA+JbxqcmMZVWcM9rbriw==}
|
||||
dependencies:
|
||||
eslint-config-vue-global-api: 0.4.1
|
||||
vue-demi: 0.14.5(vue@3.3.4)
|
||||
vue-demi: 0.14.6(vue@3.3.4)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
|
36
src/api/command.ts
Normal file
36
src/api/command.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import request from '@/utils/axios';
|
||||
|
||||
// 获取口令列表
|
||||
export function commandGet(params?: any) {
|
||||
return request({
|
||||
url: '/manager/web3/laboratory',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
// 新增口令
|
||||
export function commandPost(data: any) {
|
||||
return request({
|
||||
url: '/manager/web3/laboratory',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
// 编辑口令
|
||||
export function commandPut(data: any, id: string) {
|
||||
return request({
|
||||
url: `/manager/web3/laboratory/${id}`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
// 删除口令
|
||||
export function commandDelete(id: string) {
|
||||
return request({
|
||||
url: `/manager/web3/laboratory/${id}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
36
src/api/workplace/app.ts
Normal file
36
src/api/workplace/app.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import request from '@/utils/axios';
|
||||
|
||||
// 获取应用
|
||||
export function appGet(params?: any) {
|
||||
return request({
|
||||
url: '/manager/workplace/app',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
// 新增应用
|
||||
export function appPost(data: any) {
|
||||
return request({
|
||||
url: '/manager/workplace/app',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
// 编辑应用
|
||||
export function appPut(data: any, app_id: string) {
|
||||
return request({
|
||||
url: `/manager/workplace/apps/${app_id}`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
// 删除应用
|
||||
export function appDelete(app_id: string) {
|
||||
return request({
|
||||
url: `/manager/workplace/apps/${app_id}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
45
src/api/workplace/banner.ts
Normal file
45
src/api/workplace/banner.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import request from '@/utils/axios';
|
||||
|
||||
// 获取轮播
|
||||
export function bannerGet(params?: any) {
|
||||
return request({
|
||||
url: '/manager/workplace/banner',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
// 新增轮播
|
||||
export function bannerPost(data: any) {
|
||||
return request({
|
||||
url: '/manager/workplace/banner',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
// 编辑轮播
|
||||
export function bannerPut(data: any, banner_no: string) {
|
||||
return request({
|
||||
url: `/manager/workplace/banners/${banner_no}`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
// 删除轮播
|
||||
export function bannerDelete(banner_no: string) {
|
||||
return request({
|
||||
url: `/manager/workplace/banners/${banner_no}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// 轮播排序
|
||||
export function bannerReorderPut(data: any) {
|
||||
return request({
|
||||
url: `/manager/workplace/banner/reorder`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
79
src/api/workplace/category.ts
Normal file
79
src/api/workplace/category.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import request from '@/utils/axios';
|
||||
|
||||
// 获取分类
|
||||
export function categoryGet(params?: any) {
|
||||
return request({
|
||||
url: '/manager/workplace/category',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
// 新增分类
|
||||
export function categoryPost(data: any) {
|
||||
return request({
|
||||
url: '/manager/workplace/category',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
// 分类编辑
|
||||
export function categoryPut(data: any, category_no: string) {
|
||||
return request({
|
||||
url: `/manager/workplace/categorys/${category_no}`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
// 删除分类
|
||||
export function categoryDelete(category_no: string) {
|
||||
return request({
|
||||
url: `/manager/workplace/categorys/${category_no}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// 分类排序
|
||||
export function categoryReorderPut(data: any) {
|
||||
return request({
|
||||
url: '/manager/workplace/category/reorder',
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
// 分类获取应用
|
||||
export function categoryAppGet(category_no: string) {
|
||||
return request({
|
||||
url: `/manager/workplace/categorys/${category_no}/app`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 分类新增应用
|
||||
export function categoryAppPost(data: any, category_no: string) {
|
||||
return request({
|
||||
url: `/manager/workplace/categorys/${category_no}/app`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
// 分类删除应用
|
||||
export function categoryAppDelete(category_no: string, app_id: string) {
|
||||
return request({
|
||||
url: `/manager/workplace/categorys/${category_no}/apps/${app_id}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// 分类应用排序
|
||||
export function categorysAppsReorderPut(data: any, category_no: string) {
|
||||
return request({
|
||||
url: `/manager/workplace/categorys/${category_no}/app/reorder`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
@ -5,13 +5,31 @@
|
||||
{{ msg['content'] }}
|
||||
</span>
|
||||
<!-- 图片 -->
|
||||
<img v-else-if="msg.type == 2" class="w-120px" :src="`${url}${msg['url']}`" />
|
||||
<img
|
||||
v-else-if="msg.type == 2"
|
||||
class="w-120px cursor-pointer"
|
||||
:src="`${url}${msg['url']}`"
|
||||
@click="previewPicture(`${url}${msg['url']}`, 'image')"
|
||||
/>
|
||||
<!-- GIF -->
|
||||
<img v-else-if="msg.type == 3" class="w-120px" :src="`${url}${msg['url']}`" />
|
||||
<img
|
||||
v-else-if="msg.type == 3"
|
||||
class="w-120px cursor-pointer"
|
||||
:src="`${url}${msg['url']}`"
|
||||
@click="previewPicture(`${url}${msg['url']}`, 'image')"
|
||||
/>
|
||||
<!-- 语音 -->
|
||||
<audio v-else-if="msg.type == 4" :src="`${url}${msg['url']}`"></audio>
|
||||
<!-- 视频 -->
|
||||
<video v-else-if="msg.type == 5" controls :src="`${url}${msg['url']}`" class="w-220px h-100px"></video>
|
||||
<video
|
||||
v-else-if="msg.type == 5"
|
||||
controls
|
||||
controlsList="nofullscreen nodownload noplaybackrate noremote footbar"
|
||||
disablePictureInPicture
|
||||
:src="`${url}${msg['url']}`"
|
||||
class="w-220px h-100px cursor-pointer"
|
||||
@click="previewPicture(`${url}${msg['url']}`, 'image')"
|
||||
></video>
|
||||
<!-- 位置 -->
|
||||
<div v-else-if="msg.type == 6">
|
||||
<div>位置标题:{{ msg['title'] }}</div>
|
||||
@ -73,6 +91,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="tsx" name="BdMsg" setup>
|
||||
import { Fancybox } from '@fancyapps/ui';
|
||||
import '@lottiefiles/lottie-player/dist/tgs-player';
|
||||
import { BU_DOU_CONFIG } from '@/config';
|
||||
interface IProps {
|
||||
@ -80,4 +99,37 @@ interface IProps {
|
||||
}
|
||||
defineProps<IProps>();
|
||||
const url = BU_DOU_CONFIG.APP_URL;
|
||||
|
||||
// 图片预览
|
||||
const previewPicture = (url: string, type: string) => {
|
||||
const imgList = [];
|
||||
imgList.push({ src: url, defaultType: type });
|
||||
Fancybox.show(imgList, {
|
||||
Toolbar: {
|
||||
display: {
|
||||
left: ['infobar'],
|
||||
middle: ['zoomIn', 'zoomOut', 'toggle1to1', 'rotateCCW', 'rotateCW', 'flipX', 'flipY'],
|
||||
right: ['slideshow', 'thumbs', 'close']
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
video::-webkit-media-controls-timeline {
|
||||
display: none;
|
||||
}
|
||||
video::-webkit-media-controls-mute-button {
|
||||
display: none;
|
||||
}
|
||||
video::-webkit-media-controls-toggle-closed-captions-button {
|
||||
display: none;
|
||||
}
|
||||
video::-webkit-media-controls-volume-slider {
|
||||
display: none;
|
||||
}
|
||||
video::-webkit-media-controls-fullscreen-button {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
@ -10,25 +10,6 @@
|
||||
:class="tabsMenuValue === item.path ? 'chrome-tab_active' : ''"
|
||||
@click.stop="tabClick(item)"
|
||||
>
|
||||
<!-- <div class="chrome-tab__bg">
|
||||
<svg style="width: 100%; height: 100%">
|
||||
<defs>
|
||||
<symbol id="geometry-left" viewBox="0 0 214 36">
|
||||
<path d="M17 0h197v36H0v-2c4.5 0 9-3.5 9-8V8c0-4.5 3.5-8 8-8z"></path>
|
||||
</symbol>
|
||||
<symbol id="geometry-right" viewBox="0 0 214 36"><use xlink:href="#geometry-left"></use></symbol>
|
||||
<clipPath><rect width="100%" height="100%" x="0"></rect></clipPath>
|
||||
</defs>
|
||||
<svg width="51%" height="100%">
|
||||
<use xlink:href="#geometry-left" width="214" height="36" fill="currentColor"></use>
|
||||
</svg>
|
||||
<g transform="scale(-1, 1)">
|
||||
<svg width="51%" height="100%" x="-100%" y="0">
|
||||
<use xlink:href="#geometry-right" width="214" height="36" fill="currentColor"></use>
|
||||
</svg>
|
||||
</g>
|
||||
</svg>
|
||||
</div> -->
|
||||
<div v-if="item.icon && tabsIcon">
|
||||
<component :is="'i-bd-add-text'" theme="outline" size="16" class="cursor-pointer" />
|
||||
</div>
|
||||
|
@ -19,6 +19,7 @@ import 'vue-global-api';
|
||||
import 'element-plus/dist/index.css';
|
||||
import 'element-plus/theme-chalk/dark/css-vars.css';
|
||||
import '@icon-park/vue-next/styles/index.css';
|
||||
import '@fancyapps/ui/dist/fancybox/fancybox.css';
|
||||
import '@/styles/index.scss';
|
||||
import 'uno.css';
|
||||
|
||||
|
@ -9,7 +9,7 @@ const home: Menu.MenuOptions = {
|
||||
isHide: false,
|
||||
isKeepAlive: true,
|
||||
isLink: '',
|
||||
index: 8,
|
||||
index: 9,
|
||||
title: '设置'
|
||||
},
|
||||
children: [
|
||||
|
@ -9,7 +9,7 @@ const home: Menu.MenuOptions = {
|
||||
isHide: false,
|
||||
isKeepAlive: true,
|
||||
isLink: '',
|
||||
index: 7,
|
||||
index: 8,
|
||||
title: '工具'
|
||||
},
|
||||
children: [
|
||||
@ -27,6 +27,20 @@ const home: Menu.MenuOptions = {
|
||||
title: 'APP升级'
|
||||
}
|
||||
},
|
||||
{
|
||||
component: '/tool/command',
|
||||
name: 'toolCommand',
|
||||
path: '/tool/command',
|
||||
meta: {
|
||||
icon: 'i-bd-command',
|
||||
isAffix: false,
|
||||
isFull: false,
|
||||
isHide: false,
|
||||
isKeepAlive: true,
|
||||
isLink: '',
|
||||
title: '口令管理'
|
||||
}
|
||||
},
|
||||
{
|
||||
component: '/tool/systemrobotmenu',
|
||||
name: 'toolSystemrobotmenu',
|
||||
|
43
src/menu/modules/workplace.ts
Normal file
43
src/menu/modules/workplace.ts
Normal file
@ -0,0 +1,43 @@
|
||||
const home: Menu.MenuOptions = {
|
||||
name: 'tool',
|
||||
path: '/workplace',
|
||||
meta: {
|
||||
icon: 'i-bd-all-application',
|
||||
isAffix: false,
|
||||
isFull: false,
|
||||
isHide: false,
|
||||
isKeepAlive: true,
|
||||
isLink: '',
|
||||
index: 7,
|
||||
title: '工作台'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'workplaceManage',
|
||||
path: '/workplace/manage',
|
||||
meta: {
|
||||
icon: 'i-bd-application',
|
||||
isAffix: false,
|
||||
isFull: false,
|
||||
isHide: false,
|
||||
isKeepAlive: true,
|
||||
isLink: '',
|
||||
title: '应用管理'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'workplaceConfiguration',
|
||||
path: '/workplace/configuration',
|
||||
meta: {
|
||||
icon: 'i-bd-setting-config',
|
||||
isAffix: false,
|
||||
isFull: false,
|
||||
isHide: false,
|
||||
isKeepAlive: true,
|
||||
isLink: '',
|
||||
title: '工作台设置'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
export default home;
|
@ -35,8 +35,8 @@
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -32,8 +32,8 @@
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -33,7 +33,7 @@
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -35,8 +35,8 @@
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -34,7 +34,7 @@
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -36,7 +36,7 @@
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -39,7 +39,7 @@
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -198,8 +198,8 @@ const getUserList = () => {
|
||||
loadTable.value = true;
|
||||
messageRecordpersonalGet(queryFrom).then((res: any) => {
|
||||
loadTable.value = false;
|
||||
tableData.value = res.list;
|
||||
total.value = res.count;
|
||||
tableData.value = res?.list ? res?.list : [];
|
||||
total.value = res?.count ? res?.count : 0;
|
||||
});
|
||||
};
|
||||
|
||||
@ -225,6 +225,7 @@ const msgDel = (data: any) => {
|
||||
const formData = {
|
||||
channel_id: route.query.uid,
|
||||
channel_type: 1,
|
||||
from_uid: route.query.touid,
|
||||
list
|
||||
};
|
||||
messageDelete(formData).then((res: any) => {
|
||||
|
@ -30,7 +30,7 @@
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -32,8 +32,8 @@
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -23,8 +23,8 @@
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -23,8 +23,8 @@
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -29,8 +29,8 @@
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
146
src/pages/tool/command/components/CommandDialog.vue
Normal file
146
src/pages/tool/command/components/CommandDialog.vue
Normal file
@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="value"
|
||||
:width="600"
|
||||
:align-center="true"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:draggable="true"
|
||||
:z-index="99"
|
||||
:title="title"
|
||||
@close="onClose"
|
||||
>
|
||||
<el-form :model="formData" label-width="96px">
|
||||
<el-form-item label="口令">
|
||||
<el-input v-model="formData.short_url" placeholder="请输入口令" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="地址">
|
||||
<el-input v-model="formData.url" placeholder="请输入地址" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-space>
|
||||
<el-button @click="onClose">取消</el-button>
|
||||
<el-button type="primary" :loading="loaging" @click="onConfirm">保存</el-button>
|
||||
</el-space>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="CommandDialog" setup>
|
||||
import { ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
// API 接口
|
||||
import { commandPost, commandPut } from '@/api/command';
|
||||
|
||||
interface IProps {
|
||||
value: boolean;
|
||||
title: string;
|
||||
type: 'add' | 'edit';
|
||||
data: object;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
value: false,
|
||||
title: '新增口令',
|
||||
type: 'add'
|
||||
});
|
||||
|
||||
const content = ref('');
|
||||
const loaging = ref<boolean>(false);
|
||||
const formData = ref({
|
||||
short_url: '',
|
||||
url: ''
|
||||
});
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'update:value', item: boolean): void;
|
||||
(e: 'ok', item: any): void;
|
||||
}>();
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(n, _o) => {
|
||||
if (n && props.type === 'edit') {
|
||||
formData.value = props.data as any;
|
||||
}
|
||||
if (!n) {
|
||||
formData.value = {
|
||||
short_url: '',
|
||||
url: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 取消
|
||||
const onClose = () => {
|
||||
emits('update:value', false);
|
||||
};
|
||||
|
||||
// 新增口令
|
||||
const addBanner = () => {
|
||||
loaging.value = true;
|
||||
commandPost(formData.value)
|
||||
.then((res: any) => {
|
||||
loaging.value = false;
|
||||
if (res.status == 200) {
|
||||
ElMessage.success('新增成功!');
|
||||
content.value = '';
|
||||
onClose();
|
||||
emits('ok', true);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
loaging.value = false;
|
||||
if (err.status == 400) {
|
||||
ElMessage.error(err.msg);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 编辑口令
|
||||
const editBanner = () => {
|
||||
loaging.value = true;
|
||||
commandPut(formData.value, (props.data as any).id)
|
||||
.then((res: any) => {
|
||||
loaging.value = false;
|
||||
if (res.status == 200) {
|
||||
ElMessage.success('编辑成功!');
|
||||
content.value = '';
|
||||
onClose();
|
||||
emits('ok', true);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
loaging.value = false;
|
||||
if (err.status == 400) {
|
||||
ElMessage.error(err.msg);
|
||||
}
|
||||
});
|
||||
};
|
||||
// 保存
|
||||
const onConfirm = () => {
|
||||
if (props.type === 'add') {
|
||||
addBanner();
|
||||
}
|
||||
if (props.type === 'edit') {
|
||||
editBanner();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bd-uplod {
|
||||
::v-deep(.el-upload--picture-card) {
|
||||
height: 78px;
|
||||
width: 78px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
height: 78px;
|
||||
width: 78px;
|
||||
}
|
||||
}
|
||||
</style>
|
220
src/pages/tool/command/index.vue
Normal file
220
src/pages/tool/command/index.vue
Normal file
@ -0,0 +1,220 @@
|
||||
<template>
|
||||
<bd-page class="flex-col">
|
||||
<div class="flex-1 el-card border-none flex-col box-border overflow-hidden">
|
||||
<div class="h-50px pl-12px pr-12px box-border flex items-center justify-between bd-title">
|
||||
<div class="bd-title-left">
|
||||
<p class="m-0 font-600">口令管理</p>
|
||||
</div>
|
||||
<div class="flex items-center h-50px">
|
||||
<el-form inline>
|
||||
<el-form-item class="mb-0 !mr-16px">
|
||||
<el-input v-model="queryFrom.keyword" placeholder="名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item class="mb-0 !mr-16px">
|
||||
<el-button type="primary" @click="getTableList">查询</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item class="mb-0 !mr-0">
|
||||
<el-button type="primary" @click="onCommandAddClick">新增口令</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-hidden p-12px">
|
||||
<el-table v-loading="loadTable" :data="tableData" :border="true" style="width: 100%; height: 100%">
|
||||
<el-table-column type="index" :width="42" :align="'center'" :fixed="'left'">
|
||||
<template #header>
|
||||
<i-bd-drag class="cursor-pointer" size="16" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-for="item in column" v-bind="item" :key="item.prop">
|
||||
<template #default="scope">
|
||||
<template v-if="item.render">
|
||||
<component :is="item.render" :row="scope.row"> </component>
|
||||
</template>
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="bd-card-footer pl-12px pr-12px mb-12px flex items-center justify-between">
|
||||
<div></div>
|
||||
<el-pagination
|
||||
v-model:current-page="queryFrom.page_index"
|
||||
v-model:page-size="queryFrom.page_size"
|
||||
:page-sizes="[15, 20, 30, 50, 100]"
|
||||
:background="true"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
@size-change="onSizeChange"
|
||||
@current-change="onCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 口令操作 -->
|
||||
<CommandDialog
|
||||
v-model:value="commandDialogValue"
|
||||
:title="commandDialogTitle"
|
||||
:type="commandDialogType"
|
||||
:data="commandDialogData"
|
||||
@ok="onCommandOk"
|
||||
/>
|
||||
</bd-page>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
title: 口令管理
|
||||
isAffix: false
|
||||
</route>
|
||||
|
||||
<script lang="tsx" name="command" setup>
|
||||
import { ElButton, ElSpace, ElMessage, ElMessageBox } from 'element-plus';
|
||||
import CommandDialog from './components/CommandDialog.vue';
|
||||
|
||||
// API接口
|
||||
import { commandGet, commandDelete } from '@/api/command';
|
||||
/**
|
||||
* 表格
|
||||
*/
|
||||
const column = reactive<Column.ColumnOptions[]>([
|
||||
{
|
||||
prop: 'short_url',
|
||||
label: '口令名称'
|
||||
},
|
||||
{
|
||||
prop: 'url',
|
||||
label: '地址'
|
||||
},
|
||||
{
|
||||
prop: 'create_at',
|
||||
label: '创建时间'
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 150,
|
||||
align: 'center',
|
||||
render: (scope: any) => {
|
||||
return (
|
||||
<ElSpace>
|
||||
<ElButton type="primary" onClick={() => onCommandEidt(scope.row)}>
|
||||
编辑
|
||||
</ElButton>
|
||||
<ElButton type="danger" onClick={() => onCommandDel(scope.row)}>
|
||||
删除
|
||||
</ElButton>
|
||||
</ElSpace>
|
||||
);
|
||||
}
|
||||
}
|
||||
]);
|
||||
const tableData = ref<any[]>([]);
|
||||
const loadTable = ref<boolean>(false);
|
||||
// 分页
|
||||
const total = ref(0);
|
||||
|
||||
// 查询
|
||||
const queryFrom = reactive({
|
||||
keyword: '',
|
||||
page_size: 15,
|
||||
page_index: 1
|
||||
});
|
||||
|
||||
// 搜索
|
||||
const getTableList = () => {
|
||||
loadTable.value = true;
|
||||
commandGet(queryFrom)
|
||||
.then((res: any) => {
|
||||
loadTable.value = false;
|
||||
tableData.value = res.list;
|
||||
total.value = res.count;
|
||||
})
|
||||
.catch(() => {
|
||||
loadTable.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 分页page-size
|
||||
const onSizeChange = (size: number) => {
|
||||
queryFrom.page_size = size;
|
||||
getTableList();
|
||||
};
|
||||
|
||||
// 分页page-size
|
||||
const onCurrentChange = (current: number) => {
|
||||
queryFrom.page_index = current;
|
||||
getTableList();
|
||||
};
|
||||
|
||||
// 新增口令
|
||||
const commandDialogValue = ref(false);
|
||||
const commandDialogTitle = ref('新增口令');
|
||||
const commandDialogType = ref<'add' | 'edit'>('add');
|
||||
const onCommandAddClick = () => {
|
||||
commandDialogTitle.value = '新增口令';
|
||||
commandDialogType.value = 'add';
|
||||
commandDialogValue.value = true;
|
||||
};
|
||||
|
||||
// 编辑口令
|
||||
const commandDialogData = ref({});
|
||||
const onCommandEidt = (item: any) => {
|
||||
commandDialogTitle.value = `编辑${item.short_url}`;
|
||||
commandDialogData.value = item;
|
||||
commandDialogType.value = 'edit';
|
||||
commandDialogValue.value = true;
|
||||
};
|
||||
|
||||
// 保存口令
|
||||
const onCommandOk = () => {
|
||||
getTableList();
|
||||
};
|
||||
|
||||
// 删除口令
|
||||
const onCommandDel = (item: any) => {
|
||||
ElMessageBox.confirm(`确定要对该口令吗?`, `操作提示`, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
closeOnClickModal: false,
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
commandDelete(item.id)
|
||||
.then((_res: any) => {
|
||||
getTableList();
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: `口令删除成功!`
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
if (err.status == 400) {
|
||||
ElMessage.error(err.msg);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '取消成功!'
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getTableList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 样式
|
||||
.bd-title {
|
||||
border-bottom: 1px solid var(--el-card-border-color);
|
||||
}
|
||||
</style>
|
@ -23,8 +23,8 @@
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -32,8 +32,8 @@
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -36,8 +36,8 @@
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -35,8 +35,8 @@
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -33,8 +33,8 @@
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop] }}</slot>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -81,7 +81,7 @@ const userStore = useUserStore();
|
||||
const column = reactive<Column.ColumnOptions[]>([
|
||||
{
|
||||
prop: 'name',
|
||||
label: '用户名',
|
||||
label: '昵称',
|
||||
fixed: 'left',
|
||||
width: 140
|
||||
},
|
||||
@ -91,6 +91,11 @@ const column = reactive<Column.ColumnOptions[]>([
|
||||
fixed: 'left',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'username',
|
||||
label: '用户',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'avatar',
|
||||
label: '头像',
|
||||
|
192
src/pages/workplace/configuration/components/AppDialog.vue
Normal file
192
src/pages/workplace/configuration/components/AppDialog.vue
Normal file
@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="value"
|
||||
:width="780"
|
||||
:align-center="true"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:draggable="true"
|
||||
:z-index="99"
|
||||
title="添加应用"
|
||||
@close="onClose"
|
||||
>
|
||||
<div class="h-540px flex-col">
|
||||
<el-input v-model="queryFrom.keyword" class="mb-12px" placeholder="请输入应用名称" clearable @keyup.enter="onSearch" />
|
||||
<!-- 表格 -->
|
||||
<div class="flex-1 overflow-hidden">
|
||||
<el-table
|
||||
v-loading="loadTable"
|
||||
:data="tableData"
|
||||
row-key="app_id"
|
||||
:show-header="false"
|
||||
style="width: 100%; height: 100%"
|
||||
@selection-change="onSelectionChange"
|
||||
>
|
||||
<el-table-column v-for="(col, index) in column" v-bind="col" :key="index">
|
||||
<template #default="{ row }">
|
||||
<template v-if="col.render">
|
||||
<component :is="col.render" :row="row"> </component>
|
||||
</template>
|
||||
<template v-else-if="col.formatter">
|
||||
<slot :name="col.prop" :row="row">{{ col.formatter(row) }}</slot>
|
||||
</template>
|
||||
<template v-else-if="col.prop">
|
||||
<slot :name="col.prop" :row="row">{{ row[col.prop] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<div class="bd-card-footer mt-12px flex items-center justify-between">
|
||||
<div></div>
|
||||
<el-pagination
|
||||
v-model:current-page="queryFrom.page_index"
|
||||
v-model:page-size="queryFrom.page_size"
|
||||
:page-sizes="[15, 20, 30, 50, 100]"
|
||||
:background="true"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
@size-change="onSizeChange"
|
||||
@current-change="onCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-space>
|
||||
<el-button @click="onClose">取消</el-button>
|
||||
<el-button type="primary" :loading="loaging" @click="onConfirm">确定</el-button>
|
||||
</el-space>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="AppDialog" setup>
|
||||
import { ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
// API 接口
|
||||
import { categoryAppPost } from '@/api/workplace/category';
|
||||
import { appGet } from '@/api/workplace/app';
|
||||
|
||||
interface IProps {
|
||||
value: boolean;
|
||||
data: {
|
||||
category_no: string;
|
||||
};
|
||||
}
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
value: false
|
||||
});
|
||||
|
||||
const loaging = ref<boolean>(false);
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'update:value', item: boolean): void;
|
||||
(e: 'ok', item: any): void;
|
||||
}>();
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(n, _o) => {
|
||||
props.value = n;
|
||||
if (n) {
|
||||
getTableList();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 表格
|
||||
*/
|
||||
const column = reactive<Column.ColumnOptions[]>([
|
||||
{
|
||||
prop: 'name',
|
||||
label: '名称'
|
||||
},
|
||||
{
|
||||
prop: 'description',
|
||||
label: '描述'
|
||||
},
|
||||
{
|
||||
type: 'selection'
|
||||
}
|
||||
]);
|
||||
const tableData = ref<any[]>([]);
|
||||
const loadTable = ref<boolean>(false);
|
||||
const selectionData = ref<string[]>([]);
|
||||
const queryFrom = reactive({
|
||||
keyword: '',
|
||||
page_size: 15,
|
||||
page_index: 1
|
||||
});
|
||||
const total = ref(0);
|
||||
// 获取表格数据
|
||||
const getTableList = () => {
|
||||
loadTable.value = true;
|
||||
appGet(queryFrom)
|
||||
.then((res: any) => {
|
||||
loadTable.value = false;
|
||||
tableData.value = res.list || [];
|
||||
total.value = res.count || 0;
|
||||
})
|
||||
.catch(() => {
|
||||
loadTable.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 搜索
|
||||
const onSearch = () => {
|
||||
queryFrom.page_index = 1;
|
||||
queryFrom.page_size = 15;
|
||||
getTableList();
|
||||
};
|
||||
|
||||
const onSelectionChange = (val: any[]) => {
|
||||
const opt: string[] = [];
|
||||
val.map(item => {
|
||||
opt.push(item.app_id);
|
||||
});
|
||||
selectionData.value = opt;
|
||||
};
|
||||
|
||||
// 分页page-size
|
||||
const onSizeChange = (size: number) => {
|
||||
queryFrom.page_size = size;
|
||||
getTableList();
|
||||
};
|
||||
|
||||
// 分页page-size
|
||||
const onCurrentChange = (current: number) => {
|
||||
queryFrom.page_index = current;
|
||||
getTableList();
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
emits('update:value', false);
|
||||
};
|
||||
// 保存
|
||||
const onConfirm = () => {
|
||||
if (selectionData.value.length === 0) {
|
||||
return ElMessage.info('请输入分类!');
|
||||
}
|
||||
const fromData = {
|
||||
app_ids: selectionData.value
|
||||
};
|
||||
loaging.value = true;
|
||||
categoryAppPost(fromData, props.data.category_no)
|
||||
.then((res: any) => {
|
||||
loaging.value = false;
|
||||
if (res.status == 200) {
|
||||
ElMessage.success('新增应用成功!');
|
||||
onClose();
|
||||
emits('ok', true);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
loaging.value = false;
|
||||
if (err.status == 400) {
|
||||
ElMessage.error(err.msg);
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
265
src/pages/workplace/configuration/components/Banner.vue
Normal file
265
src/pages/workplace/configuration/components/Banner.vue
Normal file
@ -0,0 +1,265 @@
|
||||
<template>
|
||||
<bd-page class="flex-col !p-0">
|
||||
<div class="flex-1 el-card border-none flex-col box-border overflow-hidden">
|
||||
<div class="h-50px pl-12px pr-12px box-border flex items-center justify-between bd-title">
|
||||
<div class="bd-title-left"></div>
|
||||
<div class="flex items-center h-50px">
|
||||
<el-form inline>
|
||||
<el-form-item class="mb-0 !mr-0">
|
||||
<el-button type="primary" @click="onBannerDialogValue">新增轮播</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-hidden p-12px">
|
||||
<el-table v-loading="loadTable" :data="tableData" row-key="banner_no" :border="true" style="width: 100%; height: 100%">
|
||||
<el-table-column type="index" :width="42" :align="'center'" :fixed="'left'">
|
||||
<template #header>
|
||||
<i-bd-drag class="cursor-pointer" size="16" />
|
||||
</template>
|
||||
<template #default>
|
||||
<i-bd-drag class="bd-drag cursor-pointer" size="16" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-for="item in column" v-bind="item" :key="item.prop">
|
||||
<template #default="scope">
|
||||
<template v-if="item.render">
|
||||
<component :is="item.render" :row="scope.row"> </component>
|
||||
</template>
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 轮播 -->
|
||||
<BannerDialog
|
||||
v-model:value="bannerDialogValue"
|
||||
:title="bannerDialogTitle"
|
||||
:type="bannerDialogType"
|
||||
:data="bannerDialogData"
|
||||
@ok="onBannerOk"
|
||||
/>
|
||||
</bd-page>
|
||||
</template>
|
||||
|
||||
<script lang="tsx" name="Banner" setup>
|
||||
import { ElButton, ElSpace, ElMessageBox, ElMessage } from 'element-plus';
|
||||
import { Fancybox } from '@fancyapps/ui';
|
||||
import Sortable from 'sortablejs';
|
||||
import BannerDialog from './BannerDialog.vue';
|
||||
import { BU_DOU_CONFIG } from '@/config';
|
||||
|
||||
// API接口
|
||||
import { bannerGet, bannerDelete, bannerReorderPut } from '@/api/workplace/banner';
|
||||
|
||||
/**
|
||||
* 表格
|
||||
*/
|
||||
// 图片预览
|
||||
const previewPicture = (url: string) => {
|
||||
const imgList = [];
|
||||
imgList.push({ src: url });
|
||||
Fancybox.show(imgList, {
|
||||
Toolbar: {
|
||||
display: {
|
||||
left: ['infobar'],
|
||||
middle: ['zoomIn', 'zoomOut', 'toggle1to1', 'rotateCCW', 'rotateCW', 'flipX', 'flipY'],
|
||||
right: ['slideshow', 'thumbs', 'close']
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const column = reactive<Column.ColumnOptions[]>([
|
||||
{
|
||||
prop: 'title',
|
||||
label: '名称'
|
||||
},
|
||||
{
|
||||
prop: 'cover',
|
||||
label: '图片',
|
||||
width: 146,
|
||||
render: (scope: any) => {
|
||||
let img_url = '';
|
||||
if (scope.row['cover']) {
|
||||
img_url = `${BU_DOU_CONFIG.APP_URL}${scope.row.cover}`;
|
||||
}
|
||||
return <img src={img_url} class={'w-120px h-60px cursor-pointer'} onClick={() => previewPicture(img_url)} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'route',
|
||||
label: '地址'
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
label: '打开方式',
|
||||
formatter(row: any) {
|
||||
return row.status === 0 ? '网页' : '原生';
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'description',
|
||||
label: '描述'
|
||||
},
|
||||
{
|
||||
prop: 'created_at',
|
||||
label: '创建时间',
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 150,
|
||||
align: 'center',
|
||||
render: (scope: any) => {
|
||||
return (
|
||||
<ElSpace>
|
||||
<ElButton type="primary" onClick={() => onBannerEidt(scope.row)}>
|
||||
编辑
|
||||
</ElButton>
|
||||
<ElButton type="danger" onClick={() => onDelBanner(scope.row)}>
|
||||
删除
|
||||
</ElButton>
|
||||
</ElSpace>
|
||||
);
|
||||
}
|
||||
}
|
||||
]);
|
||||
const tableData = ref<any[]>([]);
|
||||
const loadTable = ref<boolean>(false);
|
||||
|
||||
// 查询
|
||||
const queryFrom = reactive({
|
||||
keyword: '',
|
||||
page_size: 15,
|
||||
page_index: 1
|
||||
});
|
||||
|
||||
// 搜索
|
||||
const getTableList = () => {
|
||||
loadTable.value = true;
|
||||
bannerGet(queryFrom)
|
||||
.then((res: any) => {
|
||||
loadTable.value = false;
|
||||
tableData.value = res;
|
||||
})
|
||||
.catch(() => {
|
||||
loadTable.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 新增轮播
|
||||
const bannerDialogValue = ref(false);
|
||||
const bannerDialogTitle = ref('新增轮播');
|
||||
const bannerDialogType = ref<'add' | 'edit'>('add');
|
||||
const onBannerDialogValue = () => {
|
||||
bannerDialogTitle.value = `新增轮播`;
|
||||
bannerDialogType.value = 'add';
|
||||
bannerDialogValue.value = true;
|
||||
};
|
||||
|
||||
// 编辑轮播
|
||||
const bannerDialogData = ref({});
|
||||
const onBannerEidt = (item: any) => {
|
||||
bannerDialogTitle.value = `编辑${item.title}`;
|
||||
bannerDialogData.value = item;
|
||||
bannerDialogType.value = 'edit';
|
||||
bannerDialogValue.value = true;
|
||||
};
|
||||
|
||||
// 保存轮播
|
||||
const onBannerOk = () => {
|
||||
getTableList();
|
||||
};
|
||||
|
||||
// 删除轮播
|
||||
const onDelBanner = (item: any) => {
|
||||
ElMessageBox.confirm(`确定要对该轮播吗?`, `操作提示`, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
closeOnClickModal: false,
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
bannerDelete(item.banner_no)
|
||||
.then((_res: any) => {
|
||||
getTableList();
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: `轮播删除成功!`
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
if (err.status == 400) {
|
||||
ElMessage.error(err.msg);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '取消成功!'
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const bannerReorder = (newIndex: string, oldIndex: string) => {
|
||||
const fromData = {
|
||||
banner_nos: [newIndex, oldIndex]
|
||||
};
|
||||
bannerReorderPut(fromData).then(res => {
|
||||
if (res.status == 200) {
|
||||
getTableList();
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: `轮播排序成功`
|
||||
});
|
||||
} else {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '轮播排序失败!'
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// tree 拖拽排序
|
||||
const tableDrop = () => {
|
||||
Sortable.create(document.querySelector('.el-table__body-wrapper tbody') as HTMLElement, {
|
||||
handle: '.bd-drag',
|
||||
animation: 300,
|
||||
onEnd(evt: any) {
|
||||
const { newIndex, oldIndex } = evt;
|
||||
const tablesList = [...tableData.value];
|
||||
const currRow = tablesList.splice(oldIndex as number, 1)[0];
|
||||
tablesList.splice(newIndex as number, 0, currRow);
|
||||
if (oldIndex > newIndex) {
|
||||
// 向上排序
|
||||
bannerReorder(tablesList[newIndex].banner_no, tablesList[oldIndex].banner_no);
|
||||
} else {
|
||||
// 向下排序
|
||||
bannerReorder(tablesList[oldIndex].banner_no, tablesList[newIndex].banner_no);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getTableList();
|
||||
tableDrop();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 样式
|
||||
.bd-title {
|
||||
border-bottom: 1px solid var(--el-card-border-color);
|
||||
}
|
||||
</style>
|
212
src/pages/workplace/configuration/components/BannerDialog.vue
Normal file
212
src/pages/workplace/configuration/components/BannerDialog.vue
Normal file
@ -0,0 +1,212 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="value"
|
||||
:width="600"
|
||||
:align-center="true"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:draggable="true"
|
||||
:z-index="99"
|
||||
:title="title"
|
||||
@close="onClose"
|
||||
>
|
||||
<el-form :model="formData" label-width="96px">
|
||||
<el-form-item label="标题">
|
||||
<el-input v-model="formData.title" placeholder="请输入标题" />
|
||||
</el-form-item>
|
||||
<el-form-item label="图片">
|
||||
<el-upload
|
||||
ref="upload"
|
||||
class="bd-upload"
|
||||
:action="actionURL"
|
||||
list-type="picture-card"
|
||||
:show-file-list="false"
|
||||
:headers="headers"
|
||||
:before-upload="beforeUploadFile"
|
||||
:on-success="onFileSuccess"
|
||||
>
|
||||
<img v-if="formData.cover" :src="`${BU_DOU_CONFIG.APP_URL}${formData.cover}`" class="avatar" />
|
||||
<el-icon v-else><Plus /></el-icon>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="打开方式">
|
||||
<el-radio-group v-model="formData.jump_type">
|
||||
<el-radio :label="0">网页</el-radio>
|
||||
<el-radio :label="1">APP</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="地址">
|
||||
<el-input v-model="formData.route" placeholder="请输入地址" />
|
||||
</el-form-item>
|
||||
<el-form-item label="描述">
|
||||
<el-input
|
||||
v-model="formData.description"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 6, maxRows: 8 }"
|
||||
placeholder="请输入描述"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-space>
|
||||
<el-button @click="onClose">取消</el-button>
|
||||
<el-button type="primary" :loading="loaging" @click="onConfirm">保存</el-button>
|
||||
</el-space>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="BannerDialog" setup>
|
||||
import { ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { Plus } from '@element-plus/icons-vue';
|
||||
import { useUserStore } from '@/stores/modules/user';
|
||||
// API 接口
|
||||
import { bannerPost, bannerPut } from '@/api/workplace/banner';
|
||||
import { feileGet } from '@/api/file';
|
||||
|
||||
import { BU_DOU_CONFIG } from '@/config';
|
||||
|
||||
interface IProps {
|
||||
value: boolean;
|
||||
title: string;
|
||||
type: 'add' | 'edit';
|
||||
data: object;
|
||||
}
|
||||
|
||||
const userStore = useUserStore();
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
value: false,
|
||||
title: '新增轮播',
|
||||
type: 'add'
|
||||
});
|
||||
|
||||
const content = ref('');
|
||||
const loaging = ref<boolean>(false);
|
||||
const formData = ref({
|
||||
cover: '',
|
||||
title: '',
|
||||
description: '',
|
||||
route: '',
|
||||
jump_type: 0
|
||||
});
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'update:value', item: boolean): void;
|
||||
(e: 'ok', item: any): void;
|
||||
}>();
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(n, _o) => {
|
||||
if (n && props.type === 'edit') {
|
||||
formData.value = props.data as any;
|
||||
}
|
||||
if (!n) {
|
||||
formData.value = {
|
||||
cover: '',
|
||||
title: '',
|
||||
description: '',
|
||||
route: '',
|
||||
jump_type: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 上传图片
|
||||
*/
|
||||
const headers = {
|
||||
token: userStore.token
|
||||
};
|
||||
const actionURL = ref('');
|
||||
// 图片上传前获取上传地址
|
||||
const beforeUploadFile = async (rawFile: any) => {
|
||||
const fileData = {
|
||||
path: `/${rawFile.uid}/${rawFile.name}`,
|
||||
type: 'report'
|
||||
};
|
||||
const res = (await feileGet(fileData)) as any;
|
||||
if (res.url) {
|
||||
actionURL.value = res.url;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
// 图片上传成功获取地址
|
||||
const onFileSuccess = (response: any, _uploadFile: any) => {
|
||||
formData.value.cover = response.path;
|
||||
};
|
||||
// 取消
|
||||
const onClose = () => {
|
||||
emits('update:value', false);
|
||||
};
|
||||
|
||||
// 新增轮播
|
||||
const addBanner = () => {
|
||||
loaging.value = true;
|
||||
bannerPost(formData.value)
|
||||
.then((res: any) => {
|
||||
loaging.value = false;
|
||||
if (res.status == 200) {
|
||||
ElMessage.success('新增成功!');
|
||||
content.value = '';
|
||||
onClose();
|
||||
emits('ok', true);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
loaging.value = false;
|
||||
if (err.status == 400) {
|
||||
ElMessage.error(err.msg);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 编辑轮播
|
||||
const editBanner = () => {
|
||||
loaging.value = true;
|
||||
const banner_no = (props.data as any).banner_no;
|
||||
bannerPut(formData.value, banner_no)
|
||||
.then((res: any) => {
|
||||
loaging.value = false;
|
||||
if (res.status == 200) {
|
||||
ElMessage.success('编辑成功!');
|
||||
content.value = '';
|
||||
onClose();
|
||||
emits('ok', true);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
loaging.value = false;
|
||||
if (err.status == 400) {
|
||||
ElMessage.error(err.msg);
|
||||
}
|
||||
});
|
||||
};
|
||||
// 发送
|
||||
const onConfirm = () => {
|
||||
if (props.type === 'add') {
|
||||
addBanner();
|
||||
}
|
||||
if (props.type === 'edit') {
|
||||
editBanner();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bd-upload {
|
||||
::v-deep(.el-upload--picture-card) {
|
||||
height: 78px;
|
||||
width: 78px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
height: 78px;
|
||||
width: 78px;
|
||||
}
|
||||
}
|
||||
</style>
|
133
src/pages/workplace/configuration/components/CategoryDialog.vue
Normal file
133
src/pages/workplace/configuration/components/CategoryDialog.vue
Normal file
@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="value"
|
||||
:width="400"
|
||||
:align-center="true"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:draggable="true"
|
||||
:z-index="99"
|
||||
title="新增分类"
|
||||
@close="onClose"
|
||||
>
|
||||
<div>
|
||||
<el-input v-model="content" placeholder="请输入分类" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-space>
|
||||
<el-button @click="onClose">取消</el-button>
|
||||
<el-button type="primary" :loading="loaging" @click="onSend">保存</el-button>
|
||||
</el-space>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="CategoryDialog" setup>
|
||||
import { ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
// API 接口
|
||||
import { categoryPost, categoryPut } from '@/api/workplace/category';
|
||||
interface IProps {
|
||||
value: boolean;
|
||||
type: 'add' | 'edit';
|
||||
data: {
|
||||
category_no?: string;
|
||||
name?: string;
|
||||
sort_num?: number;
|
||||
};
|
||||
}
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
value: false,
|
||||
title: '新增分类',
|
||||
type: 'add'
|
||||
});
|
||||
|
||||
const content = ref('');
|
||||
const loaging = ref<boolean>(false);
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'update:value', item: boolean): void;
|
||||
(e: 'ok', item: any): void;
|
||||
}>();
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(n, _o) => {
|
||||
console.log(props.value);
|
||||
props.value = n;
|
||||
if (n && props.type == 'edit') {
|
||||
content.value = props.data?.name || '';
|
||||
}
|
||||
if (!n) {
|
||||
content.value = '';
|
||||
}
|
||||
}
|
||||
);
|
||||
// 取消
|
||||
const onClose = () => {
|
||||
emits('update:value', false);
|
||||
};
|
||||
|
||||
// 新增分类
|
||||
const addCategor = () => {
|
||||
const fromData = {
|
||||
name: content.value
|
||||
};
|
||||
loaging.value = true;
|
||||
categoryPost(fromData)
|
||||
.then((res: any) => {
|
||||
loaging.value = false;
|
||||
if (res.status == 200) {
|
||||
ElMessage.success('编辑分类成功!');
|
||||
content.value = '';
|
||||
onClose();
|
||||
emits('ok', true);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
loaging.value = false;
|
||||
if (err.status == 400) {
|
||||
ElMessage.error(err.msg);
|
||||
}
|
||||
});
|
||||
};
|
||||
// 编辑分类
|
||||
const editCategor = () => {
|
||||
const fromData = {
|
||||
name: content.value
|
||||
};
|
||||
loaging.value = true;
|
||||
const category_no = (props.data as any).category_no;
|
||||
categoryPut(fromData, category_no)
|
||||
.then((res: any) => {
|
||||
loaging.value = false;
|
||||
if (res.status == 200) {
|
||||
ElMessage.success('编辑分类成功!');
|
||||
content.value = '';
|
||||
onClose();
|
||||
emits('ok', true);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
loaging.value = false;
|
||||
if (err.status == 400) {
|
||||
ElMessage.error(err.msg);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 保存
|
||||
const onSend = () => {
|
||||
if (!content.value) {
|
||||
return ElMessage.info('请输入分类!');
|
||||
}
|
||||
// 新增
|
||||
if (props.type === 'add') {
|
||||
addCategor();
|
||||
}
|
||||
// 编辑
|
||||
if (props.type === 'edit') {
|
||||
editCategor();
|
||||
}
|
||||
};
|
||||
</script>
|
447
src/pages/workplace/configuration/components/CustomGroup.vue
Normal file
447
src/pages/workplace/configuration/components/CustomGroup.vue
Normal file
@ -0,0 +1,447 @@
|
||||
<template>
|
||||
<bd-page class="flex !p-0">
|
||||
<!-- S 左侧分类 -->
|
||||
<div class="bd-sort min-w-200px max-w-200px h-full box-border flex flex-col">
|
||||
<div class="h-50px pl-12px pr-12px box-border flex items-center justify-between bd-title">
|
||||
<div class="bd-title-left font-500 text-14px">分组</div>
|
||||
<div class="flex items-center h-50px">
|
||||
<i-bd-add :size="22" class="cursor-pointer" @click="onCategoryAdd" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="m-12px">
|
||||
<el-input v-model="keyword" placeholder="搜索分类/按回车键搜索" clearable />
|
||||
</div>
|
||||
<div class="flex-1 overflow-hidden">
|
||||
<el-scrollbar>
|
||||
<div class="tree-warp p-12px pt-0">
|
||||
<div
|
||||
v-for="item in dataTree"
|
||||
:key="item.category_no"
|
||||
class="bd-tree-item"
|
||||
:class="{ 'bd-tree-activate': item.category_no === optTree }"
|
||||
@click="onOptTreeClick(item.category_no)"
|
||||
>
|
||||
<div class="mr-4px">
|
||||
<i-bd-drag class="bd-drag cursor-pointer" size="14" />
|
||||
</div>
|
||||
<div class="flex-1 text">{{ item.name }}</div>
|
||||
<div class="bd-opt">
|
||||
<i-bd-editor :size="16" class="cursor-pointer pr-4px" @click.stop="onCategoryEdit(item)" />
|
||||
<i-bd-delete :size="16" class="cursor-pointer" @click.stop="onCategoryDelete(item)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
<!-- E 左侧分类 -->
|
||||
|
||||
<!-- S 右侧 表格 -->
|
||||
<div class="flex-1 h-full flex flex-col">
|
||||
<div class="h-50px pl-12px pr-12px box-border flex items-center justify-between bd-title">
|
||||
<div class="bd-title-left"></div>
|
||||
<div class="flex items-center h-50px">
|
||||
<el-form inline>
|
||||
<el-form-item class="mb-0 !mr-0">
|
||||
<el-button type="primary" @click="appDialogValue = true">新增应用</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 表格 -->
|
||||
<div class="flex-1 overflow-hidden p-12px">
|
||||
<el-table v-loading="loadTable" :data="tableData" row-key="app_id" :border="true" style="width: 100%; height: 100%">
|
||||
<el-table-column type="index" :width="42" :align="'center'" :fixed="'left'">
|
||||
<template #header>
|
||||
<i-bd-drag class="cursor-pointer" size="16" />
|
||||
</template>
|
||||
<template #default>
|
||||
<i-bd-drag class="bd-drag cursor-pointer" size="16" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-for="item in column" v-bind="item" :key="item.prop">
|
||||
<template #default="scope">
|
||||
<template v-if="item.render">
|
||||
<component :is="item.render" :row="scope.row"> </component>
|
||||
</template>
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- E 右侧 表格 -->
|
||||
|
||||
<!-- 新增分类 -->
|
||||
<CategoryDialog
|
||||
v-model:value="categoryValue"
|
||||
:type="categoryType"
|
||||
:title="categoryTitle"
|
||||
:data="categoryData"
|
||||
@ok="onCategoryOk"
|
||||
/>
|
||||
|
||||
<!-- 添加应用 -->
|
||||
<AppDialog v-model:value="appDialogValue" :data="appDialogData" @ok="onAppDialogOk" />
|
||||
</bd-page>
|
||||
</template>
|
||||
|
||||
<script lang="tsx" name="CustomGroup" setup>
|
||||
import { ElButton, ElSpace, ElImage, ElMessageBox, ElMessage } from 'element-plus';
|
||||
import Sortable from 'sortablejs';
|
||||
import CategoryDialog from './CategoryDialog.vue';
|
||||
import AppDialog from './AppDialog.vue';
|
||||
import { BU_DOU_CONFIG } from '@/config';
|
||||
|
||||
// API接口
|
||||
import {
|
||||
categoryGet,
|
||||
categoryDelete,
|
||||
categoryReorderPut,
|
||||
categoryAppGet,
|
||||
categoryAppDelete,
|
||||
categorysAppsReorderPut
|
||||
} from '@/api/workplace/category';
|
||||
|
||||
interface Tree {
|
||||
category_no: string;
|
||||
name: string;
|
||||
sort_num: number;
|
||||
}
|
||||
/**
|
||||
* 左侧分类
|
||||
*/
|
||||
const dataTree = ref<Tree[]>([]);
|
||||
const optTree = ref('');
|
||||
const keyword = ref('');
|
||||
// 获取分类
|
||||
const getCategoryData = () => {
|
||||
categoryGet().then((res: any) => {
|
||||
if (res.length > 0) {
|
||||
dataTree.value = res;
|
||||
if (!optTree.value) {
|
||||
optTree.value = res[0].category_no;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 选中
|
||||
const onOptTreeClick = (no: string) => {
|
||||
optTree.value = no;
|
||||
};
|
||||
|
||||
// 确定添加应用
|
||||
const onCategoryOk = () => {
|
||||
getCategoryData();
|
||||
};
|
||||
// 分类排序
|
||||
const categoryReorder = (newIndex: string, oldIndex: string) => {
|
||||
const fromData = {
|
||||
category_nos: [newIndex, oldIndex]
|
||||
};
|
||||
categoryReorderPut(fromData).then(res => {
|
||||
if (res.status == 200) {
|
||||
getCategoryData();
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: `分类排序成功`
|
||||
});
|
||||
} else {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '分类排序失败!'
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 分类拖拽排序
|
||||
const treesDrop = () => {
|
||||
Sortable.create(document.querySelector('.tree-warp') as HTMLElement, {
|
||||
handle: '.bd-drag',
|
||||
animation: 300,
|
||||
onEnd({ newIndex, oldIndex }: any) {
|
||||
const treesList = [...dataTree.value];
|
||||
const currRow = treesList.splice(oldIndex as number, 1)[0];
|
||||
treesList.splice(newIndex as number, 0, currRow);
|
||||
if (oldIndex > newIndex) {
|
||||
// 向上排序
|
||||
categoryReorder(treesList[newIndex].category_no, treesList[oldIndex].category_no);
|
||||
} else {
|
||||
// 向下排序
|
||||
categoryReorder(treesList[oldIndex].category_no, treesList[newIndex].category_no);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const categoryValue = ref(false);
|
||||
const categoryTitle = ref('新增分类');
|
||||
const categoryType = ref<'add' | 'edit'>('add');
|
||||
const categoryData = ref({});
|
||||
|
||||
// 分类新增
|
||||
const onCategoryAdd = () => {
|
||||
categoryValue.value = true;
|
||||
categoryTitle.value = '新增分类';
|
||||
categoryType.value = 'add';
|
||||
categoryData.value = {};
|
||||
};
|
||||
|
||||
// 分类编辑
|
||||
const onCategoryEdit = (item: any) => {
|
||||
console.log(item);
|
||||
categoryValue.value = true;
|
||||
categoryTitle.value = '编辑分类';
|
||||
categoryType.value = 'edit';
|
||||
categoryData.value = { ...item };
|
||||
};
|
||||
|
||||
// 分类删除
|
||||
const onCategoryDelete = (item: any) => {
|
||||
ElMessageBox.confirm(`确定要对该分类吗?`, `操作提示`, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
closeOnClickModal: false,
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
categoryDelete(item.category_no)
|
||||
.then((_res: any) => {
|
||||
getCategoryData();
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: `轮播删除成功!`
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
if (err.status == 400) {
|
||||
ElMessage.error(err.msg);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '取消成功!'
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 添加应用
|
||||
*/
|
||||
const appDialogValue = ref(false);
|
||||
const appDialogData = ref({
|
||||
category_no: ''
|
||||
});
|
||||
watch(
|
||||
() => optTree.value,
|
||||
() => {
|
||||
appDialogData.value = {
|
||||
category_no: optTree.value
|
||||
};
|
||||
queryFrom.category_no = optTree.value;
|
||||
getTableList();
|
||||
}
|
||||
);
|
||||
// 确定添加应用
|
||||
const onAppDialogOk = () => {
|
||||
getTableList();
|
||||
};
|
||||
/**
|
||||
* 表格
|
||||
*/
|
||||
const column = reactive<Column.ColumnOptions[]>([
|
||||
{
|
||||
prop: 'icon',
|
||||
label: '应用LOGO',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
render: (scope: any) => {
|
||||
let img_url = '';
|
||||
if (scope.row['icon']) {
|
||||
img_url = `${BU_DOU_CONFIG.APP_URL}${scope.row.icon}`;
|
||||
}
|
||||
return <ElImage src={img_url} fit={'scale-down'} class={'w-60px h-60px'} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'name',
|
||||
label: '应用名称',
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
prop: 'app_id',
|
||||
label: '应用APP ID',
|
||||
width: 290
|
||||
},
|
||||
{
|
||||
prop: 'description',
|
||||
label: '描述'
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
align: 'center',
|
||||
width: 80,
|
||||
render: (scope: any) => {
|
||||
return (
|
||||
<ElSpace>
|
||||
<ElButton type="danger" onClick={() => onDelApply(scope.row)}>
|
||||
删除
|
||||
</ElButton>
|
||||
</ElSpace>
|
||||
);
|
||||
}
|
||||
}
|
||||
]);
|
||||
const tableData = ref<any[]>([]);
|
||||
const loadTable = ref<boolean>(false);
|
||||
|
||||
// 查询
|
||||
const queryFrom = reactive({
|
||||
category_no: ''
|
||||
});
|
||||
|
||||
// 搜索
|
||||
const getTableList = () => {
|
||||
loadTable.value = true;
|
||||
categoryAppGet(queryFrom.category_no)
|
||||
.then((res: any) => {
|
||||
loadTable.value = false;
|
||||
tableData.value = res;
|
||||
})
|
||||
.catch(() => {
|
||||
loadTable.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 移除应用
|
||||
const onDelApply = (item: any) => {
|
||||
ElMessageBox.confirm(`确定要对该应用移除吗?`, `操作提示`, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
closeOnClickModal: false,
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
categoryAppDelete(optTree.value, item.app_id)
|
||||
.then((_res: any) => {
|
||||
getTableList();
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: `应用移除成功!`
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
if (err.status == 400) {
|
||||
ElMessage.error(err.msg);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '取消成功!'
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const categorysAppsReorder = (new_app_id: string, old_app_id: string) => {
|
||||
const fromData = {
|
||||
app_ids: [new_app_id, old_app_id]
|
||||
};
|
||||
categorysAppsReorderPut(fromData, queryFrom.category_no).then(res => {
|
||||
if (res.status == 200) {
|
||||
getTableList();
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: `应用排序成功`
|
||||
});
|
||||
} else {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '应用排序失败!'
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// table 拖拽排序
|
||||
const tableDrop = () => {
|
||||
Sortable.create(document.querySelector('.el-table__body-wrapper tbody') as HTMLElement, {
|
||||
handle: '.bd-drag',
|
||||
animation: 300,
|
||||
onEnd({ newIndex, oldIndex }: any) {
|
||||
const tablesList = [...tableData.value];
|
||||
const currRow = tablesList.splice(oldIndex as number, 1)[0];
|
||||
tablesList.splice(newIndex as number, 0, currRow);
|
||||
tableData.value = tablesList;
|
||||
if (oldIndex > newIndex) {
|
||||
// 向上排序
|
||||
categorysAppsReorder(tablesList[newIndex].app_id, tablesList[oldIndex].app_id);
|
||||
} else {
|
||||
// 向下排序
|
||||
categorysAppsReorder(tablesList[oldIndex].app_id, tablesList[newIndex].app_id);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 初始化数据
|
||||
*/
|
||||
onMounted(() => {
|
||||
getCategoryData();
|
||||
treesDrop();
|
||||
tableDrop();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 分类
|
||||
.bd-sort {
|
||||
border-right: 1px solid var(--el-card-border-color);
|
||||
}
|
||||
|
||||
.bd-tree-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
height: 26px;
|
||||
padding: 0 4px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 4px;
|
||||
|
||||
.bd-opt {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--el-menu-active-bg-color);
|
||||
color: var(--el-menu-active-color);
|
||||
.bd-opt {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bd-tree-activate {
|
||||
background-color: var(--el-menu-active-bg-color);
|
||||
.text {
|
||||
color: var(--el-menu-active-color);
|
||||
}
|
||||
}
|
||||
|
||||
.bd-title {
|
||||
border-bottom: 1px solid var(--el-card-border-color);
|
||||
}
|
||||
</style>
|
161
src/pages/workplace/configuration/components/Recommend.vue
Normal file
161
src/pages/workplace/configuration/components/Recommend.vue
Normal file
@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<bd-page class="flex-col !p-0">
|
||||
<div class="flex-1 el-card border-none flex-col box-border overflow-hidden">
|
||||
<div class="h-50px pl-12px pr-12px box-border flex items-center justify-between bd-title">
|
||||
<div class="bd-title-left"></div>
|
||||
<div class="flex items-center h-50px">
|
||||
<el-form inline>
|
||||
<el-form-item class="mb-0 !mr-16px">
|
||||
<el-input v-model="queryFrom.keyword" placeholder="名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item class="mb-0 !mr-0">
|
||||
<el-button type="primary">新增推荐应用</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-hidden p-12px">
|
||||
<el-table v-loading="loadTable" :data="tableData" :border="true" style="width: 100%; height: 100%">
|
||||
<el-table-column type="index" :width="42" :align="'center'" :fixed="'left'">
|
||||
<template #header>
|
||||
<i-bd-drag class="cursor-pointer" size="16" />
|
||||
</template>
|
||||
<template #default>
|
||||
<i-bd-drag class="bd-drag cursor-pointer" size="16" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-for="item in column" v-bind="item" :key="item.prop">
|
||||
<template #default="scope">
|
||||
<template v-if="item.render">
|
||||
<component :is="item.render" :row="scope.row"> </component>
|
||||
</template>
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="bd-card-footer pl-12px pr-12px mb-12px flex items-center justify-between">
|
||||
<div></div>
|
||||
<el-pagination
|
||||
v-model:current-page="queryFrom.page_index"
|
||||
v-model:page-size="queryFrom.page_size"
|
||||
:page-sizes="[15, 20, 30, 50, 100]"
|
||||
:background="true"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
@size-change="onSizeChange"
|
||||
@current-change="onCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</bd-page>
|
||||
</template>
|
||||
|
||||
<script lang="tsx" name="Recommend" setup>
|
||||
import { ElButton, ElSpace, ElImage } from 'element-plus';
|
||||
import Sortable from 'sortablejs';
|
||||
import { BU_DOU_CONFIG } from '@/config';
|
||||
/**
|
||||
* 表格
|
||||
*/
|
||||
const column = reactive<Column.ColumnOptions[]>([
|
||||
{
|
||||
prop: 'icon',
|
||||
label: '应用LOGO',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
render: (scope: any) => {
|
||||
let img_url = '';
|
||||
if (scope.row['icon']) {
|
||||
img_url = `${BU_DOU_CONFIG.APP_URL}${scope.row.icon}`;
|
||||
}
|
||||
return <ElImage src={img_url} fit={'scale-down'} class={'w-60px h-60px'} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'name',
|
||||
label: '应用名称',
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
prop: 'app_id',
|
||||
label: '应用APP ID',
|
||||
width: 290
|
||||
},
|
||||
{
|
||||
prop: 'description',
|
||||
label: '描述'
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
align: 'center',
|
||||
render: (_scope: any) => {
|
||||
return (
|
||||
<ElSpace>
|
||||
<ElButton type="primary">配置</ElButton>
|
||||
</ElSpace>
|
||||
);
|
||||
}
|
||||
}
|
||||
]);
|
||||
const tableData = ref<any[]>([]);
|
||||
const loadTable = ref<boolean>(false);
|
||||
// 分页
|
||||
const total = ref(0);
|
||||
|
||||
// 查询
|
||||
const queryFrom = reactive({
|
||||
keyword: '',
|
||||
page_size: 15,
|
||||
page_index: 1
|
||||
});
|
||||
|
||||
// 搜索
|
||||
const getTableList = () => {};
|
||||
|
||||
// 分页page-size
|
||||
const onSizeChange = (size: number) => {
|
||||
queryFrom.page_size = size;
|
||||
getTableList();
|
||||
};
|
||||
|
||||
// 分页page-size
|
||||
const onCurrentChange = (current: number) => {
|
||||
queryFrom.page_index = current;
|
||||
getTableList();
|
||||
};
|
||||
|
||||
// 新增版本
|
||||
|
||||
// table 拖拽排序
|
||||
const tableDrop = () => {
|
||||
Sortable.create(document.querySelector('.el-table__body-wrapper tbody') as HTMLElement, {
|
||||
// draggable: '.bd-drag',
|
||||
animation: 300,
|
||||
onEnd({ newIndex, oldIndex }: any) {
|
||||
const tablesList = [...tableData.value];
|
||||
const currRow = tablesList.splice(oldIndex as number, 1)[0];
|
||||
tablesList.splice(newIndex as number, 0, currRow);
|
||||
tableData.value = tablesList;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
tableDrop();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 样式
|
||||
.bd-title {
|
||||
border-bottom: 1px solid var(--el-card-border-color);
|
||||
}
|
||||
</style>
|
41
src/pages/workplace/configuration/index.vue
Normal file
41
src/pages/workplace/configuration/index.vue
Normal file
@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<bd-page class="flex-col">
|
||||
<div class="flex-1 el-card border-none flex-col box-border overflow-hidden">
|
||||
<el-tabs v-model="activeName" class="bd-tabs">
|
||||
<el-tab-pane v-for="item in tabsData" :key="item.name" :label="item.label" :name="item.name">
|
||||
<component :is="item.render" v-if="item.name === activeName" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</bd-page>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
title: 工作台设置
|
||||
isAffix: false
|
||||
</route>
|
||||
|
||||
<script lang="tsx" setup>
|
||||
import Banner from './components/Banner.vue';
|
||||
import CustomGroup from './components/CustomGroup.vue';
|
||||
|
||||
const activeName = ref('banner');
|
||||
|
||||
const tabsData = reactive([
|
||||
{
|
||||
name: 'banner',
|
||||
label: '轮播',
|
||||
render: () => {
|
||||
return <Banner />;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'custom-group',
|
||||
label: '自定义分组',
|
||||
render: () => {
|
||||
return <CustomGroup />;
|
||||
}
|
||||
}
|
||||
]);
|
||||
</script>
|
230
src/pages/workplace/manage/components/Apply.vue
Normal file
230
src/pages/workplace/manage/components/Apply.vue
Normal file
@ -0,0 +1,230 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="value"
|
||||
:width="600"
|
||||
:align-center="true"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:draggable="true"
|
||||
:z-index="99"
|
||||
:title="title"
|
||||
@close="onClose"
|
||||
>
|
||||
<el-form :model="formData" label-width="96px">
|
||||
<el-form-item label="应用名称">
|
||||
<el-input v-model="formData.name" placeholder="请输入应用名称" maxlength="10" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item label="应用图标">
|
||||
<el-upload
|
||||
ref="upload"
|
||||
class="bd-upload"
|
||||
:action="actionURL"
|
||||
list-type="picture-card"
|
||||
:show-file-list="false"
|
||||
:headers="headers"
|
||||
:before-upload="beforeUploadFile"
|
||||
:on-success="onFileSuccess"
|
||||
>
|
||||
<img v-if="formData.icon" :src="`${BU_DOU_CONFIG.APP_URL}${formData.icon}`" class="avatar" />
|
||||
<el-icon v-else><Plus /></el-icon>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="打开方式">
|
||||
<el-radio-group v-model="formData.jump_type">
|
||||
<el-radio :label="0">网页</el-radio>
|
||||
<el-radio :label="1">APP</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="网页地址">
|
||||
<el-input v-model="formData.web_route" placeholder="请输入网页地址" />
|
||||
</el-form-item>
|
||||
<el-form-item label="APP地址">
|
||||
<el-input v-model="formData.app_route" placeholder="请输入APP地址" />
|
||||
</el-form-item>
|
||||
<el-form-item label="付款">
|
||||
<el-radio-group v-model="formData.is_paid_app">
|
||||
<el-radio :label="0">免费</el-radio>
|
||||
<el-radio :label="1">付费</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="应用描述">
|
||||
<el-input
|
||||
v-model="formData.description"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 6, maxRows: 8 }"
|
||||
placeholder="请输入应用描述"
|
||||
show-word-limit
|
||||
maxlength="500"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-space>
|
||||
<el-button @click="onClose">取消</el-button>
|
||||
<el-button type="primary" :loading="loaging" @click="onConfirm">保存</el-button>
|
||||
</el-space>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="Apply" setup>
|
||||
import { ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { Plus } from '@element-plus/icons-vue';
|
||||
import { useUserStore } from '@/stores/modules/user';
|
||||
// API 接口
|
||||
import { appPost, appPut } from '@/api/workplace/app';
|
||||
import { feileGet } from '@/api/file';
|
||||
|
||||
import { BU_DOU_CONFIG } from '@/config';
|
||||
|
||||
interface IProps {
|
||||
value: boolean;
|
||||
title: string;
|
||||
type: 'add' | 'edit';
|
||||
data: object;
|
||||
}
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
value: false,
|
||||
title: '新增应用',
|
||||
type: 'add'
|
||||
});
|
||||
const userStore = useUserStore();
|
||||
|
||||
const content = ref('');
|
||||
const loaging = ref<boolean>(false);
|
||||
const formData = ref({
|
||||
icon: '',
|
||||
name: '',
|
||||
jump_type: 0,
|
||||
description: '',
|
||||
app_route: '',
|
||||
web_route: '',
|
||||
is_paid_app: 0
|
||||
});
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'update:value', item: boolean): void;
|
||||
(e: 'ok', item: any): void;
|
||||
}>();
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(n, _o) => {
|
||||
props.value = n;
|
||||
if (n && props.type == 'edit') {
|
||||
formData.value = props.data as any;
|
||||
}
|
||||
if (!n) {
|
||||
formData.value = {
|
||||
icon: '',
|
||||
name: '',
|
||||
jump_type: 0,
|
||||
description: '',
|
||||
app_route: '',
|
||||
web_route: '',
|
||||
is_paid_app: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 上传图片
|
||||
*/
|
||||
const headers = {
|
||||
token: userStore.token
|
||||
};
|
||||
const actionURL = ref('');
|
||||
// 图片上传前获取上传地址
|
||||
const beforeUploadFile = async (rawFile: any) => {
|
||||
const fileData = {
|
||||
path: `/${rawFile.uid}/${rawFile.name}`,
|
||||
type: 'report'
|
||||
};
|
||||
const res = (await feileGet(fileData)) as any;
|
||||
if (res.url) {
|
||||
actionURL.value = res.url;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
// 图片上传成功获取地址
|
||||
const onFileSuccess = (response: any, _uploadFile: any) => {
|
||||
formData.value.icon = response.path;
|
||||
};
|
||||
|
||||
// 取消
|
||||
const onClose = () => {
|
||||
emits('update:value', false);
|
||||
};
|
||||
|
||||
// 新增应用
|
||||
const addApp = () => {
|
||||
loaging.value = true;
|
||||
appPost(formData.value)
|
||||
.then((res: any) => {
|
||||
loaging.value = false;
|
||||
if (res.status == 200) {
|
||||
ElMessage.success('新增成功!');
|
||||
content.value = '';
|
||||
onClose();
|
||||
emits('ok', true);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
loaging.value = false;
|
||||
if (err.status == 400) {
|
||||
ElMessage.error(err.msg);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 编辑
|
||||
const editApp = () => {
|
||||
loaging.value = true;
|
||||
const app_id = (props.data as any).app_id;
|
||||
appPut(formData.value, app_id)
|
||||
.then((res: any) => {
|
||||
loaging.value = false;
|
||||
if (res.status == 200) {
|
||||
ElMessage.success('编辑成功!');
|
||||
content.value = '';
|
||||
onClose();
|
||||
emits('ok', true);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
loaging.value = false;
|
||||
if (err.status == 400) {
|
||||
ElMessage.error(err.msg);
|
||||
}
|
||||
});
|
||||
};
|
||||
// 发送
|
||||
const onConfirm = () => {
|
||||
// 新增
|
||||
if (props.type === 'add') {
|
||||
addApp();
|
||||
}
|
||||
// 编辑
|
||||
if (props.type === 'edit') {
|
||||
editApp();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bd-upload {
|
||||
::v-deep(.el-upload--picture-card) {
|
||||
height: 78px;
|
||||
width: 78px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
height: 78px;
|
||||
width: 78px;
|
||||
}
|
||||
}
|
||||
</style>
|
256
src/pages/workplace/manage/index.vue
Normal file
256
src/pages/workplace/manage/index.vue
Normal file
@ -0,0 +1,256 @@
|
||||
<template>
|
||||
<bd-page class="flex-col">
|
||||
<div class="flex-1 el-card border-none flex-col box-border overflow-hidden">
|
||||
<div class="h-50px pl-12px pr-12px box-border flex items-center justify-between bd-title">
|
||||
<div class="bd-title-left">
|
||||
<p class="m-0 font-600">应用管理</p>
|
||||
</div>
|
||||
<div class="flex items-center h-50px">
|
||||
<el-form inline>
|
||||
<el-form-item class="mb-0 !mr-16px">
|
||||
<el-input v-model="queryFrom.keyword" placeholder="应用名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item class="mb-0 !mr-16px">
|
||||
<el-button type="primary" @click="getTableList">查询</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item class="mb-0 !mr-0">
|
||||
<el-button type="primary" @click="onAppVersionAdd">新增应用</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-hidden p-12px">
|
||||
<el-table v-loading="loadTable" :data="tableData" :border="true" style="width: 100%; height: 100%">
|
||||
<el-table-column type="index" :width="42" :align="'center'" :fixed="'left'">
|
||||
<template #header>
|
||||
<i-bd-setting class="cursor-pointer" size="16" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-for="item in column" v-bind="item" :key="item.prop">
|
||||
<template #default="scope">
|
||||
<template v-if="item.render">
|
||||
<component :is="item.render" :row="scope.row"> </component>
|
||||
</template>
|
||||
<template v-else-if="item.formatter">
|
||||
<slot :name="item.prop" :row="scope.row">{{ item.formatter(scope.row) }}</slot>
|
||||
</template>
|
||||
<template v-else-if="item.prop">
|
||||
<slot :name="item.prop" :row="scope.row">{{ scope.row[item.prop!] }}</slot>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="bd-card-footer pl-12px pr-12px mb-12px flex items-center justify-between">
|
||||
<div></div>
|
||||
<el-pagination
|
||||
v-model:current-page="queryFrom.page_index"
|
||||
v-model:page-size="queryFrom.page_size"
|
||||
:page-sizes="[15, 20, 30, 50, 100]"
|
||||
:background="true"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
@size-change="onSizeChange"
|
||||
@current-change="onCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 应用 -->
|
||||
<Apply v-model:value="applyAddValue" :type="applyType" :title="applyTitle" :data="applyData" @ok="onApplyClick" />
|
||||
</bd-page>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
title: 应用管理
|
||||
isAffix: false
|
||||
</route>
|
||||
|
||||
<script lang="tsx" setup>
|
||||
import { ElButton, ElMessageBox, ElMessage, ElSpace } from 'element-plus';
|
||||
import { Fancybox } from '@fancyapps/ui';
|
||||
import Apply from './components/Apply.vue';
|
||||
import { BU_DOU_CONFIG } from '@/config';
|
||||
|
||||
// API接口
|
||||
import { appGet, appDelete } from '@/api/workplace/app';
|
||||
/**
|
||||
* 新增应用
|
||||
*/
|
||||
// 新增版本
|
||||
const applyAddValue = ref<boolean>(false);
|
||||
const applyTitle = ref('新增应用');
|
||||
const applyType = ref<'add' | 'edit'>('add');
|
||||
const onAppVersionAdd = () => {
|
||||
applyAddValue.value = true;
|
||||
applyTitle.value = '新增应用';
|
||||
applyType.value = 'add';
|
||||
};
|
||||
|
||||
// 确定应用
|
||||
const onApplyClick = () => {
|
||||
getTableList();
|
||||
};
|
||||
|
||||
const previewPicture = (url: string) => {
|
||||
const imgList = [];
|
||||
imgList.push({ src: url });
|
||||
Fancybox.show(imgList, {
|
||||
Toolbar: {
|
||||
display: {
|
||||
left: ['infobar'],
|
||||
middle: ['zoomIn', 'zoomOut', 'toggle1to1', 'rotateCCW', 'rotateCW', 'flipX', 'flipY'],
|
||||
right: ['slideshow', 'thumbs', 'close']
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 表格
|
||||
*/
|
||||
const column = reactive<Column.ColumnOptions[]>([
|
||||
{
|
||||
prop: 'icon',
|
||||
label: '应用LOGO',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
render: (scope: any) => {
|
||||
let img_url = '';
|
||||
if (scope.row['icon']) {
|
||||
img_url = `${BU_DOU_CONFIG.APP_URL}${scope.row.icon}`;
|
||||
}
|
||||
return <img src={img_url} class={'w-60px h-60px cursor-pointer'} onClick={() => previewPicture(img_url)} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'name',
|
||||
label: '应用名称',
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
prop: 'app_id',
|
||||
label: '应用APP ID',
|
||||
width: 290
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
label: '应用状态',
|
||||
width: 100,
|
||||
formatter(row: any) {
|
||||
return row.status === 1 ? '开启' : '关闭';
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'description',
|
||||
label: '应用描述'
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 150,
|
||||
align: 'center',
|
||||
render: (scope: any) => {
|
||||
return (
|
||||
<ElSpace>
|
||||
<ElButton type="primary" onClick={() => oApplyEidt(scope.row)}>
|
||||
编辑
|
||||
</ElButton>
|
||||
<ElButton type="danger" onClick={() => onDelApply(scope.row)}>
|
||||
删除
|
||||
</ElButton>
|
||||
</ElSpace>
|
||||
);
|
||||
}
|
||||
}
|
||||
]);
|
||||
const tableData = ref<any[]>([]);
|
||||
const loadTable = ref<boolean>(false);
|
||||
// 分页
|
||||
const total = ref(0);
|
||||
|
||||
// 查询
|
||||
const queryFrom = reactive({
|
||||
keyword: '',
|
||||
page_size: 15,
|
||||
page_index: 1
|
||||
});
|
||||
|
||||
// 搜索
|
||||
const getTableList = () => {
|
||||
loadTable.value = true;
|
||||
appGet(queryFrom)
|
||||
.then((res: any) => {
|
||||
loadTable.value = false;
|
||||
tableData.value = res.list || [];
|
||||
total.value = res.count || 0;
|
||||
})
|
||||
.catch(() => {
|
||||
loadTable.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 编辑
|
||||
const applyData = ref({});
|
||||
const oApplyEidt = (item: any) => {
|
||||
applyTitle.value = `编辑${item.name}`;
|
||||
applyData.value = item;
|
||||
applyType.value = 'edit';
|
||||
applyAddValue.value = true;
|
||||
};
|
||||
|
||||
// 删除应用
|
||||
const onDelApply = (item: any) => {
|
||||
ElMessageBox.confirm(`确定要对该应用删除吗?`, `操作提示`, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
closeOnClickModal: false,
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
appDelete(item.app_id)
|
||||
.then((_res: any) => {
|
||||
getTableList();
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: `应用删除成功!`
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
if (err.status == 400) {
|
||||
ElMessage.error(err.msg);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '取消成功!'
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 分页page-size
|
||||
const onSizeChange = (size: number) => {
|
||||
queryFrom.page_size = size;
|
||||
getTableList();
|
||||
};
|
||||
|
||||
// 分页page-size
|
||||
const onCurrentChange = (current: number) => {
|
||||
queryFrom.page_index = current;
|
||||
getTableList();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getTableList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 样式
|
||||
.bd-title {
|
||||
border-bottom: 1px solid var(--el-card-border-color);
|
||||
}
|
||||
</style>
|
@ -11,6 +11,7 @@
|
||||
|
||||
/* 当前页面最大化 css */
|
||||
.main-maximize {
|
||||
|
||||
.aside-split,
|
||||
.el-aside,
|
||||
.el-header,
|
||||
@ -40,6 +41,7 @@
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.table-search {
|
||||
padding: 18px 0 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
@ -52,18 +54,22 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
.text {
|
||||
margin: 20px 0 30px;
|
||||
font-size: 23px;
|
||||
font-weight: bold;
|
||||
color: var(--el-text-color-regular);
|
||||
}
|
||||
|
||||
.el-descriptions {
|
||||
width: 100%;
|
||||
padding: 40px 0 0;
|
||||
|
||||
.el-descriptions__title {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.el-descriptions__label {
|
||||
width: 200px;
|
||||
}
|
||||
@ -75,6 +81,7 @@
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.table-box {
|
||||
// 这里减去的是 treeFilter 组件宽度
|
||||
width: calc(100% - 230px);
|
||||
@ -94,8 +101,9 @@
|
||||
.table-search {
|
||||
padding: 18px 18px 0;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.el-form {
|
||||
.el-form-item__content > * {
|
||||
.el-form-item__content>* {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@ -104,6 +112,7 @@
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.operation {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -117,9 +126,11 @@
|
||||
.header-button-lf {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.header-button-ri {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
@ -133,6 +144,7 @@
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.el-table__header th {
|
||||
height: 45px;
|
||||
font-size: 15px;
|
||||
@ -140,16 +152,18 @@
|
||||
color: var(--el-text-color-primary);
|
||||
background: var(--el-fill-color-light);
|
||||
}
|
||||
|
||||
.el-table__row {
|
||||
height: 45px;
|
||||
font-size: 14px;
|
||||
|
||||
.el-table__placeholder {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
// 设置 el-table 中 header 文字不换行,并省略
|
||||
.el-table__header .el-table__cell > .cell {
|
||||
.el-table__header .el-table__cell>.cell {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@ -159,6 +173,7 @@
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
.table-empty {
|
||||
line-height: 30px;
|
||||
}
|
||||
@ -186,16 +201,19 @@
|
||||
height: 40px !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
.el-table__row {
|
||||
height: 40px !important;
|
||||
font-size: 13px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-table--large {
|
||||
.el-table__header th {
|
||||
height: 50px !important;
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
.el-table__row {
|
||||
height: 50px !important;
|
||||
font-size: 15px !important;
|
||||
@ -208,12 +226,14 @@
|
||||
padding: 16px 20px;
|
||||
margin-bottom: 0;
|
||||
border-bottom: 1px solid var(--el-border-color-lighter);
|
||||
|
||||
span {
|
||||
font-size: 17px;
|
||||
line-height: 17px;
|
||||
color: var(--el-text-color-primary) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-drawer__footer {
|
||||
border-top: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
@ -227,8 +247,10 @@
|
||||
.drawer-multiColumn-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.el-form-item {
|
||||
width: 47%;
|
||||
|
||||
&:nth-child(2n-1) {
|
||||
margin-right: 5%;
|
||||
}
|
||||
@ -242,6 +264,7 @@
|
||||
padding: 15px 20px;
|
||||
margin: 0;
|
||||
border-bottom: 1px solid var(--el-border-color-lighter);
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 17px;
|
||||
}
|
||||
@ -258,12 +281,47 @@
|
||||
background: var(--el-fill-color-light);
|
||||
}
|
||||
}
|
||||
|
||||
/* el-menu-item */
|
||||
.el-menu-item {
|
||||
height: 48px !important;
|
||||
line-height: 48px !important;
|
||||
}
|
||||
|
||||
/* bu-button*/
|
||||
.bu-button:focus-visible {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/* bd-tabs */
|
||||
.bd-tabs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
.el-tabs__header {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.el-tabs__nav-wrap {
|
||||
padding: 0 24px;
|
||||
|
||||
&::after {
|
||||
height: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.el-tabs__item {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.el-tabs__content {
|
||||
flex: 1;
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
.el-tab-pane {
|
||||
flex: 1;
|
||||
height: 100% !important;
|
||||
}
|
||||
}
|
||||
|
4
src/types/global.d.ts
vendored
4
src/types/global.d.ts
vendored
@ -80,8 +80,8 @@ type ObjToKeyValArray<T> = {
|
||||
}[keyof T];
|
||||
declare namespace Column {
|
||||
interface ColumnOptions {
|
||||
prop: string;
|
||||
label: string;
|
||||
prop?: string;
|
||||
label?: string;
|
||||
type?: 'selection' | 'index' | 'expand';
|
||||
fixed?: true | 'left' | 'right';
|
||||
width?: string | number;
|
||||
|
Loading…
x
Reference in New Issue
Block a user