mirror of https://gitee.com/xiaonuobase/snowy
【更新】前端依赖大升级,业务代码等多处优化调整,完全去掉以往this.xxx等语法。
parent
a216d0ccff
commit
4f9de9fc9a
|
@ -19,70 +19,70 @@
|
|||
"dependencies": {
|
||||
"@amap/amap-jsapi-loader": "1.0.1",
|
||||
"@ant-design/colors": "7.0.0",
|
||||
"@ant-design/icons-vue": "6.1.0",
|
||||
"@antv/g2plot": "2.4.28",
|
||||
"@ant-design/icons-vue": "7.0.1",
|
||||
"@antv/g2plot": "2.4.31",
|
||||
"@chenfengyuan/vue-qrcode": "2.0.0",
|
||||
"@highlightjs/vue-plugin": "2.1.0",
|
||||
"@tinymce/tinymce-vue": "5.0.0",
|
||||
"@vue-office/docx": "1.2.0",
|
||||
"@vue-office/excel": "1.2.0",
|
||||
"@vue-office/pdf": "1.2.0",
|
||||
"@tinymce/tinymce-vue": "5.1.1",
|
||||
"@vue-office/docx": "1.3.2",
|
||||
"@vue-office/excel": "1.4.7",
|
||||
"@vue-office/pdf": "1.5.5",
|
||||
"ant-design-vue": "3.2.14",
|
||||
"axios": "1.1.3",
|
||||
"cropperjs": "1.5.12",
|
||||
"dayjs": "1.11.7",
|
||||
"echarts": "5.4.0",
|
||||
"axios": "1.6.2",
|
||||
"cropperjs": "1.6.1",
|
||||
"dayjs": "1.11.10",
|
||||
"echarts": "5.4.3",
|
||||
"echarts-stat": "1.2.0",
|
||||
"enquire.js": "2.1.6",
|
||||
"event-source-polyfill": "1.0.31",
|
||||
"fuse.js": "6.6.2",
|
||||
"highlight.js": "11.6.0",
|
||||
"hotkeys-js": "3.10.1",
|
||||
"js-pinyin": "0.1.9",
|
||||
"fuse.js": "7.0.0",
|
||||
"highlight.js": "11.9.0",
|
||||
"hotkeys-js": "3.12.2",
|
||||
"js-pinyin": "0.2.5",
|
||||
"lodash-es": "4.17.21",
|
||||
"nprogress": "0.2.0",
|
||||
"pinia": "2.0.33",
|
||||
"qs": "6.11.1",
|
||||
"pinia": "2.1.7",
|
||||
"qs": "6.11.2",
|
||||
"screenfull": "6.0.2",
|
||||
"sm-crypto": "0.3.11",
|
||||
"sm-crypto": "0.3.13",
|
||||
"snowflake-id": "1.1.0",
|
||||
"sortablejs": "1.15.0",
|
||||
"tinymce": "6.2.0",
|
||||
"vue": "3.2.44",
|
||||
"vue-cropper": "1.0.5",
|
||||
"sortablejs": "1.15.1",
|
||||
"tinymce": "6.8.1",
|
||||
"vue": "3.3.10",
|
||||
"vue-cropper": "1.1.1",
|
||||
"vue-demi": "0.13.11",
|
||||
"vue-i18n": "9.2.2",
|
||||
"vue-router": "4.1.6",
|
||||
"vue3-colorpicker": "2.0.4",
|
||||
"vue-i18n": "9.8.0",
|
||||
"vue-router": "4.2.5",
|
||||
"vue3-colorpicker": "2.2.3",
|
||||
"vue3-tree-org": "4.2.2",
|
||||
"vuedraggable-es": "4.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "0.29.4",
|
||||
"@babel/eslint-parser": "7.19.1",
|
||||
"@vitejs/plugin-legacy": "3.0.2",
|
||||
"@vitejs/plugin-vue": "4.1.0",
|
||||
"@vitejs/plugin-vue-jsx": "3.0.1",
|
||||
"@vue/compiler-sfc": "3.2.47",
|
||||
"@vitejs/plugin-legacy": "5.2.0",
|
||||
"@vitejs/plugin-vue": "4.5.2",
|
||||
"@vitejs/plugin-vue-jsx": "3.1.0",
|
||||
"@vue/compiler-sfc": "3.3.10",
|
||||
"@vue/eslint-config-standard": "8.0.1",
|
||||
"antd-less-to-css-variable": "1.0.5",
|
||||
"autoprefixer": "10.4.13",
|
||||
"eslint": "8.26.0",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"eslint-plugin-prettier": "4.2.1",
|
||||
"autoprefixer": "10.4.16",
|
||||
"eslint": "8.55.0",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-plugin-prettier": "5.0.1",
|
||||
"eslint-plugin-vue": "9.7.0",
|
||||
"less": "4.1.3",
|
||||
"postcss": "8.4.21",
|
||||
"prettier": "2.8.7",
|
||||
"rollup-plugin-visualizer": "5.8.3",
|
||||
"tailwindcss": "3.2.7",
|
||||
"typescript": "4.9.5",
|
||||
"unplugin-auto-import": "0.15.2",
|
||||
"unplugin-vue-components": "0.24.1",
|
||||
"vite": "4.2.1",
|
||||
"postcss": "8.4.32",
|
||||
"prettier": "3.1.0",
|
||||
"rollup-plugin-visualizer": "5.10.0",
|
||||
"tailwindcss": "3.3.6",
|
||||
"typescript": "5.3.3",
|
||||
"unplugin-auto-import": "0.17.2",
|
||||
"unplugin-vue-components": "0.26.0",
|
||||
"vite": "5.0.6",
|
||||
"vite-plugin-compression": "0.5.1",
|
||||
"vite-plugin-vue-setup-extend": "0.4.0",
|
||||
"vue-eslint-parser": "9.1.0"
|
||||
"vue-eslint-parser": "9.3.2"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/auth/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/auth/` + url, ...arg)
|
||||
/**
|
||||
* 绘画
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/auth/third/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/auth/third/` + url, ...arg)
|
||||
/**
|
||||
* 三方登录
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/auth/third/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/auth/third/` + url, ...arg)
|
||||
/**
|
||||
* 三方用户
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/biz/dict/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/biz/dict/` + url, ...arg)
|
||||
/**
|
||||
* 字典
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/biz/org/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/biz/org/` + url, ...arg)
|
||||
/**
|
||||
* 机构
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/biz/position/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/biz/position/` + url, ...arg)
|
||||
/**
|
||||
* 岗位
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/biz/user/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/biz/user/` + url, ...arg)
|
||||
/**
|
||||
* 人员接口api
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/dev/config/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/dev/config/` + url, ...arg)
|
||||
/**
|
||||
* 配置
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/dev/dict/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/dev/dict/` + url, ...arg)
|
||||
/**
|
||||
* 字典
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/dev/email/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/dev/email/` + url, ...arg)
|
||||
/**
|
||||
* 邮件
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/dev/file/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/dev/file/` + url, ...arg)
|
||||
/**
|
||||
* 文件
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/dev/job/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/dev/job/` + url, ...arg)
|
||||
/**
|
||||
* 定时任务
|
||||
*
|
||||
|
@ -22,10 +22,6 @@ export default {
|
|||
jobPage(data) {
|
||||
return request('page', data, 'get')
|
||||
},
|
||||
// 获取定时任务列表
|
||||
jobList(data) {
|
||||
return request('list', data, 'get')
|
||||
},
|
||||
// 提交表单 edit为true时为编辑,默认为新增
|
||||
submitForm(data, edit = false) {
|
||||
return request(edit ? 'edit' : 'add', data)
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/dev/log/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/dev/log/` + url, ...arg)
|
||||
/**
|
||||
* 日志
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/dev/message/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/dev/message/` + url, ...arg)
|
||||
/**
|
||||
* 站内信
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/dev/monitor/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/dev/monitor/` + url, ...arg)
|
||||
/**
|
||||
* 监控
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/dev/sms/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/dev/sms/` + url, ...arg)
|
||||
/**
|
||||
* 短信
|
||||
*
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/gen/basic/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/gen/basic/` + url, ...arg)
|
||||
|
||||
export default {
|
||||
// 获取代码生成基础分页
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/gen/config/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/gen/config/` + url, ...arg)
|
||||
|
||||
export default {
|
||||
// 获取代码生成详情配置列表
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/mobile/button/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/mobile/button/` + url, ...arg)
|
||||
/**
|
||||
* 按钮
|
||||
*
|
||||
|
|
|
@ -13,10 +13,6 @@ export default {
|
|||
mobileMenuTree(data) {
|
||||
return request('tree', data, 'get')
|
||||
},
|
||||
// 获取移动端菜单列表
|
||||
mobileMenuList(data) {
|
||||
return request('list', data, 'get')
|
||||
},
|
||||
// 提交移动端菜单表单 edit为true时为编辑,默认为新增
|
||||
mobileMenuSubmitForm(data, edit = false) {
|
||||
return request(edit ? 'edit' : 'add', data)
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/mobile/module/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/mobile/module/` + url, ...arg)
|
||||
/**
|
||||
* 类别
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/sys/index/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/sys/index/` + url, ...arg)
|
||||
/**
|
||||
* 系统首页控制器
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/sys/org/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/sys/org/` + url, ...arg)
|
||||
/**
|
||||
* 机构
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/sys/position/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/sys/position/` + url, ...arg)
|
||||
/**
|
||||
* 职位
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/sys/button/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/sys/button/` + url, ...arg)
|
||||
/**
|
||||
* 按钮
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/sys/field/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/sys/field/` + url, ...arg)
|
||||
/**
|
||||
* 字段
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/sys/menu/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/sys/menu/` + url, ...arg)
|
||||
/**
|
||||
* 菜单
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/sys/module/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/sys/module/` + url, ...arg)
|
||||
/**
|
||||
* 模块
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/sys/role/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/sys/role/` + url, ...arg)
|
||||
/**
|
||||
* 角色
|
||||
*
|
||||
|
@ -22,10 +22,6 @@ export default {
|
|||
rolePage(data) {
|
||||
return request('page', data, 'get')
|
||||
},
|
||||
// 获取角色列表
|
||||
roleList(data) {
|
||||
return request('list', data, 'get')
|
||||
},
|
||||
// 提交表单 edit为true时为编辑,默认为新增
|
||||
submitForm(data, edit = false) {
|
||||
return request(edit ? 'edit' : 'add', data)
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/sys/user/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/sys/user/` + url, ...arg)
|
||||
/**
|
||||
* 用户接口api
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
import { baseRequest } from '@/utils/request'
|
||||
|
||||
const request = (url, ...arg) => baseRequest(`/sys/userCenter/${url}`, ...arg)
|
||||
const request = (url, ...arg) => baseRequest(`/sys/userCenter/` + url, ...arg)
|
||||
/**
|
||||
* 用户个人控制器
|
||||
*
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
export const getYear = () => {
|
||||
let v = []
|
||||
let y = new Date().getFullYear()
|
||||
for (let i = 0; i < 11; i++) {
|
||||
v.push(y + i)
|
||||
}
|
||||
return v
|
||||
}
|
||||
export const data = {
|
||||
second: ['0', '5', '15', '20', '25', '30', '35', '40', '45', '50', '55', '59'],
|
||||
minute: ['0', '5', '15', '20', '25', '30', '35', '40', '45', '50', '55', '59'],
|
||||
hour: [
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'10',
|
||||
'11',
|
||||
'12',
|
||||
'13',
|
||||
'14',
|
||||
'15',
|
||||
'16',
|
||||
'17',
|
||||
'18',
|
||||
'19',
|
||||
'20',
|
||||
'21',
|
||||
'22',
|
||||
'23'
|
||||
],
|
||||
day: [
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'10',
|
||||
'11',
|
||||
'12',
|
||||
'13',
|
||||
'14',
|
||||
'15',
|
||||
'16',
|
||||
'17',
|
||||
'18',
|
||||
'19',
|
||||
'20',
|
||||
'21',
|
||||
'22',
|
||||
'23',
|
||||
'24',
|
||||
'25',
|
||||
'26',
|
||||
'27',
|
||||
'28',
|
||||
'29',
|
||||
'30',
|
||||
'31'
|
||||
],
|
||||
month: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
|
||||
week: [
|
||||
{
|
||||
value: '1',
|
||||
label: '周日'
|
||||
},
|
||||
{
|
||||
value: '2',
|
||||
label: '周一'
|
||||
},
|
||||
{
|
||||
value: '3',
|
||||
label: '周二'
|
||||
},
|
||||
{
|
||||
value: '4',
|
||||
label: '周三'
|
||||
},
|
||||
{
|
||||
value: '5',
|
||||
label: '周四'
|
||||
},
|
||||
{
|
||||
value: '6',
|
||||
label: '周五'
|
||||
},
|
||||
{
|
||||
value: '7',
|
||||
label: '周六'
|
||||
}
|
||||
],
|
||||
year: getYear()
|
||||
}
|
|
@ -405,18 +405,10 @@
|
|||
</template>
|
||||
|
||||
<script setup name="XnCron">
|
||||
import { data, getYear } from './data.js'
|
||||
const activeKey = ref('1')
|
||||
const type = ref('0')
|
||||
const defaultValue = ref('')
|
||||
const modalVisible = ref(false)
|
||||
const getYear = () => {
|
||||
let v = []
|
||||
let y = new Date().getFullYear()
|
||||
for (let i = 0; i < 11; i++) {
|
||||
v.push(y + i)
|
||||
}
|
||||
return v
|
||||
}
|
||||
const dateValue = ref({
|
||||
second: {
|
||||
type: '0',
|
||||
|
@ -504,101 +496,6 @@
|
|||
appoint: []
|
||||
}
|
||||
})
|
||||
const data = {
|
||||
second: ['0', '5', '15', '20', '25', '30', '35', '40', '45', '50', '55', '59'],
|
||||
minute: ['0', '5', '15', '20', '25', '30', '35', '40', '45', '50', '55', '59'],
|
||||
hour: [
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'10',
|
||||
'11',
|
||||
'12',
|
||||
'13',
|
||||
'14',
|
||||
'15',
|
||||
'16',
|
||||
'17',
|
||||
'18',
|
||||
'19',
|
||||
'20',
|
||||
'21',
|
||||
'22',
|
||||
'23'
|
||||
],
|
||||
day: [
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'10',
|
||||
'11',
|
||||
'12',
|
||||
'13',
|
||||
'14',
|
||||
'15',
|
||||
'16',
|
||||
'17',
|
||||
'18',
|
||||
'19',
|
||||
'20',
|
||||
'21',
|
||||
'22',
|
||||
'23',
|
||||
'24',
|
||||
'25',
|
||||
'26',
|
||||
'27',
|
||||
'28',
|
||||
'29',
|
||||
'30',
|
||||
'31'
|
||||
],
|
||||
month: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
|
||||
week: [
|
||||
{
|
||||
value: '1',
|
||||
label: '周日'
|
||||
},
|
||||
{
|
||||
value: '2',
|
||||
label: '周一'
|
||||
},
|
||||
{
|
||||
value: '3',
|
||||
label: '周二'
|
||||
},
|
||||
{
|
||||
value: '4',
|
||||
label: '周三'
|
||||
},
|
||||
{
|
||||
value: '5',
|
||||
label: '周四'
|
||||
},
|
||||
{
|
||||
value: '6',
|
||||
label: '周五'
|
||||
},
|
||||
{
|
||||
value: '7',
|
||||
label: '周六'
|
||||
}
|
||||
],
|
||||
year: getYear()
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
|
@ -610,112 +507,63 @@
|
|||
default: () => []
|
||||
}
|
||||
})
|
||||
const setRules = (v) => {
|
||||
switch (v.type) {
|
||||
case '0':
|
||||
return '*'
|
||||
case '1':
|
||||
return v.range.start + '-' + v.range.end
|
||||
case '2':
|
||||
return v.loop.start + '/' + v.loop.end
|
||||
case '3':
|
||||
return v.appoint.length > 0 ? v.appoint.join(',') : '*'
|
||||
case '4':
|
||||
return 'L'
|
||||
case '5':
|
||||
return '?'
|
||||
default:
|
||||
return '*'
|
||||
}
|
||||
}
|
||||
const value_second = computed(() => {
|
||||
let v = dateValue.value.second
|
||||
if (v.type === '0') {
|
||||
return '*'
|
||||
} else if (v.type === '1') {
|
||||
return v.range.start + '-' + v.range.end
|
||||
} else if (v.type === '2') {
|
||||
return v.loop.start + '/' + v.loop.end
|
||||
} else if (v.type === '3') {
|
||||
return v.appoint.length > 0 ? v.appoint.join(',') : '*'
|
||||
} else {
|
||||
return '*'
|
||||
}
|
||||
return setRules(v)
|
||||
})
|
||||
const value_minute = computed(() => {
|
||||
let v = dateValue.value.minute
|
||||
if (v.type === '0') {
|
||||
return '*'
|
||||
} else if (v.type === '1') {
|
||||
return v.range.start + '-' + v.range.end
|
||||
} else if (v.type === '2') {
|
||||
return v.loop.start + '/' + v.loop.end
|
||||
} else if (v.type === '3') {
|
||||
return v.appoint.length > 0 ? v.appoint.join(',') : '*'
|
||||
} else {
|
||||
return '*'
|
||||
}
|
||||
return setRules(v)
|
||||
})
|
||||
const value_hour = computed(() => {
|
||||
let v = dateValue.value.hour
|
||||
if (v.type === '0') {
|
||||
return '*'
|
||||
} else if (v.type === '1') {
|
||||
return v.range.start + '-' + v.range.end
|
||||
} else if (v.type === '2') {
|
||||
return v.loop.start + '/' + v.loop.end
|
||||
} else if (v.type === '3') {
|
||||
return v.appoint.length > 0 ? v.appoint.join(',') : '*'
|
||||
} else {
|
||||
return '*'
|
||||
}
|
||||
return setRules(v)
|
||||
})
|
||||
const value_day = computed(() => {
|
||||
let v = dateValue.value.day
|
||||
if (v.type === '0') {
|
||||
return '*'
|
||||
} else if (v.type === '1') {
|
||||
return v.range.start + '-' + v.range.end
|
||||
} else if (v.type === '2') {
|
||||
return v.loop.start + '/' + v.loop.end
|
||||
} else if (v.type === '3') {
|
||||
return v.appoint.length > 0 ? v.appoint.join(',') : '*'
|
||||
} else if (v.type === '4') {
|
||||
return 'L'
|
||||
} else if (v.type === '5') {
|
||||
return '?'
|
||||
} else {
|
||||
return '*'
|
||||
}
|
||||
return setRules(v)
|
||||
})
|
||||
const value_month = computed(() => {
|
||||
let v = dateValue.value.month
|
||||
if (v.type === '0') {
|
||||
return '*'
|
||||
} else if (v.type === '1') {
|
||||
return v.range.start + '-' + v.range.end
|
||||
} else if (v.type === '2') {
|
||||
return v.loop.start + '/' + v.loop.end
|
||||
} else if (v.type === '3') {
|
||||
return v.appoint.length > 0 ? v.appoint.join(',') : '*'
|
||||
} else {
|
||||
return '*'
|
||||
}
|
||||
return setRules(v)
|
||||
})
|
||||
const value_week = computed(() => {
|
||||
let v = dateValue.value.week
|
||||
if (v.type === '0') {
|
||||
return '*'
|
||||
} else if (v.type === '1') {
|
||||
return v.range.start + '-' + v.range.end
|
||||
} else if (v.type === '2') {
|
||||
return v.loop.end + '#' + v.loop.start
|
||||
} else if (v.type === '3') {
|
||||
return v.appoint.length > 0 ? v.appoint.join(',') : '*'
|
||||
} else if (v.type === '4') {
|
||||
return v.last + 'L'
|
||||
} else if (v.type === '5') {
|
||||
return '?'
|
||||
} else {
|
||||
return '*'
|
||||
}
|
||||
return setRules(v)
|
||||
})
|
||||
const value_year = computed(() => {
|
||||
let v = dateValue.value.year
|
||||
if (v.type === '-1') {
|
||||
return ''
|
||||
} else if (v.type === '0') {
|
||||
return '*'
|
||||
} else if (v.type === '1') {
|
||||
return v.range.start + '-' + v.range.end
|
||||
} else if (v.type === '2') {
|
||||
return v.loop.start + '/' + v.loop.end
|
||||
} else if (v.type === '3') {
|
||||
return v.appoint.length > 0 ? v.appoint.join(',') : ''
|
||||
} else {
|
||||
return ''
|
||||
switch (v.type) {
|
||||
case '-1':
|
||||
return ''
|
||||
case '0':
|
||||
return '*'
|
||||
case '1':
|
||||
return v.range.start + '-' + v.range.end
|
||||
case '2':
|
||||
return v.loop.start + '/' + v.loop.end
|
||||
case '3':
|
||||
return v.appoint.length > 0 ? v.appoint.join(',') : ''
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<a-modal
|
||||
:class="['my-modal', modalClass, simpleClass]"
|
||||
:visible="visible"
|
||||
v-bind="$props"
|
||||
v-bind="props"
|
||||
:width="modalWidth"
|
||||
:wrap-class-name="wrapClassName + fullscreenClass"
|
||||
@cancel="handleCancel"
|
||||
|
@ -27,284 +27,259 @@
|
|||
<slot name="insertFooter"></slot>
|
||||
<slot name="footer">
|
||||
<a-button @click="handleCancel">
|
||||
{{ $props.cancelText || '取消' }}
|
||||
{{ props.cancelText || '取消' }}
|
||||
</a-button>
|
||||
<slot name="centerFooter"></slot>
|
||||
<a-button type="primary" @click="handleOk" :loading="loading">
|
||||
{{ $props.okText || '确定' }}
|
||||
{{ props.okText || '确定' }}
|
||||
</a-button>
|
||||
</slot>
|
||||
<slot name="appendFooter"></slot>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
<script>
|
||||
import props from './props.js'
|
||||
|
||||
export default {
|
||||
name: 'DragModal',
|
||||
mixins: [props],
|
||||
props: {
|
||||
// 容器的类名
|
||||
modalClass: {
|
||||
type: String,
|
||||
default: 'modal-box'
|
||||
},
|
||||
// 对话框外层容器的类名
|
||||
wrapClassName: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
helpMessage: {
|
||||
type: String
|
||||
},
|
||||
// 可全屏
|
||||
fullscreen: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 可拖拽
|
||||
drag: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 可拉伸
|
||||
resize: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否显示
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 标题
|
||||
title: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
// 宽度
|
||||
width: {
|
||||
type: [Number, String],
|
||||
default: '70%'
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
}
|
||||
<script setup>
|
||||
import mixinProps from './props.js'
|
||||
import { useSlots } from 'vue'
|
||||
const slots = useSlots()
|
||||
const props = defineProps({
|
||||
...mixinProps,
|
||||
// 容器的类名
|
||||
modalClass: {
|
||||
type: String,
|
||||
default: 'modal-box'
|
||||
},
|
||||
emits: ['ok', 'close', 'fullscreen'],
|
||||
data() {
|
||||
return {
|
||||
modalWidth: '',
|
||||
contain: null,
|
||||
// 拖拽
|
||||
header: null,
|
||||
modalContent: null,
|
||||
mouseDownX: 0,
|
||||
mouseDownY: 0,
|
||||
deltaX: 0,
|
||||
deltaY: 0,
|
||||
sumX: 0,
|
||||
sumY: 0,
|
||||
onmousedown: false,
|
||||
// 缩放
|
||||
modalBody: null,
|
||||
myBody: null,
|
||||
prevModalWidth: 0,
|
||||
prevModalHeight: 0,
|
||||
prevBodyWidth: 0,
|
||||
prevBodyHeight: 0,
|
||||
startX: 0,
|
||||
startY: 0,
|
||||
// 全屏
|
||||
fullscreenClass: '',
|
||||
fullscreenStatus: false
|
||||
}
|
||||
// 对话框外层容器的类名
|
||||
wrapClassName: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
computed: {
|
||||
slotKeys() {
|
||||
return Object.keys(this.$slots)
|
||||
},
|
||||
simpleClass() {
|
||||
return Math.random().toString(36).substring(2)
|
||||
}
|
||||
helpMessage: {
|
||||
type: String
|
||||
},
|
||||
watch: {
|
||||
visible() {
|
||||
this.$nextTick(() => {
|
||||
this.initialEvent(this.visible)
|
||||
})
|
||||
},
|
||||
fullscreenStatus() {
|
||||
this.fullscreenClass = this.fullscreenStatus ? ' full-modal' : ''
|
||||
}
|
||||
// 可全屏
|
||||
fullscreen: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.initialEvent(this.visible)
|
||||
// 可拖拽
|
||||
drag: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 可拉伸
|
||||
resize: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否显示
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 标题
|
||||
title: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
// 宽度
|
||||
width: {
|
||||
type: [Number, String],
|
||||
default: '70%'
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['ok', 'close', 'fullscreen'])
|
||||
const modalWidth = ref('')
|
||||
const contain = ref(null)
|
||||
// 拖拽
|
||||
const header = ref(null)
|
||||
const modalContent = ref(null)
|
||||
const mouseDownX = ref(0)
|
||||
const mouseDownY = ref(0)
|
||||
const deltaX = ref(0)
|
||||
const deltaY = ref(0)
|
||||
const sumX = ref(0)
|
||||
const sumY = ref(0)
|
||||
const onmousedown = ref(false)
|
||||
// 缩放
|
||||
const modalBody = ref(null)
|
||||
const myBody = ref(null)
|
||||
const prevModalWidth = ref(0)
|
||||
const prevModalHeight = ref(0)
|
||||
const prevBodyWidth = ref(0)
|
||||
const prevBodyHeight = ref(0)
|
||||
const startX = ref(0)
|
||||
const startY = ref(0)
|
||||
// 全屏
|
||||
const fullscreenClass = ref('')
|
||||
const fullscreenStatus = ref(false)
|
||||
const slotKeys = computed(() => {
|
||||
return Object.keys(slots)
|
||||
})
|
||||
const simpleClass = computed(() => {
|
||||
return Math.random().toString(36).substring(2)
|
||||
})
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
initialEvent(props.visible)
|
||||
})
|
||||
})
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newValue) => {
|
||||
nextTick(() => {
|
||||
initialEvent(props.visible)
|
||||
})
|
||||
},
|
||||
created() {},
|
||||
beforeUnmount() {
|
||||
this.removeMove()
|
||||
document.removeEventListener('mouseup', this.removeUp, false)
|
||||
this.removeResize()
|
||||
document.removeEventListener('mouseup', this.removeResize)
|
||||
},
|
||||
methods: {
|
||||
changeWidth(width) {
|
||||
this.modalWidth = width
|
||||
},
|
||||
handleFullScreen(e) {
|
||||
e?.stopPropagation()
|
||||
e?.preventDefault()
|
||||
}
|
||||
)
|
||||
watch(
|
||||
() => fullscreenStatus.value,
|
||||
(newValue) => {
|
||||
fullscreenClass.value = fullscreenStatus.value ? ' full-modal' : ''
|
||||
}
|
||||
)
|
||||
onBeforeUnmount(() => {
|
||||
removeMove()
|
||||
document.removeEventListener('mouseup', removeUp, false)
|
||||
removeResize()
|
||||
document.removeEventListener('mouseup', removeResize)
|
||||
})
|
||||
const changeWidth = (width) => {
|
||||
modalWidth.value = width
|
||||
}
|
||||
const handleFullScreen = (e) => {
|
||||
e?.stopPropagation()
|
||||
e?.preventDefault()
|
||||
|
||||
this.fullscreenStatus = !this.fullscreenStatus
|
||||
this.$emit('fullscreen', e)
|
||||
},
|
||||
handleOk(e) {
|
||||
this.reset()
|
||||
this.$emit('ok', e)
|
||||
},
|
||||
handleCancel(e) {
|
||||
const classList = e.target?.classList
|
||||
// 过滤自定义关闭按钮的空白区域
|
||||
if (classList.contains('ant-modal-close-x') || classList.contains('ant-space-item')) {
|
||||
return
|
||||
fullscreenStatus.value = !fullscreenStatus.value
|
||||
emit('fullscreen', e)
|
||||
}
|
||||
const handleOk = (e) => {
|
||||
reset()
|
||||
emit('ok', e)
|
||||
}
|
||||
const handleCancel = (e) => {
|
||||
const classList = e.target?.classList
|
||||
// 过滤自定义关闭按钮的空白区域
|
||||
if (classList.contains('ant-modal-close-x') || classList.contains('ant-space-item')) {
|
||||
return
|
||||
}
|
||||
reset()
|
||||
emit('close', e)
|
||||
}
|
||||
const reset = () => {
|
||||
// 拖拽
|
||||
mouseDownX.value = 0
|
||||
mouseDownY.value = 0
|
||||
deltaX.value = 0
|
||||
deltaY.value = 0
|
||||
sumX.value = 0
|
||||
sumY.value = 0
|
||||
// 缩放
|
||||
prevModalWidth.value = 0
|
||||
prevModalHeight.value = 0
|
||||
prevBodyWidth.value = 0
|
||||
prevBodyHeight.value = 0
|
||||
startX.value = 0
|
||||
startY.value = 0
|
||||
// 全屏
|
||||
fullscreenStatus.value = false
|
||||
}
|
||||
const initialEvent = (visible) => {
|
||||
if (visible) {
|
||||
reset()
|
||||
// 获取控件
|
||||
document.removeEventListener('mouseup', removeUp, false)
|
||||
contain.value = document.getElementsByClassName(simpleClass.value)[0]
|
||||
changeWidth(props.width)
|
||||
if (props.drag === true) {
|
||||
header.value = contain.value.getElementsByClassName('ant-modal-header')[0]
|
||||
modalContent.value = contain.value.getElementsByClassName('ant-modal-content')[0]
|
||||
header.value.style.cursor = 'all-scroll'
|
||||
modalContent.value.style.left = 0
|
||||
modalContent.value.style.transform = 'translate(0px,0px)'
|
||||
// 拖拽事件监听
|
||||
header.value.onmousedown = (event) => {
|
||||
onmousedown.value = true
|
||||
mouseDownX.value = event.pageX
|
||||
mouseDownY.value = event.pageY
|
||||
document.body.onselectstart = () => false
|
||||
document.addEventListener('mousemove', handleMove, false)
|
||||
}
|
||||
this.reset()
|
||||
this.$emit('close', e)
|
||||
},
|
||||
reset() {
|
||||
// 拖拽
|
||||
this.mouseDownX = 0
|
||||
this.mouseDownY = 0
|
||||
this.deltaX = 0
|
||||
this.deltaY = 0
|
||||
this.sumX = 0
|
||||
this.sumY = 0
|
||||
// 缩放
|
||||
this.prevModalWidth = 0
|
||||
this.prevModalHeight = 0
|
||||
this.prevBodyWidth = 0
|
||||
this.prevBodyHeight = 0
|
||||
this.startX = 0
|
||||
this.startY = 0
|
||||
// 全屏
|
||||
this.fullscreenStatus = false
|
||||
},
|
||||
initialEvent(visible) {
|
||||
// console.log('--------- 初始化')
|
||||
// console.log('simpleClass===>', this.simpleClass)
|
||||
// console.log('document===>', document)
|
||||
if (visible) {
|
||||
this.reset()
|
||||
// 获取控件
|
||||
document.removeEventListener('mouseup', this.removeUp, false)
|
||||
this.contain = document.getElementsByClassName(this.simpleClass)[0]
|
||||
// console.log('初始化-contain:', this.contain)
|
||||
this.changeWidth(this.$props.width)
|
||||
if (this.$props.drag === true) {
|
||||
this.header = this.contain.getElementsByClassName('ant-modal-header')[0]
|
||||
this.modalContent = this.contain.getElementsByClassName('ant-modal-content')[0]
|
||||
this.header.style.cursor = 'all-scroll'
|
||||
this.modalContent.style.left = 0
|
||||
this.modalContent.style.transform = 'translate(0px,0px)'
|
||||
// console.log('初始化-header:', this.header)
|
||||
// console.log('初始化-modalContent:', this.modalContent)
|
||||
// 拖拽事件监听
|
||||
// this.contain.onmousedown = (event) => {
|
||||
this.header.onmousedown = (event) => {
|
||||
this.onmousedown = true
|
||||
this.mouseDownX = event.pageX
|
||||
this.mouseDownY = event.pageY
|
||||
document.body.onselectstart = () => false
|
||||
document.addEventListener('mousemove', this.handleMove, false)
|
||||
}
|
||||
document.addEventListener('mouseup', this.removeUp, false)
|
||||
}
|
||||
|
||||
if (this.$props.resize === true) {
|
||||
this.modalBody = this.contain.getElementsByClassName('ant-modal-content')[0]
|
||||
this.myBody = this.contain.getElementsByClassName('ant-modal-body')[0]
|
||||
this.modalBody.style.overflow = 'hidden'
|
||||
this.modalBody.style.resize = 'both'
|
||||
this.myBody.style.overflow = 'auto'
|
||||
this.myBody.style.height = 'auto'
|
||||
// console.log('初始化-modalBody:', this.modalBody)
|
||||
// console.log('初始化-myBody:', this.myBody)
|
||||
// 缩放事件监听
|
||||
this.modalBody.onmousedown = (event) => {
|
||||
event.preventDefault()
|
||||
const rect = this.modalBody.getBoundingClientRect()
|
||||
const rightBorder = rect.x + rect.width - 17
|
||||
const bottomBorder = rect.y + rect.height - 17
|
||||
// console.log('rightBorder:' + rightBorder, 'clientX:' + event.clientX)
|
||||
// console.log('bottomBorder:' + bottomBorder, 'clientY:' + event.clientY)
|
||||
if (event.clientX >= rightBorder && event.clientY >= bottomBorder) {
|
||||
this.prevModalWidth = this.modalBody.offsetWidth
|
||||
this.prevModalHeight = this.modalBody.offsetHeight
|
||||
this.prevBodyWidth = this.myBody.offsetWidth
|
||||
this.prevBodyHeight = this.myBody.offsetHeight
|
||||
this.startX = event.clientX
|
||||
this.startY = event.clientY
|
||||
|
||||
document.addEventListener('mousemove', this.handleResize)
|
||||
}
|
||||
document.addEventListener('mouseup', this.removeResize)
|
||||
}
|
||||
document.addEventListener('mouseup', removeUp, false)
|
||||
}
|
||||
|
||||
if (props.resize === true) {
|
||||
modalBody.value = contain.value.getElementsByClassName('ant-modal-content')[0]
|
||||
myBody.value = contain.value.getElementsByClassName('ant-modal-body')[0]
|
||||
modalBody.value.style.overflow = 'hidden'
|
||||
modalBody.value.style.resize = 'both'
|
||||
myBody.value.style.overflow = 'auto'
|
||||
myBody.value.style.height = 'auto'
|
||||
// 缩放事件监听
|
||||
modalBody.value.onmousedown = (event) => {
|
||||
event.preventDefault()
|
||||
const rect = modalBody.value.getBoundingClientRect()
|
||||
const rightBorder = rect.x + rect.width - 17
|
||||
const bottomBorder = rect.y + rect.height - 17
|
||||
if (event.clientX >= rightBorder && event.clientY >= bottomBorder) {
|
||||
prevModalWidth.value = modalBody.value.offsetWidth
|
||||
prevModalHeight.value = modalBody.value.offsetHeight
|
||||
prevBodyWidth.value = myBody.value.offsetWidth
|
||||
prevBodyHeight.value = myBody.value.offsetHeight
|
||||
startX.value = event.clientX
|
||||
startY.value = event.clientY
|
||||
document.addEventListener('mousemove', handleResize)
|
||||
}
|
||||
document.addEventListener('mouseup', removeResize)
|
||||
}
|
||||
},
|
||||
handleMove(event) {
|
||||
if (this.fullscreenStatus) {
|
||||
return
|
||||
}
|
||||
const delta1X = event.pageX - this.mouseDownX
|
||||
const delta1Y = event.pageY - this.mouseDownY
|
||||
this.deltaX = delta1X
|
||||
this.deltaY = delta1Y
|
||||
// console.log('delta1X:' + delta1X, 'sumX:' + this.sumX, 'delta1Y:' + delta1Y, 'sumY:' + this.sumY)
|
||||
this.modalContent.style.transform = `translate(${delta1X + this.sumX}px, ${delta1Y + this.sumY}px)`
|
||||
},
|
||||
removeMove() {
|
||||
document.removeEventListener('mousemove', this.handleMove, false)
|
||||
},
|
||||
removeUp(event) {
|
||||
document.body.onselectstart = () => true
|
||||
if (this.onmousedown && !(event.pageX === this.mouseDownX && event.pageY === this.mouseDownY)) {
|
||||
this.onmousedown = false
|
||||
this.sumX = this.sumX + this.deltaX
|
||||
this.sumY = this.sumY + this.deltaY
|
||||
// console.log('sumX:' + this.sumX, 'sumY:' + this.sumY)
|
||||
}
|
||||
this.removeMove()
|
||||
// this.checkMove()
|
||||
},
|
||||
handleResize(event) {
|
||||
if (this.fullscreenStatus) {
|
||||
return
|
||||
}
|
||||
const diffX = event.clientX - this.startX
|
||||
const diffY = event.clientY - this.startY
|
||||
const minWidth = 180
|
||||
const minHeight = 0
|
||||
|
||||
if (this.prevBodyWidth + diffX > minWidth) {
|
||||
this.changeWidth(this.prevModalWidth + diffX + 'px')
|
||||
// this.myBody.style.width = this.prevBodyWidth + diffX + 'px'
|
||||
}
|
||||
if (this.prevBodyHeight + diffY > minHeight) {
|
||||
// this.modalBody.style.height = this.prevModalHeight + diffY + 'px'
|
||||
this.myBody.style.height = this.prevBodyHeight + diffY + 'px'
|
||||
}
|
||||
},
|
||||
removeResize() {
|
||||
document.removeEventListener('mousemove', this.handleResize)
|
||||
}
|
||||
}
|
||||
}
|
||||
const handleMove = (event) => {
|
||||
if (fullscreenStatus.value) {
|
||||
return
|
||||
}
|
||||
const delta1X = event.pageX - mouseDownX.value
|
||||
const delta1Y = event.pageY - mouseDownY.value
|
||||
deltaX.value = delta1X
|
||||
deltaY.value = delta1Y
|
||||
modalContent.value.style.transform = `translate(${delta1X + sumX.value}px, ${delta1Y + sumY.value}px)`
|
||||
}
|
||||
const removeMove = () => {
|
||||
document.removeEventListener('mousemove', handleMove, false)
|
||||
}
|
||||
const removeUp = (event) => {
|
||||
document.body.onselectstart = () => true
|
||||
if (onmousedown.value && !(event.pageX === mouseDownX.value && event.pageY === mouseDownY.value)) {
|
||||
onmousedown.value = false
|
||||
sumX.value = sumX.value + deltaX.value
|
||||
sumY.value = sumY.value + deltaY.value
|
||||
}
|
||||
removeMove()
|
||||
}
|
||||
const handleResize = (event) => {
|
||||
if (fullscreenStatus.value) {
|
||||
return
|
||||
}
|
||||
const diffX = event.clientX - startX.value
|
||||
const diffY = event.clientY - startY.value
|
||||
const minWidth = 180
|
||||
const minHeight = 0
|
||||
if (prevBodyWidth.value + diffX > minWidth) {
|
||||
changeWidth(prevModalWidth.value + diffX + 'px')
|
||||
}
|
||||
if (prevBodyHeight.value + diffY > minHeight) {
|
||||
myBody.value.style.height = prevBodyHeight.value + diffY + 'px'
|
||||
}
|
||||
}
|
||||
const removeResize = () => {
|
||||
document.removeEventListener('mousemove', handleResize)
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
.ant-modal-close-x {
|
||||
|
|
|
@ -8,12 +8,7 @@
|
|||
|
||||
```javascript
|
||||
import Ellipsis from '@/components/Ellipsis'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Ellipsis
|
||||
}
|
||||
}
|
||||
// vue3 不需要利用compoents去注册组件,引入后可直接使用
|
||||
```
|
||||
|
||||
|
||||
|
|
|
@ -1,50 +1,48 @@
|
|||
<script lang="jsx">
|
||||
<template>
|
||||
<ellipsis />
|
||||
</template>
|
||||
<script setup>
|
||||
import { h } from 'vue'
|
||||
import Tooltip from 'ant-design-vue/es/tooltip'
|
||||
import { cutStrByFullLength, getStrFullLength } from './util'
|
||||
import { useSlots } from 'vue'
|
||||
const slots = useSlots()
|
||||
|
||||
export default {
|
||||
name: 'Ellipsis',
|
||||
components: {
|
||||
Tooltip
|
||||
const props = defineProps({
|
||||
prefixCls: {
|
||||
type: String,
|
||||
default: 'ant-pro-ellipsis'
|
||||
},
|
||||
props: {
|
||||
prefixCls: {
|
||||
type: String,
|
||||
default: 'ant-pro-ellipsis'
|
||||
},
|
||||
tooltip: {
|
||||
type: Boolean
|
||||
},
|
||||
length: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
lines: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
fullWidthRecognition: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
tooltip: {
|
||||
type: Boolean
|
||||
},
|
||||
methods: {
|
||||
getStrDom(str, fullLength) {
|
||||
return <span>{cutStrByFullLength(str, this.length) + (fullLength > this.length ? '...' : '')}</span>
|
||||
},
|
||||
getTooltip(fullStr, fullLength) {
|
||||
return <Tooltip title={fullStr}>{this.getStrDom(fullStr, fullLength)}</Tooltip>
|
||||
}
|
||||
length: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
render() {
|
||||
const { tooltip, length } = this.$props
|
||||
const str = this.$slots
|
||||
.default()
|
||||
.map((vNode) => vNode.children)
|
||||
.join('')
|
||||
const fullLength = getStrFullLength(str)
|
||||
const strDom = tooltip && fullLength > length ? this.getTooltip(str, fullLength) : this.getStrDom(str, fullLength)
|
||||
return strDom
|
||||
lines: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
fullWidthRecognition: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const str = slots
|
||||
.default()
|
||||
.map((vNode) => vNode.children)
|
||||
.join('')
|
||||
|
||||
const fullLength = getStrFullLength(str)
|
||||
const showStr = cutStrByFullLength(str, props.length) + (fullLength > props.length ? '...' : '')
|
||||
|
||||
// 使用h函数注册渲染一个组件
|
||||
const ellipsis = () => {
|
||||
return props.tooltip && fullLength > props.length
|
||||
? h(Tooltip, { title: str }, { default: () => showStr })
|
||||
: // 引用组件时,需要设置默认值 default: () => xxx
|
||||
h('span', showStr)
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="baiduMap" :style="{height: `${height}px`}">
|
||||
<div class="baiduMap" :style="{ height: `${height}px` }">
|
||||
<div :id="`container-${mid}`" style="width: 100%; height: 100%">地图资源加载中...</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -25,6 +25,7 @@
|
|||
},
|
||||
plugins: {
|
||||
type: Array,
|
||||
// eslint-disable-next-line vue/require-valid-default-prop
|
||||
default: ['BMap.ScaleControl', 'BMap.ZoomControl', 'BMap.LocationControl', 'BMap.NavigationControl3D']
|
||||
},
|
||||
viewMode: {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="gaodeMap" :style="{height: `${height}px`}">
|
||||
<div class="gaodeMap" :style="{ height: `${height}px` }">
|
||||
<div :id="`container-${mid}`" style="width: 100%; height: 100%">地图资源加载中...</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -26,6 +26,7 @@
|
|||
},
|
||||
plugins: {
|
||||
type: Array,
|
||||
// eslint-disable-next-line vue/require-valid-default-prop
|
||||
default: ['AMap.ToolBar', 'AMap.Scale', 'AMap.HawkEye', 'AMap.MapType', 'AMap.Geolocation', 'AMap.MarkerCluster']
|
||||
},
|
||||
viewMode: {
|
||||
|
|
|
@ -36,70 +36,72 @@
|
|||
</a-tabs>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import config from '@/assets/icons/mobile'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
iconData: [],
|
||||
modelValue: '',
|
||||
activeKey: 'default',
|
||||
iconItemDefault: 'default'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.iconData.push(...config.icons)
|
||||
},
|
||||
methods: {
|
||||
// 打开
|
||||
showIconModal(value) {
|
||||
this.visible = true
|
||||
this.defaultSetting(value)
|
||||
},
|
||||
// 默认配置
|
||||
defaultSetting(value) {
|
||||
if (value) {
|
||||
this.modelValue = value
|
||||
// 判断展开哪个
|
||||
if (value.indexOf('-outlined') > -1 || value.indexOf('-filled') > -1 || value.indexOf('-two-tone') > -1) {
|
||||
this.activeKey = 'default'
|
||||
if (value.indexOf('-two-tone') > -1) {
|
||||
this.iconItemDefault = 'twotone'
|
||||
} else if (value.indexOf('-filled') > -1) {
|
||||
this.iconItemDefault = 'filled'
|
||||
}
|
||||
} else if (value.indexOf('-extend') > -1) {
|
||||
// 扩展列表
|
||||
this.activeKey = 'extend'
|
||||
// 如扩展其他顶部单选的情况,默认选中在这里配置,同时这里需要做判断
|
||||
// this.iconItemDefault = '您的json中配置的'
|
||||
}
|
||||
const visible = ref(false)
|
||||
const iconData = ref([])
|
||||
const modelValue = ref('')
|
||||
const activeKey = ref('default')
|
||||
const iconItemDefault = ref('default')
|
||||
|
||||
onMounted(() => {
|
||||
iconData.value.push(...config.icons)
|
||||
})
|
||||
|
||||
// 打开
|
||||
const showIconModal = (value) => {
|
||||
visible.value = true
|
||||
defaultSetting(value)
|
||||
}
|
||||
|
||||
// 暴露子组件的方法
|
||||
defineExpose({
|
||||
showIconModal
|
||||
})
|
||||
// 默认配置
|
||||
const defaultSetting = (value) => {
|
||||
if (value) {
|
||||
modelValue.value = value
|
||||
// 判断展开哪个
|
||||
if (value.indexOf('-outlined') > -1 || value.indexOf('-filled') > -1 || value.indexOf('-two-tone') > -1) {
|
||||
activeKey.value = 'default'
|
||||
if (value.indexOf('-two-tone') > -1) {
|
||||
iconItemDefault.value = 'twotone'
|
||||
} else if (value.indexOf('-filled') > -1) {
|
||||
iconItemDefault.value = 'filled'
|
||||
}
|
||||
},
|
||||
// 切换标签页,如果是切换到了没用额外的标签页的地方,我们将其置为默认
|
||||
paneChange(e) {
|
||||
if (e.indexOf('default') === -1) {
|
||||
this.iconItemDefault = 'default'
|
||||
}
|
||||
},
|
||||
// 切换icon风格
|
||||
radioGroupChange(e) {
|
||||
this.iconItemDefault = e.target.value
|
||||
},
|
||||
// 选择图标后关闭并返回
|
||||
selectIcon(value) {
|
||||
this.defaultValue = value
|
||||
this.visible = false
|
||||
// eslint-disable-next-line vue/require-explicit-emits
|
||||
this.$emit('iconCallBack', this.defaultValue)
|
||||
},
|
||||
onCancel() {
|
||||
this.visible = false
|
||||
} else if (value.indexOf('-extend') > -1) {
|
||||
// 扩展列表
|
||||
activeKey.value = 'extend'
|
||||
// 如扩展其他顶部单选的情况,默认选中在这里配置,同时这里需要做判断
|
||||
// this.iconItemDefault = '您的json中配置的'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 切换标签页,如果是切换到了没用额外的标签页的地方,我们将其置为默认
|
||||
const paneChange = (e) => {
|
||||
if (e.indexOf('default') === -1) {
|
||||
iconItemDefault.value = 'default'
|
||||
}
|
||||
}
|
||||
|
||||
// 切换icon风格
|
||||
const radioGroupChange = (e) => {
|
||||
iconItemDefault.value = e.target.value
|
||||
}
|
||||
const emit = defineEmits(['iconCallBack'])
|
||||
|
||||
// 选择图标后关闭并返回
|
||||
const selectIcon = (value) => {
|
||||
visible.value = false
|
||||
// eslint-disable-next-line vue/require-explicit-emits
|
||||
emit('iconCallBack', value)
|
||||
}
|
||||
|
||||
const onCancel = () => {
|
||||
visible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -36,70 +36,73 @@
|
|||
</a-tabs>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import config from '@/config/iconSelect'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
iconData: [],
|
||||
modelValue: '',
|
||||
activeKey: 'default',
|
||||
iconItemDefault: 'default'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.iconData.push(...config.icons)
|
||||
},
|
||||
methods: {
|
||||
// 打开
|
||||
showIconModal(value) {
|
||||
this.visible = true
|
||||
this.defaultSetting(value)
|
||||
},
|
||||
// 默认配置
|
||||
defaultSetting(value) {
|
||||
if (value) {
|
||||
this.modelValue = value
|
||||
// 判断展开哪个
|
||||
if (value.indexOf('-outlined') > -1 || value.indexOf('-filled') > -1 || value.indexOf('-two-tone') > -1) {
|
||||
this.activeKey = 'default'
|
||||
if (value.indexOf('-two-tone') > -1) {
|
||||
this.iconItemDefault = 'twotone'
|
||||
} else if (value.indexOf('-filled') > -1) {
|
||||
this.iconItemDefault = 'filled'
|
||||
}
|
||||
} else if (value.indexOf('-extend') > -1) {
|
||||
// 扩展列表
|
||||
this.activeKey = 'extend'
|
||||
// 如扩展其他顶部单选的情况,默认选中在这里配置,同时这里需要做判断
|
||||
// this.iconItemDefault = '您的json中配置的'
|
||||
}
|
||||
const visible = ref(false)
|
||||
const iconData = ref([])
|
||||
const modelValue = ref('')
|
||||
const activeKey = ref('default')
|
||||
const iconItemDefault = ref('default')
|
||||
|
||||
onMounted(() => {
|
||||
iconData.value.push(...config.icons)
|
||||
})
|
||||
|
||||
// 打开
|
||||
const showIconModal = (value) => {
|
||||
visible.value = true
|
||||
defaultSetting(value)
|
||||
}
|
||||
|
||||
// 暴露子组件的方法
|
||||
defineExpose({
|
||||
showIconModal
|
||||
})
|
||||
|
||||
// 默认配置
|
||||
const defaultSetting = (value) => {
|
||||
if (value) {
|
||||
modelValue.value = value
|
||||
// 判断展开哪个
|
||||
if (value.indexOf('-outlined') > -1 || value.indexOf('-filled') > -1 || value.indexOf('-two-tone') > -1) {
|
||||
activeKey.value = 'default'
|
||||
if (value.indexOf('-two-tone') > -1) {
|
||||
iconItemDefault.value = 'twotone'
|
||||
} else if (value.indexOf('-filled') > -1) {
|
||||
iconItemDefault.value = 'filled'
|
||||
}
|
||||
},
|
||||
// 切换标签页,如果是切换到了没用额外的标签页的地方,我们将其置为默认
|
||||
paneChange(e) {
|
||||
if (e.indexOf('default') === -1) {
|
||||
this.iconItemDefault = 'default'
|
||||
}
|
||||
},
|
||||
// 切换icon风格
|
||||
radioGroupChange(e) {
|
||||
this.iconItemDefault = e.target.value
|
||||
},
|
||||
// 选择图标后关闭并返回
|
||||
selectIcon(value) {
|
||||
this.defaultValue = value
|
||||
this.visible = false
|
||||
// eslint-disable-next-line vue/require-explicit-emits
|
||||
this.$emit('iconCallBack', this.defaultValue)
|
||||
},
|
||||
onCancel() {
|
||||
this.visible = false
|
||||
} else if (value.indexOf('-extend') > -1) {
|
||||
// 扩展列表
|
||||
activeKey.value = 'extend'
|
||||
// 如扩展其他顶部单选的情况,默认选中在这里配置,同时这里需要做判断
|
||||
// this.iconItemDefault = '您的json中配置的'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 切换标签页,如果是切换到了没用额外的标签页的地方,我们将其置为默认
|
||||
const paneChange = (e) => {
|
||||
if (e.indexOf('default') === -1) {
|
||||
iconItemDefault.value = 'default'
|
||||
}
|
||||
}
|
||||
|
||||
// 切换icon风格
|
||||
const radioGroupChange = (e) => {
|
||||
iconItemDefault.value = e.target.value
|
||||
}
|
||||
const emit = defineEmits(['iconCallBack'])
|
||||
|
||||
// 选择图标后关闭并返回
|
||||
const selectIcon = (value) => {
|
||||
visible.value = false
|
||||
// eslint-disable-next-line vue/require-explicit-emits
|
||||
emit('iconCallBack', value)
|
||||
}
|
||||
|
||||
const onCancel = () => {
|
||||
visible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -13,29 +13,23 @@ iconSelector
|
|||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<a-button type="primary" @click="$refs.iconselector.showModal(iconValue)">选择</a-button>
|
||||
<icon-selector ref="iconselector" @callBack="iconCallBack"/>
|
||||
<a-button type="primary" @click="openIcon(iconValue)">选择</a-button>
|
||||
<icon-selector ref="iconselector" @iconCallBack="iconCallBack" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import iconSelector from '@/components/Selector/iconSelector.vue'
|
||||
<script setup>
|
||||
const iconselector = ref() // 绑定ref="iconselector"
|
||||
|
||||
// 打开icon选择器
|
||||
const openIcon = (iconValue) => {
|
||||
iconselector.value.showIconModal(iconValue)
|
||||
}
|
||||
// 选择后回调
|
||||
const iconCallBack = (value) => {
|
||||
console.log('iconCallBack Icon', value)
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'YourView',
|
||||
components: {
|
||||
iconSelector
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
iconCallBack (icon) {
|
||||
console.log('iconCallBack Icon', icon)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
</div>
|
||||
<div class="org-table">
|
||||
<a-table
|
||||
ref="table"
|
||||
ref="tableRef"
|
||||
size="small"
|
||||
:columns="commons"
|
||||
:data-source="tableData"
|
||||
|
@ -143,7 +143,7 @@
|
|||
}
|
||||
]
|
||||
// 主表格的ref 名称
|
||||
const table = ref()
|
||||
const tableRef = ref()
|
||||
// 选中表格的ref 名称
|
||||
const selectedTable = ref()
|
||||
const tableRecordNum = ref()
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
</div>
|
||||
<div class="pos-table">
|
||||
<a-table
|
||||
ref="table"
|
||||
ref="tableRef"
|
||||
size="small"
|
||||
:columns="commons"
|
||||
:data-source="tableData"
|
||||
|
@ -143,7 +143,7 @@
|
|||
}
|
||||
]
|
||||
// 主表格的ref 名称
|
||||
const table = ref()
|
||||
const tableRef = ref()
|
||||
// 选中表格的ref 名称
|
||||
const selectedTable = ref()
|
||||
const tableRecordNum = ref()
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
</div>
|
||||
<div class="role-table">
|
||||
<a-table
|
||||
ref="table"
|
||||
ref="tableRef"
|
||||
size="small"
|
||||
:columns="commons"
|
||||
:data-source="tableData"
|
||||
|
@ -143,7 +143,7 @@
|
|||
}
|
||||
]
|
||||
// 主表格的ref 名称
|
||||
const table = ref()
|
||||
const tableRef = ref()
|
||||
// 选中表格的ref 名称
|
||||
const selectedTable = ref()
|
||||
const tableRecordNum = ref()
|
||||
|
@ -192,10 +192,13 @@
|
|||
}
|
||||
})
|
||||
// 是否是单选
|
||||
// eslint-disable-next-line vue/no-setup-props-destructure
|
||||
const radioModel = props.radioModel
|
||||
// 数据是否转换成工作流格式
|
||||
// eslint-disable-next-line vue/no-setup-props-destructure
|
||||
const dataIsConverterFlw = props.dataIsConverterFlw
|
||||
// 是否展示‘全局’这个节点
|
||||
// eslint-disable-next-line vue/no-setup-props-destructure
|
||||
const roleGlobal = props.roleGlobal
|
||||
// 分页相关
|
||||
const current = ref(0) // 当前页数
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
</div>
|
||||
<div class="user-table">
|
||||
<a-table
|
||||
ref="table"
|
||||
ref="tableRef"
|
||||
size="small"
|
||||
:columns="commons"
|
||||
:data-source="tableData"
|
||||
|
@ -143,7 +143,7 @@
|
|||
}
|
||||
]
|
||||
// 主表格的ref 名称
|
||||
const table = ref()
|
||||
const tableRef = ref()
|
||||
// 选中表格的ref 名称
|
||||
const selectedTable = ref()
|
||||
const tableRecordNum = ref()
|
||||
|
|
|
@ -39,16 +39,10 @@
|
|||
switch (arguments.length) {
|
||||
case 1:
|
||||
return parseInt(Math.random() * minNum + 1, 10)
|
||||
// eslint-disable-next-line no-unreachable
|
||||
break
|
||||
case 2:
|
||||
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10)
|
||||
// eslint-disable-next-line no-unreachable
|
||||
break
|
||||
default:
|
||||
return 0
|
||||
// eslint-disable-next-line no-unreachable
|
||||
break
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -21,7 +21,7 @@ Table 重封装组件说明
|
|||
|
||||
<template>
|
||||
<s-table
|
||||
ref="table"
|
||||
ref="tableRef"
|
||||
:rowKey="(record) => record.data.id"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
|
@ -99,94 +99,80 @@ export default {
|
|||
|
||||
```vue
|
||||
<template>
|
||||
<s-table
|
||||
ref="table"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
>
|
||||
<span slot="action" slot-scope="text, record">
|
||||
<a>编辑</a>
|
||||
<a-divider type="vertical"/>
|
||||
<a-dropdown>
|
||||
<a class="ant-dropdown-link">
|
||||
更多 <a-icon type="down"/>
|
||||
</a>
|
||||
<a-menu slot="overlay">
|
||||
<a-menu-item>
|
||||
<a href="javascript:;">1st menu item</a>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a href="javascript:;">2nd menu item</a>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a href="javascript:;">3rd menu item</a>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
</span>
|
||||
<s-table ref="tableRef" :columns="columns" :data="loadData" :alert="false" bordered :row-key="(record) => record.id">
|
||||
<!-- #operator 插槽可以放入一些关于表格的操作,比如新增数据。 -->
|
||||
<template #operator class="table-operator">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="">
|
||||
<template #icon><plus-outlined /></template>
|
||||
新增
|
||||
</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
<!-- #bodyCell 放入column表格列需要显示的数据,可以通过判断进行一个自定义显示 -->
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template >
|
||||
<a-avatar style="width: 25px; height: 25px" />
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'status'">
|
||||
<!-- 进行自定义显示内容 -->
|
||||
</template>
|
||||
<!-- column.dataIndex === 'action' 时,可以进行编辑删除等关于这行数据的一个操作,操作内容可进行自定义 -->
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<a @click="">编辑</a>
|
||||
</template>
|
||||
</template>
|
||||
</s-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import STable from '@/components/table/'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
STable,
|
||||
const tableRef = ref() //一定要进行一个表格的ref绑定
|
||||
const columns = ref([
|
||||
{
|
||||
title: '规则编号',
|
||||
dataIndex: 'no',
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
columns: [
|
||||
{
|
||||
title: '规则编号',
|
||||
dataIndex: 'no',
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'description',
|
||||
},
|
||||
{
|
||||
title: '服务调用次数',
|
||||
dataIndex: 'callNo',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
dataIndex: 'updatedAt',
|
||||
},
|
||||
{
|
||||
table: '操作',
|
||||
dataIndex: 'action',
|
||||
scopedSlots: { customRender: 'action' },
|
||||
},
|
||||
],
|
||||
// 查询条件参数
|
||||
queryParam: {},
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: (parameter) => {
|
||||
return this.$http.get('/service', {
|
||||
params: Object.assign(parameter, this.queryParam),
|
||||
}).then((res) => {
|
||||
return res.result
|
||||
})
|
||||
},
|
||||
}
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'description',
|
||||
},
|
||||
methods: {
|
||||
edit(row) {
|
||||
// axios 发送数据到后端 修改数据成功后
|
||||
// 调用 refresh() 重新加载列表数据
|
||||
// 这里 setTimeout 模拟发起请求的网络延迟..
|
||||
setTimeout(() => {
|
||||
this.$refs.table.refresh() // refresh() 不传参默认值 false 不刷新到分页第一页
|
||||
}, 1500)
|
||||
|
||||
},
|
||||
{
|
||||
title: '服务调用次数',
|
||||
dataIndex: 'callNo',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
dataIndex: 'updatedAt',
|
||||
},
|
||||
{
|
||||
table: '操作',
|
||||
dataIndex: 'action',
|
||||
scopedSlots: { customRender: 'action' },
|
||||
},
|
||||
])
|
||||
const queryParam = ref({})
|
||||
// 加载按钮数据
|
||||
const loadData = (parameter) => {
|
||||
return this.$http.get('/service', {
|
||||
params: Object.assign(parameter, queryParam.value),
|
||||
}).then((res) => {
|
||||
return res.result
|
||||
})
|
||||
}
|
||||
const edit = (row) => {
|
||||
// axios 发送数据到后端 修改数据成功后
|
||||
// 调用 refresh() 重新加载列表数据
|
||||
// 这里 setTimeout 模拟发起请求的网络延迟..
|
||||
setTimeout(() => {
|
||||
tableRef.value.refresh() // refresh() 不传参默认值 false 不刷新到分页第一页
|
||||
}, 1500)
|
||||
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
|
@ -195,9 +181,9 @@ export default {
|
|||
内置方法
|
||||
----
|
||||
|
||||
通过 `this.$refs.table` 调用
|
||||
通过 `声明的ref去调用 ==> tableRef.value` 调用
|
||||
|
||||
`this.$refs.table.refresh(true)` 刷新列表 (用户新增/修改数据后,重载列表数据)
|
||||
`tableRef.value.refresh(true)` 刷新列表 (用户新增/修改数据后,重载列表数据)
|
||||
|
||||
> 注意:要调用 `refresh(bool)` 需要给表格组件设定 `ref` 值
|
||||
>
|
||||
|
@ -233,39 +219,83 @@ alert: {
|
|||
>
|
||||
> 文档中的结构有可能由于组件 bug 进行修正而改动。实际修改请以当时最新版本为准
|
||||
|
||||
修改 `@/components/table/index.js` 第 156 行起
|
||||
修改 `@/components/table/index.js` 第 348 行起
|
||||
|
||||
|
||||
|
||||
```javascript
|
||||
result.then(r => {
|
||||
this.localPagination = this.showPagination && Object.assign({}, this.localPagination, {
|
||||
current: r.pageNo, // 返回结果中的当前分页数
|
||||
total: r.totalCount, // 返回结果中的总记录数
|
||||
showSizeChanger: this.showSizeChanger,
|
||||
pageSize: (pagination && pagination.pageSize) ||
|
||||
this.localPagination.pageSize
|
||||
}) || false
|
||||
// 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页
|
||||
if (r.data.length === 0 && this.showPagination && this.localPagination.current > 1) {
|
||||
this.localPagination.current--
|
||||
this.loadData()
|
||||
return
|
||||
}
|
||||
const data = reactive({
|
||||
needTotalList: [],
|
||||
localLoading: false,
|
||||
localDataSource: [],
|
||||
localPagination: Object.assign({}, props.pagination),
|
||||
isFullscreen: false,
|
||||
customSize: props.compSize,
|
||||
columnsSetting: [],
|
||||
localSettings: {
|
||||
rowClassName: props.rowClassName,
|
||||
rowClassNameSwitch: Boolean(props.rowClassName)
|
||||
}
|
||||
})
|
||||
|
||||
// 这里用于判断接口是否有返回 r.totalCount 且 this.showPagination = true 且 pageNo 和 pageSize 存在 且 totalCount 小于等于 pageNo * pageSize 的大小
|
||||
// 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能
|
||||
try {
|
||||
if ((['auto', true].includes(this.showPagination) && r.totalCount <= (r.pageNo * this.localPagination.pageSize))) {
|
||||
this.localPagination.hideOnSinglePage = true
|
||||
}
|
||||
} catch (e) {
|
||||
this.localPagination = false
|
||||
}
|
||||
console.log('loadData -> this.localPagination', this.localPagination)
|
||||
this.localDataSource = r.data // 返回结果中的数组数据
|
||||
this.localLoading = false
|
||||
})
|
||||
// 这里的 data.xxx 是之前声明的
|
||||
// 在 loadData() 方法中去获取后端数据,进行一个数据的加载更新
|
||||
result.then((r) => {
|
||||
if (r == null) {
|
||||
data.localLoading = false
|
||||
return
|
||||
}
|
||||
data.localPagination =
|
||||
(props.showPagination &&
|
||||
Object.assign({}, data.localPagination, {
|
||||
current: r.current, // pageNo, // 返回结果中的当前分页数
|
||||
total: r.total, // totalRows, // 返回结果中的总记录数
|
||||
showSizeChanger: props.showSizeChanger,
|
||||
pageSizeOptions: props.pageSizeOptions,
|
||||
showTotal: (total, range) => {
|
||||
return `${range[0]}-${range[1]} 共 ${total} 条 `
|
||||
},
|
||||
pageSize: (pagination && pagination.pageSize) || data.localPagination.pageSize
|
||||
})) ||
|
||||
false
|
||||
|
||||
// 后端数据records为null保存修复
|
||||
if (r.records == null) {
|
||||
r.records = []
|
||||
}
|
||||
|
||||
// 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页
|
||||
if (r.records.length === 0 && props.showPagination && data.localPagination.current > 1) {
|
||||
data.localPagination.current--
|
||||
loadData()
|
||||
return
|
||||
}
|
||||
// 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能
|
||||
try {
|
||||
/*
|
||||
if ((['auto', true].includes(props.showPagination) && r.total <= (r.pages * data.localPagination.size))) {
|
||||
data.localPagination.hideOnSinglePage = true
|
||||
}
|
||||
*/
|
||||
if (!props.showPagination) {
|
||||
data.localPagination.hideOnSinglePage = true
|
||||
}
|
||||
} catch (e) {
|
||||
data.localPagination = false
|
||||
}
|
||||
// 返回结果中的数组数据
|
||||
if (props.showPagination === false) {
|
||||
// 既然配置了不分页,那么我们这里接收到肯定是数组
|
||||
data.localDataSource = []
|
||||
if (r instanceof Array) {
|
||||
data.localDataSource = r
|
||||
}
|
||||
} else {
|
||||
data.localDataSource = r.records
|
||||
}
|
||||
data.localLoading = false
|
||||
getTableProps() // 获取到后端返回的数据后,需要调用一下获取table的props的方法去刷新table
|
||||
})
|
||||
```
|
||||
返回 JSON 例子:
|
||||
```json
|
||||
|
@ -336,4 +366,4 @@ result.then(r => {
|
|||
更新时间
|
||||
----
|
||||
|
||||
该文档最后更新于: 2019-06-23 PM 17:19
|
||||
该文档最后更新于: 2023-12-27 PM 16:45
|
||||
|
|
|
@ -22,76 +22,70 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from 'vuedraggable-es'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
draggable
|
||||
},
|
||||
props: {
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
indeterminate: false,
|
||||
checkAll: true,
|
||||
columnsSetting: [],
|
||||
originColumns: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.columnsSetting = this.columns.map((value) => {
|
||||
if (value.checked == undefined) {
|
||||
return {
|
||||
...value,
|
||||
checked: true
|
||||
}
|
||||
} else return value
|
||||
})
|
||||
// 这里要用深的拷贝,否则,勾选了字段时会修改了originColumns里的内容
|
||||
this.originColumns = this.columnsSetting.map((value) => ({ ...value }))
|
||||
// 处理全选组件
|
||||
const notCheckedList = this.columnsSetting.filter((value) => !value.checked)
|
||||
if (notCheckedList.length) this.checkAll = false
|
||||
},
|
||||
methods: {
|
||||
reset() {
|
||||
this.columnsSetting = this.originColumns.map((value) => ({ ...value }))
|
||||
this.indeterminate = false
|
||||
const checkedList = this.columnsSetting.filter((value) => value.checked)
|
||||
this.checkAll = checkedList.length === this.columnsSetting.length
|
||||
this.emitColumnChange()
|
||||
},
|
||||
onChange() {
|
||||
const checkedList = this.columnsSetting.filter((value) => value.checked)
|
||||
this.indeterminate = Boolean(checkedList.length) && checkedList.length < this.columnsSetting.length
|
||||
this.checkAll = checkedList.length === this.columnsSetting.length
|
||||
this.emitColumnChange()
|
||||
},
|
||||
onCheckAllChange(e) {
|
||||
e.preventDefault()
|
||||
const val = e.target.checked
|
||||
Object.assign(this, {
|
||||
indeterminate: false,
|
||||
checkAll: val,
|
||||
columnsSetting: this.columns.map((value) => ({
|
||||
...value,
|
||||
checked: val
|
||||
}))
|
||||
})
|
||||
this.emitColumnChange()
|
||||
},
|
||||
emitColumnChange() {
|
||||
// eslint-disable-next-line vue/require-explicit-emits
|
||||
this.$emit('columnChange', this.columnsSetting)
|
||||
}
|
||||
<script setup>
|
||||
import Draggable from 'vuedraggable-es'
|
||||
const emit = defineEmits(['columnChange'])
|
||||
const props = defineProps({
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
const indeterminate = ref(false)
|
||||
const checkAll = ref(true)
|
||||
const columnsSetting = ref([])
|
||||
const originColumns = ref()
|
||||
|
||||
onMounted(() => {
|
||||
columnsSetting.value = props.columns.map((value) => {
|
||||
if (value.checked === undefined) {
|
||||
return {
|
||||
...value,
|
||||
checked: true
|
||||
}
|
||||
} else return value
|
||||
})
|
||||
|
||||
// 这里要用深的拷贝,否则,勾选了字段时会修改了originColumns里的内容
|
||||
originColumns.value = columnsSetting.value.map((value) => ({ ...value }))
|
||||
|
||||
// 处理全选组件
|
||||
const notCheckedList = columnsSetting.value.filter((value) => !value.checked)
|
||||
if (notCheckedList.length) checkAll.value = false
|
||||
})
|
||||
|
||||
const reset = () => {
|
||||
columnsSetting.value = originColumns.value.map((value) => ({ ...value }))
|
||||
indeterminate.value = false
|
||||
const checkedList = columnsSetting.value.filter((value) => value.checked)
|
||||
checkAll.value = checkedList.length === columnsSetting.value.length
|
||||
emitColumnChange()
|
||||
}
|
||||
|
||||
const onChange = () => {
|
||||
const checkedList = columnsSetting.value.filter((value) => value.checked)
|
||||
indeterminate.value = Boolean(checkedList.length) && checkedList.length < columnsSetting.value.length
|
||||
checkAll.value = checkedList.length === columnsSetting.value.length
|
||||
emitColumnChange()
|
||||
}
|
||||
|
||||
// 全选
|
||||
const onCheckAllChange = (e) => {
|
||||
e.preventDefault()
|
||||
const val = e.target.checked
|
||||
|
||||
indeterminate.value = false
|
||||
checkAll.value = val
|
||||
columnsSetting.value = props.columns.map((value) => ({
|
||||
...value,
|
||||
checked: val
|
||||
}))
|
||||
emitColumnChange()
|
||||
}
|
||||
|
||||
const emitColumnChange = () => {
|
||||
// eslint-disable-next-line vue/require-explicit-emits
|
||||
emit('columnChange', columnsSetting.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
|
|
@ -1,36 +1,128 @@
|
|||
<script lang="jsx">
|
||||
<template>
|
||||
<div className="table-wrapper">
|
||||
<div className="s-table-tool">
|
||||
<div className="s-table-tool-left">
|
||||
<!-- 插槽操作按钮 -->
|
||||
<slot name="operator"></slot>
|
||||
</div>
|
||||
<!-- 斑马纹 -->
|
||||
<div className="layout-items-center s-table-tool-right">
|
||||
<div className="layout-items-center ml-4" v-show="props.toolConfig.striped">
|
||||
<a-checkbox :checked="data.localSettings.rowClassNameSwitch" @change="changeRowClass"> 斑马纹 </a-checkbox>
|
||||
</div>
|
||||
<span v-for="item in tool">
|
||||
<!-- 刷新 -->
|
||||
<a-tooltip
|
||||
v-if="item.name === 'refresh' && props.toolConfig.refresh"
|
||||
:title="item.title"
|
||||
class="s-tool-item"
|
||||
@click="refresh"
|
||||
>
|
||||
<component class="icons" :is="item.icon"></component>
|
||||
</a-tooltip>
|
||||
|
||||
<!-- 列展示 -->
|
||||
<a-popover
|
||||
v-if="item.isPopover && item.name === 'columnSetting' && props.toolConfig.columnSetting"
|
||||
trigger="click"
|
||||
placement="topLeft"
|
||||
overlayClassName="s-table-column-settings"
|
||||
arrow-point-at-center
|
||||
>
|
||||
<template #content>
|
||||
<columnSetting :columns="props.columns" @columnChange="columnChange" />
|
||||
</template>
|
||||
<a-tooltip :title="item.title" class="s-tool-item">
|
||||
<component class="icons" :is="item.icon"></component>
|
||||
</a-tooltip>
|
||||
</a-popover>
|
||||
<!-- 密度 -->
|
||||
<a-dropdown trigger="click" v-if="item.isDropdown && item.name == 'height' && props.toolConfig.height">
|
||||
<template #overlay>
|
||||
<a-menu selectable :selectedKeys="[data.customSize]" @click="changeHeight">
|
||||
<a-menu-item key="default">默认</a-menu-item>
|
||||
<a-menu-item key="middle">中等</a-menu-item>
|
||||
<a-menu-item key="small">紧凑</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-tooltip :title="item.title" class="s-tool-item">
|
||||
<component class="icons" :is="item.icon"></component>
|
||||
</a-tooltip>
|
||||
</a-dropdown>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 统计列数据 -->
|
||||
<a-alert showIcon class="mb-4" v-if="props.alert">
|
||||
<template #message>
|
||||
<div>
|
||||
<span className="mr-3">
|
||||
已选择:{{ ' ' }}
|
||||
<a className="font-6">
|
||||
{{
|
||||
props.rowSelection && props.rowSelection.selectedRowKeys ? props.rowSelection.selectedRowKeys.length : 0
|
||||
}}
|
||||
</a>
|
||||
</span>
|
||||
<span className="mr-3" v-for="item in data.needTotalList">
|
||||
{{ item.title }} 总计{{ ' ' }}
|
||||
<a className="font-6">{{ !item.customRender ? item.total : item.customRender(item.total) }}</a>
|
||||
</span>
|
||||
<a
|
||||
v-show="
|
||||
props.rowSelection && props.rowSelection.selectedRowKeys && props.rowSelection.selectedRowKeys.length > 0
|
||||
"
|
||||
className="ml-6"
|
||||
@click="
|
||||
rowClear(
|
||||
typeof props.alert === 'boolean' && props.alert
|
||||
? clearSelected()
|
||||
: props.alert.clear && typeof props.alert.clear === 'function'
|
||||
? props.alert.clear()
|
||||
: null
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ ' ' }}
|
||||
清空{{ ' ' }}
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
</a-alert>
|
||||
|
||||
<!-- 表格 -->
|
||||
<a-table
|
||||
v-bind="{ ...renderTableProps, ...data.localSettings }"
|
||||
@change="loadData"
|
||||
:row-key="(record) => record.id"
|
||||
@expand="
|
||||
(expanded, record) => {
|
||||
emit('expand', expanded, record)
|
||||
}
|
||||
"
|
||||
>
|
||||
<template #[item]="scope" v-for="item in renderSlots">
|
||||
<slot :name="item" :scope="scope" v-bind="scope || {}"></slot>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import './index.less'
|
||||
import { tableProps } from 'ant-design-vue/es/table/Table.js'
|
||||
import { get } from 'lodash-es'
|
||||
import draggable from 'vuedraggable-es'
|
||||
import columnSetting from './columnSetting.vue'
|
||||
import './index.less'
|
||||
import i18n from '@/locales'
|
||||
|
||||
const { t } = i18n.global
|
||||
import { useSlots } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
const slots = useSlots()
|
||||
const route = useRoute()
|
||||
const emit = defineEmits(['expand'])
|
||||
const renderSlots = Object.keys(slots)
|
||||
|
||||
export default {
|
||||
name: 'STable',
|
||||
components: {
|
||||
draggable,
|
||||
columnSetting
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
needTotalList: [],
|
||||
localLoading: false,
|
||||
localDataSource: [],
|
||||
localPagination: Object.assign({}, this.pagination),
|
||||
isFullscreen: false,
|
||||
customSize: this.compSize,
|
||||
columnsSetting: [],
|
||||
localSettings: {
|
||||
rowClassName: this.rowClassName,
|
||||
rowClassNameSwitch: Boolean(this.rowClassName)
|
||||
}
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line vue/order-in-components
|
||||
props: Object.assign({}, tableProps(), {
|
||||
const props = defineProps(
|
||||
Object.assign({}, tableProps(), {
|
||||
rowKey: {
|
||||
type: [String, Function],
|
||||
default: 'key'
|
||||
|
@ -97,468 +189,356 @@
|
|||
striped: false
|
||||
})
|
||||
}
|
||||
}),
|
||||
watch: {
|
||||
pageNum(val) {
|
||||
Object.assign(this.localPagination, {
|
||||
current: val
|
||||
})
|
||||
},
|
||||
size(val) {
|
||||
Object.assign(this.localPagination, {
|
||||
size: val
|
||||
})
|
||||
},
|
||||
showSizeChanger(val) {
|
||||
Object.assign(this.localPagination, {
|
||||
showSizeChanger: val
|
||||
})
|
||||
},
|
||||
columns(v) {
|
||||
this.columnsSetting = v
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const { current } = this.$route.params
|
||||
const localPageNum = (current && parseInt(current)) || this.pageNum
|
||||
this.localPagination =
|
||||
(['auto', true].includes(this.showPagination) &&
|
||||
Object.assign({}, this.localPagination, {
|
||||
current: localPageNum,
|
||||
pageSize: this.size, //this.compSize, size// 改动
|
||||
showSizeChanger: this.showSizeChanger,
|
||||
defaultPageSize: this.defaultPageSize,
|
||||
pageSizeOptions: this.pageSizeOptions,
|
||||
showTotal: (total, range) => {
|
||||
return `${range[0]}-${range[1]} 共 ${total} 条 `
|
||||
}
|
||||
})) ||
|
||||
false
|
||||
this.needTotalList = this.initTotalList(this.columns)
|
||||
this.loadData()
|
||||
this.columnsSetting = this.columns
|
||||
/*.map((c) => {
|
||||
const tt = c.title
|
||||
if (typeof tt === 'string') {
|
||||
c.title = () => t(tt)
|
||||
}
|
||||
return c
|
||||
})*/
|
||||
},
|
||||
methods: {
|
||||
// 表格重新加载方法 如果参数为 true, 则强制刷新到第一页
|
||||
refresh(bool = false) {
|
||||
bool &&
|
||||
(this.localPagination = Object.assign(
|
||||
{},
|
||||
{
|
||||
current: 1,
|
||||
pageSize: this.localPagination.pageSize
|
||||
}
|
||||
))
|
||||
this.loadData()
|
||||
},
|
||||
// 加载数据方法 分页选项器 过滤条件 排序条件
|
||||
loadData(pagination, filters, sorter) {
|
||||
this.localLoading = true
|
||||
const parameter = Object.assign(
|
||||
{
|
||||
current:
|
||||
(pagination && pagination.current) ||
|
||||
(this.showPagination && this.localPagination.current) ||
|
||||
this.pageNum,
|
||||
// 此处后端使用size作为分页参数
|
||||
size:
|
||||
(pagination && pagination.pageSize) ||
|
||||
(this.showPagination && this.localPagination.pageSize) ||
|
||||
this.pageSize ||
|
||||
this.localPagination.pageSize
|
||||
},
|
||||
(sorter &&
|
||||
sorter.field && {
|
||||
sortField: sorter.field
|
||||
}) ||
|
||||
{},
|
||||
(sorter &&
|
||||
sorter.order && {
|
||||
sortOrder: sorter.order
|
||||
}) ||
|
||||
{},
|
||||
{
|
||||
...filters
|
||||
}
|
||||
)
|
||||
const result = this.data(parameter)
|
||||
if ((typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function') {
|
||||
result.then((r) => {
|
||||
if (r == null) {
|
||||
this.localLoading = false
|
||||
return
|
||||
}
|
||||
this.localPagination =
|
||||
(this.showPagination &&
|
||||
Object.assign({}, this.localPagination, {
|
||||
current: r.current, // pageNo, // 返回结果中的当前分页数
|
||||
total: r.total, // totalRows, // 返回结果中的总记录数
|
||||
showSizeChanger: this.showSizeChanger,
|
||||
pageSizeOptions: this.pageSizeOptions,
|
||||
showTotal: (total, range) => {
|
||||
return `${range[0]}-${range[1]} 共 ${total} 条 `
|
||||
},
|
||||
pageSize: (pagination && pagination.pageSize) || this.localPagination.pageSize
|
||||
})) ||
|
||||
false
|
||||
// 后端数据records为null保存修复
|
||||
if (r.records == null) {
|
||||
r.records = []
|
||||
}
|
||||
// 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页
|
||||
if (r.records.length === 0 && this.showPagination && this.localPagination.current > 1) {
|
||||
this.localPagination.current--
|
||||
this.loadData()
|
||||
return
|
||||
}
|
||||
// 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能
|
||||
try {
|
||||
/*
|
||||
if ((['auto', true].includes(this.showPagination) && r.total <= (r.pages * this.localPagination.size))) {
|
||||
this.localPagination.hideOnSinglePage = true
|
||||
}
|
||||
*/
|
||||
if (!this.showPagination) {
|
||||
this.localPagination.hideOnSinglePage = true
|
||||
}
|
||||
} catch (e) {
|
||||
this.localPagination = false
|
||||
}
|
||||
// 返回结果中的数组数据
|
||||
if (this.showPagination === false) {
|
||||
// 既然配置了不分页,那么我们这里接收到肯定是数组
|
||||
this.localDataSource = []
|
||||
if (r instanceof Array) {
|
||||
this.localDataSource = r
|
||||
}
|
||||
} else {
|
||||
this.localDataSource = r.records
|
||||
}
|
||||
this.localLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
initTotalList(columns) {
|
||||
const totalList = []
|
||||
columns &&
|
||||
columns instanceof Array &&
|
||||
columns.forEach((column) => {
|
||||
if (column.needTotal) {
|
||||
totalList.push({
|
||||
...column,
|
||||
total: 0
|
||||
})
|
||||
}
|
||||
})
|
||||
return totalList
|
||||
},
|
||||
// 用于更新已选中的列表数据 total 统计
|
||||
updateSelect(selectedRowKeys, selectedRows) {
|
||||
if (this.rowSelection) {
|
||||
this.rowSelection.selectedRows = selectedRows
|
||||
this.rowSelection.selectedRowKeys = selectedRowKeys
|
||||
}
|
||||
const list = this.needTotalList
|
||||
this.needTotalList = list.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
total: selectedRows.reduce((sum, val) => {
|
||||
const total = sum + parseInt(get(val, item.dataIndex))
|
||||
return isNaN(total) ? 0 : total
|
||||
}, 0)
|
||||
}
|
||||
})
|
||||
},
|
||||
// 清空 table 已选中项
|
||||
clearSelected() {
|
||||
if (this.rowSelection) {
|
||||
this.rowSelection.onChange([], [])
|
||||
this.updateSelect([], [])
|
||||
}
|
||||
},
|
||||
// 刷新并清空已选
|
||||
clearRefreshSelected(bool = false) {
|
||||
this.refresh(bool)
|
||||
this.clearSelected()
|
||||
},
|
||||
// 处理交给 table 使用者去处理 clear 事件时,内部选中统计同时调用
|
||||
renderClear(callback) {
|
||||
if (this.rowSelection && this.rowSelection.selectedRowKeys && this.rowSelection.selectedRowKeys.length > 0) {
|
||||
return (
|
||||
<a
|
||||
className="ml-6"
|
||||
onClick={() => {
|
||||
callback()
|
||||
this.clearSelected()
|
||||
}}>
|
||||
{' '}
|
||||
清空{' '}
|
||||
</a>
|
||||
)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
},
|
||||
renderAlert() {
|
||||
// 绘制统计列数据
|
||||
const needTotalItems = this.needTotalList.map((item) => {
|
||||
return (
|
||||
<span className="mr-3">
|
||||
{item.title} 总计{' '}
|
||||
<a className="font-6">{!item.customRender ? item.total : item.customRender(item.total)}</a>
|
||||
</span>
|
||||
)
|
||||
})
|
||||
// 绘制 alert 组件
|
||||
if (alert) {
|
||||
const showAlert =
|
||||
(typeof this.alert === 'object' &&
|
||||
this.alert !== null &&
|
||||
this.alert.show &&
|
||||
typeof this.rowSelection.selectedRowKeys !== 'undefined') ||
|
||||
this.alert
|
||||
if (showAlert) {
|
||||
// 绘制 清空 按钮
|
||||
const clearItem =
|
||||
typeof this.alert === 'boolean' && this.alert
|
||||
? this.renderClear(this.clearSelected)
|
||||
: this.alert.clear && typeof this.alert.clear === 'function'
|
||||
? this.renderClear(this.alert.clear)
|
||||
: null
|
||||
const message = (
|
||||
<div>
|
||||
<span className="mr-3">
|
||||
已选择:{' '}
|
||||
<a className="font-6">
|
||||
{this.rowSelection && this.rowSelection.selectedRowKeys
|
||||
? this.rowSelection.selectedRowKeys.length
|
||||
: 0}
|
||||
</a>
|
||||
</span>
|
||||
{needTotalItems}
|
||||
{clearItem}
|
||||
</div>
|
||||
)
|
||||
return <a-alert showIcon class="mb-4" message={message} />
|
||||
}
|
||||
}
|
||||
},
|
||||
columnChange(val) {
|
||||
this.columnsSetting = val
|
||||
},
|
||||
renderHeader() {
|
||||
let tools = [
|
||||
{
|
||||
name: 'refresh',
|
||||
icon: <sync-outlined class="ml-4" />,
|
||||
title: '刷新',
|
||||
onClick: () => {
|
||||
this.refresh()
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'height',
|
||||
icon: <column-height-outlined />,
|
||||
title: '密度',
|
||||
isDropdown: true,
|
||||
menu: () => {
|
||||
const onClick = ({ key }) => {
|
||||
this.customSize = key
|
||||
}
|
||||
return (
|
||||
<a-menu onClick={onClick} selectable selectedKeys={[this.customSize]}>
|
||||
<a-menu-item key="default">默认</a-menu-item>
|
||||
<a-menu-item key="middle">中等</a-menu-item>
|
||||
<a-menu-item key="small">紧凑</a-menu-item>
|
||||
</a-menu>
|
||||
)
|
||||
},
|
||||
onClick: () => {}
|
||||
},
|
||||
{
|
||||
name: 'columnSetting',
|
||||
icon: <setting-outlined />,
|
||||
title: '列设置',
|
||||
isPopover: true,
|
||||
visible: false,
|
||||
menu: () => {
|
||||
return <columnSetting columns={this.columns} onColumnChange={this.columnChange} />
|
||||
},
|
||||
onClick: () => {}
|
||||
}
|
||||
]
|
||||
if (this.extraTool.length) {
|
||||
tools = tools.concat(this.extraTool)
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
// 斑马纹
|
||||
const changeRowClass = (value) => {
|
||||
const val = value.target.checked
|
||||
this.localSettings.rowClassNameSwitch = val
|
||||
const evenClass = val ? (_record, index) => (index % 2 === 1 ? 'table-striped' : null) : this.rowClassName
|
||||
this.localSettings.rowClassName = evenClass
|
||||
}
|
||||
return (
|
||||
<div className="s-table-tool">
|
||||
<div className="s-table-tool-left">{this.$slots.operator && this.$slots.operator()}</div>
|
||||
<div className="layout-items-center s-table-tool-right">
|
||||
{this.toolConfig.striped ? (
|
||||
<div className="layout-items-center ml-4">
|
||||
<a-checkbox checked={this.localSettings.rowClassNameSwitch} onChange={changeRowClass}>
|
||||
斑马纹
|
||||
</a-checkbox>
|
||||
</div>
|
||||
) : null}
|
||||
const data = reactive({
|
||||
needTotalList: [],
|
||||
localLoading: false,
|
||||
localDataSource: [],
|
||||
localPagination: Object.assign({}, props.pagination),
|
||||
isFullscreen: false,
|
||||
customSize: props.compSize,
|
||||
columnsSetting: [],
|
||||
localSettings: {
|
||||
rowClassName: props.rowClassName,
|
||||
rowClassNameSwitch: Boolean(props.rowClassName)
|
||||
}
|
||||
})
|
||||
|
||||
{tools.map((tool) => {
|
||||
if (!this.toolConfig[tool.name]) {
|
||||
return null
|
||||
}
|
||||
const tooltipEle = (
|
||||
<a-tooltip title={tool.title} class="s-tool-item" onClick={tool.onClick}>
|
||||
{tool.icon}
|
||||
</a-tooltip>
|
||||
)
|
||||
if (tool.isPopover) {
|
||||
return (
|
||||
<a-popover
|
||||
trigger={'click'}
|
||||
placement="topLeft"
|
||||
overlayClassName="s-table-column-settings"
|
||||
arrow-point-at-center
|
||||
content={tool.menu()}>
|
||||
{tooltipEle}
|
||||
</a-popover>
|
||||
)
|
||||
}
|
||||
if (tool.isDropdown) {
|
||||
return (
|
||||
<a-dropdown trigger={['click']} overlay={tool.menu()}>
|
||||
{tooltipEle}
|
||||
</a-dropdown>
|
||||
)
|
||||
}
|
||||
return tooltipEle
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
let props = {}
|
||||
const localKeys = Object.keys(this.$data)
|
||||
Object.keys(tableProps()).forEach((k) => {
|
||||
const localKey = `local${k.substring(0, 1).toUpperCase()}${k.substring(1)}`
|
||||
if (localKeys.includes(localKey)) {
|
||||
props[k] = this[localKey]
|
||||
return props[k]
|
||||
}
|
||||
if (k === 'rowSelection') {
|
||||
if (this.rowSelection) {
|
||||
// 如果需要使用alert,则重新绑定 rowSelection 事件
|
||||
props[k] = {
|
||||
...this.rowSelection,
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
this.updateSelect(selectedRowKeys, selectedRows)
|
||||
typeof this[k].onChange !== 'undefined' && this[k].onChange(selectedRowKeys, selectedRows)
|
||||
}
|
||||
}
|
||||
return props[k]
|
||||
} else if (!this.rowSelection) {
|
||||
// 如果没打算开启 rowSelection 则清空默认的选择项
|
||||
props[k] = null
|
||||
return props[k]
|
||||
}
|
||||
}
|
||||
if (k === 'customRow') {
|
||||
if (this.lineSelection && this.rowSelection) {
|
||||
// 如果需要 整行选择,则重新绑定 customRow 事件
|
||||
props[k] = (record, index) => {
|
||||
return {
|
||||
...(typeof this.customRow !== 'undefined' && this.customRow(record, index)),
|
||||
onClick: (event) => {
|
||||
// 若存在原onClick则执行
|
||||
typeof this[k] !== 'undefined' &&
|
||||
typeof this[k](record, index).onClick !== 'undefined' &&
|
||||
this[k](record, index).onClick(event)
|
||||
// 记录为disabled则直接返回,默认为不可选
|
||||
const rowDisabled =
|
||||
typeof this.rowSelection.getCheckboxProps !== 'undefined' &&
|
||||
this.rowSelection.getCheckboxProps(record).disabled
|
||||
if (rowDisabled) return
|
||||
// 过滤自定义按钮的非空白区域
|
||||
const classList = event.target?.classList
|
||||
if (!classList.contains('ant-table-cell')) return
|
||||
const key = (typeof this.rowKey === 'function' && this.rowKey(record)) || this.rowKey || index
|
||||
let selectedRows = this.rowSelection.selectedRows
|
||||
let selectedRowKeys = this.rowSelection.selectedRowKeys
|
||||
const rowType = this.rowSelection?.type || 'checkbox'
|
||||
|
||||
if (rowType === 'radio' || this.rowSelection.selectedRowKeys === undefined) {
|
||||
selectedRowKeys = [key]
|
||||
selectedRows = [record]
|
||||
} else if (!this.rowSelection.selectedRowKeys?.includes(key)) {
|
||||
selectedRowKeys.push(key)
|
||||
selectedRows.push(record)
|
||||
} else {
|
||||
const index = this.rowSelection.selectedRowKeys?.findIndex((itemKey) => itemKey === key)
|
||||
selectedRows.splice(index, 1)
|
||||
selectedRowKeys.splice(index, 1)
|
||||
}
|
||||
this.updateSelect(selectedRowKeys, selectedRows)
|
||||
typeof this.rowSelection.onChange !== 'undefined' &&
|
||||
this.rowSelection.onChange(selectedRowKeys, selectedRows)
|
||||
}
|
||||
}
|
||||
}
|
||||
return props[k]
|
||||
}
|
||||
}
|
||||
this[k] && (props[k] = this[k])
|
||||
// 此处配置表格大小与要显示的列
|
||||
props = {
|
||||
...props,
|
||||
size: this.customSize, // 注意这个size是a-table组件需要的,这里不能跟别的地方成为compSize
|
||||
columns: this.columnsSetting.filter((value) => value.checked === undefined || value.checked)
|
||||
}
|
||||
// 如果在使用界面每配置scroll,那么使用全局的,对缩小屏幕下横向滚动条左右滑动
|
||||
if (!props.scroll) {
|
||||
props.scroll = { x: 1000 }
|
||||
// 对于界面上要显示的字段太多,默认加上横向滚动条
|
||||
if (props.columns && props.columns.length > 10) {
|
||||
props.scroll = { x: 1200 }
|
||||
}
|
||||
}
|
||||
return props[k]
|
||||
watch(
|
||||
() => props.pageNum,
|
||||
(newVal) => {
|
||||
Object.assign(data.localPagination, {
|
||||
current: newVal
|
||||
})
|
||||
const table = (
|
||||
<a-table
|
||||
{...props}
|
||||
{...this.localSettings}
|
||||
v-slots={this.$slots}
|
||||
onChange={this.loadData}
|
||||
onExpand={(expanded, record) => {
|
||||
this.$emit('expand', expanded, record)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
watch(
|
||||
() => props.size,
|
||||
(newVal) => {
|
||||
Object.assign(data.localPagination, {
|
||||
size: newVal
|
||||
})
|
||||
}
|
||||
)
|
||||
watch(
|
||||
() => props.showSizeChanger,
|
||||
(newVal) => {
|
||||
Object.assign(data.localPagination, {
|
||||
showSizeChanger: newVal
|
||||
})
|
||||
}
|
||||
)
|
||||
watch(
|
||||
() => props.columns,
|
||||
(newVal) => {
|
||||
data.columnsSetting = newVal
|
||||
}
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="table-wrapper">
|
||||
{this.renderHeader()}
|
||||
{this.renderAlert()}
|
||||
{table}
|
||||
</div>
|
||||
)
|
||||
// 表格props
|
||||
const renderTableProps = ref([])
|
||||
// 右上角工具数组
|
||||
const tool = [
|
||||
{
|
||||
name: 'refresh',
|
||||
icon: 'sync-outlined',
|
||||
title: '刷新'
|
||||
},
|
||||
{
|
||||
name: 'height',
|
||||
icon: 'column-height-outlined',
|
||||
title: '密度',
|
||||
isDropdown: true
|
||||
},
|
||||
{
|
||||
name: 'columnSetting',
|
||||
icon: 'setting-outlined',
|
||||
title: '列设置',
|
||||
isPopover: true,
|
||||
visible: false
|
||||
}
|
||||
]
|
||||
|
||||
// 刷新
|
||||
const refresh = (bool = false) => {
|
||||
bool &&
|
||||
(data.localPagination = Object.assign(
|
||||
{},
|
||||
{
|
||||
current: 1,
|
||||
pageSize: data.localPagination.pageSize
|
||||
}
|
||||
))
|
||||
loadData()
|
||||
getTableProps()
|
||||
}
|
||||
// 斑马纹勾选
|
||||
const changeRowClass = (value) => {
|
||||
const val = value.target.checked
|
||||
data.localSettings.rowClassNameSwitch = val
|
||||
const evenClass = val ? (_record, index) => (index % 2 === 1 ? 'table-striped' : null) : props.rowClassName
|
||||
data.localSettings.rowClassName = evenClass
|
||||
}
|
||||
// 密度切换
|
||||
const changeHeight = (v) => {
|
||||
data.customSize = v.key
|
||||
getTableProps()
|
||||
}
|
||||
// 列设置
|
||||
const columnChange = (val) => {
|
||||
data.columnsSetting = val
|
||||
getTableProps()
|
||||
}
|
||||
// 列清空
|
||||
const rowClear = (callback) => {
|
||||
callback
|
||||
clearSelected()
|
||||
}
|
||||
// 初始化
|
||||
const init = () => {
|
||||
const { current } = route.params
|
||||
const localPageNum = (current && parseInt(current)) || props.pageNum
|
||||
data.localPagination =
|
||||
(['auto', true].includes(props.showPagination) &&
|
||||
Object.assign({}, data.localPagination, {
|
||||
current: localPageNum,
|
||||
pageSize: props.size, //props.compSize, size// 改动
|
||||
showSizeChanger: props.showSizeChanger,
|
||||
defaultPageSize: props.defaultPageSize,
|
||||
pageSizeOptions: props.pageSizeOptions,
|
||||
showTotal: (total, range) => {
|
||||
return `${range[0]}-${range[1]} 共 ${total} 条 `
|
||||
}
|
||||
})) ||
|
||||
false
|
||||
data.needTotalList = initTotalList(props.columns)
|
||||
data.columnsSetting = props.columns
|
||||
loadData()
|
||||
}
|
||||
const initTotalList = (columns) => {
|
||||
const totalList = []
|
||||
columns &&
|
||||
columns instanceof Array &&
|
||||
columns.forEach((column) => {
|
||||
if (column.needTotal) {
|
||||
totalList.push({
|
||||
...column,
|
||||
total: 0
|
||||
})
|
||||
}
|
||||
})
|
||||
return totalList
|
||||
}
|
||||
// 加载数据方法 分页选项器 过滤条件 排序条件
|
||||
const loadData = (pagination, filters, sorter) => {
|
||||
data.localLoading = true
|
||||
const parameter = Object.assign(
|
||||
{
|
||||
current:
|
||||
(pagination && pagination.current) || (props.showPagination && data.localPagination.current) || props.pageNum,
|
||||
// 此处后端使用size作为分页参数
|
||||
size:
|
||||
(pagination && pagination.pageSize) ||
|
||||
(props.showPagination && data.localPagination.pageSize) ||
|
||||
props.pageSize ||
|
||||
data.localPagination.pageSize
|
||||
},
|
||||
(sorter &&
|
||||
sorter.field && {
|
||||
sortField: sorter.field
|
||||
}) ||
|
||||
{},
|
||||
(sorter &&
|
||||
sorter.order && {
|
||||
sortOrder: sorter.order
|
||||
}) ||
|
||||
{},
|
||||
{
|
||||
...filters
|
||||
}
|
||||
)
|
||||
const result = props.data(parameter)
|
||||
if ((typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function') {
|
||||
result.then((r) => {
|
||||
if (r == null) {
|
||||
data.localLoading = false
|
||||
return
|
||||
}
|
||||
data.localPagination =
|
||||
(props.showPagination &&
|
||||
Object.assign({}, data.localPagination, {
|
||||
current: r.current, // pageNo, // 返回结果中的当前分页数
|
||||
total: r.total, // totalRows, // 返回结果中的总记录数
|
||||
showSizeChanger: props.showSizeChanger,
|
||||
pageSizeOptions: props.pageSizeOptions,
|
||||
showTotal: (total, range) => {
|
||||
return `${range[0]}-${range[1]} 共 ${total} 条 `
|
||||
},
|
||||
pageSize: (pagination && pagination.pageSize) || data.localPagination.pageSize
|
||||
})) ||
|
||||
false
|
||||
|
||||
// 后端数据records为null保存修复
|
||||
if (r.records == null) {
|
||||
r.records = []
|
||||
}
|
||||
|
||||
// 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页
|
||||
if (r.records.length === 0 && props.showPagination && data.localPagination.current > 1) {
|
||||
data.localPagination.current--
|
||||
loadData()
|
||||
return
|
||||
}
|
||||
// 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能
|
||||
try {
|
||||
/*
|
||||
if ((['auto', true].includes(props.showPagination) && r.total <= (r.pages * data.localPagination.size))) {
|
||||
data.localPagination.hideOnSinglePage = true
|
||||
}
|
||||
*/
|
||||
if (!props.showPagination) {
|
||||
data.localPagination.hideOnSinglePage = true
|
||||
}
|
||||
} catch (e) {
|
||||
data.localPagination = false
|
||||
}
|
||||
// 返回结果中的数组数据
|
||||
if (props.showPagination === false) {
|
||||
// 既然配置了不分页,那么我们这里接收到肯定是数组
|
||||
data.localDataSource = []
|
||||
if (r instanceof Array) {
|
||||
data.localDataSource = r
|
||||
}
|
||||
} else {
|
||||
data.localDataSource = r.records
|
||||
}
|
||||
data.localLoading = false
|
||||
getTableProps()
|
||||
})
|
||||
}
|
||||
}
|
||||
// 加载props
|
||||
const getTableProps = () => {
|
||||
let renderProps = {}
|
||||
const localKeys = Object.keys(data)
|
||||
Object.keys(tableProps()).forEach((k) => {
|
||||
const localKey = `local${k.substring(0, 1).toUpperCase()}${k.substring(1)}`
|
||||
if (localKeys.includes(localKey)) {
|
||||
renderProps[k] = data[localKey]
|
||||
return renderProps[k]
|
||||
}
|
||||
if (k === 'rowSelection') {
|
||||
if (props.rowSelection) {
|
||||
// 如果需要使用alert,则重新绑定 rowSelection 事件
|
||||
renderProps[k] = {
|
||||
...props.rowSelection,
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
updateSelect(selectedRowKeys, selectedRows)
|
||||
typeof props[k].onChange !== 'undefined' && props[k].onChange(selectedRowKeys, selectedRows)
|
||||
}
|
||||
}
|
||||
return renderProps[k]
|
||||
} else if (!props.rowSelection) {
|
||||
// 如果没打算开启 rowSelection 则清空默认的选择项
|
||||
renderProps[k] = null
|
||||
return renderProps[k]
|
||||
}
|
||||
}
|
||||
if (k === 'customRow') {
|
||||
if (props.lineSelection && props.rowSelection) {
|
||||
// 如果需要 整行选择,则重新绑定 customRow 事件
|
||||
renderProps[k] = (record, index) => {
|
||||
return {
|
||||
...(typeof props.customRow !== 'undefined' && props.customRow(record, index)),
|
||||
onClick: (event) => {
|
||||
// 若存在原onClick则执行
|
||||
typeof data[k] !== 'undefined' &&
|
||||
typeof data[k](record, index).onClick !== 'undefined' &&
|
||||
data[k](record, index).onClick(event)
|
||||
// 记录为disabled则直接返回,默认为不可选
|
||||
const rowDisabled =
|
||||
typeof props.rowSelection.getCheckboxProps !== 'undefined' &&
|
||||
props.rowSelection.getCheckboxProps(record).disabled
|
||||
if (rowDisabled) return
|
||||
// 过滤自定义按钮的非空白区域
|
||||
const classList = event.target?.classList
|
||||
if (!classList.contains('ant-table-cell')) return
|
||||
const key = (typeof props.rowKey === 'function' && props.rowKey(record)) || props.rowKey || index
|
||||
let selectedRows = props.rowSelection.selectedRows
|
||||
let selectedRowKeys = props.rowSelection.selectedRowKeys
|
||||
const rowType = props.rowSelection?.type || 'checkbox'
|
||||
|
||||
if (rowType === 'radio' || props.rowSelection.selectedRowKeys === undefined) {
|
||||
selectedRowKeys = [key]
|
||||
selectedRows = [record]
|
||||
} else if (!props.rowSelection.selectedRowKeys?.includes(key)) {
|
||||
selectedRowKeys.push(key)
|
||||
selectedRows.push(record)
|
||||
} else {
|
||||
const index = props.rowSelection.selectedRowKeys?.findIndex((itemKey) => itemKey === key)
|
||||
selectedRows.splice(index, 1)
|
||||
selectedRowKeys.splice(index, 1)
|
||||
}
|
||||
updateSelect(selectedRowKeys, selectedRows)
|
||||
}
|
||||
}
|
||||
}
|
||||
return renderProps[k]
|
||||
}
|
||||
}
|
||||
data[k] && (renderProps[k] = data[k])
|
||||
// 此处配置表格大小与要显示的列
|
||||
renderProps = {
|
||||
...renderProps,
|
||||
bordered: props.bordered,
|
||||
size: data.customSize, // 注意这个size是a-table组件需要的,这里不能跟别的地方成为compSize
|
||||
columns: data.columnsSetting.filter((value) => value.checked === undefined || value.checked)
|
||||
}
|
||||
return renderProps[k]
|
||||
})
|
||||
renderTableProps.value = renderProps
|
||||
}
|
||||
// 用于更新已选中的列表数据 total 统计
|
||||
const updateSelect = (selectedRowKeys, selectedRows) => {
|
||||
if (props.rowSelection) {
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
props.rowSelection.selectedRows = selectedRows
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
props.rowSelection.selectedRowKeys = selectedRowKeys
|
||||
getTableProps()
|
||||
}
|
||||
const list = data.needTotalList
|
||||
data.needTotalList = list.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
total: selectedRows.reduce((sum, val) => {
|
||||
const total = sum + parseInt(get(val, item.dataIndex))
|
||||
return isNaN(total) ? 0 : total
|
||||
}, 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
// 清空 table 已选中项
|
||||
const clearSelected = () => {
|
||||
if (props.rowSelection) {
|
||||
props.rowSelection.onChange([], [])
|
||||
updateSelect([], [])
|
||||
getTableProps()
|
||||
}
|
||||
}
|
||||
// 刷新并清空已选
|
||||
const clearRefreshSelected = (bool = false) => {
|
||||
refresh(bool)
|
||||
clearSelected()
|
||||
}
|
||||
// 暴露子组件的方法
|
||||
defineExpose({
|
||||
clearRefreshSelected,
|
||||
refresh
|
||||
})
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<a-tag color="orange">{{ item.title }}</a-tag>
|
||||
</template>
|
||||
<template #actions>
|
||||
<template v-for="{ key, label, icon, color } in props.actions">
|
||||
<template v-for="{ key, label, icon, color } in props.actions" :key="key">
|
||||
<a-tooltip :title="label">
|
||||
<component :is="icon" @click="doAction(key, item)" :style="{ color: color }" />
|
||||
</a-tooltip>
|
||||
|
@ -22,8 +22,10 @@
|
|||
<span class="xn-card-meta-title">{{ item.subTitle }}</span>
|
||||
</template>
|
||||
<template #description>
|
||||
<div v-if="item.contents" v-for="content in item.contents">
|
||||
<span>{{ content.label }}:{{ content.value }}</span>
|
||||
<div v-if="item.contents">
|
||||
<div v-for="content in item.contents" :key="content.value">
|
||||
<span>{{ content.label }}:{{ content.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-card-meta>
|
||||
|
|
|
@ -3,86 +3,80 @@
|
|||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
target: null,
|
||||
show: Boolean
|
||||
})
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'XnContextMenu',
|
||||
props: {
|
||||
target: null,
|
||||
show: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
triggerShowFn: () => {},
|
||||
triggerHideFn: () => {},
|
||||
x: null,
|
||||
y: null,
|
||||
style: {},
|
||||
binded: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show(show) {
|
||||
if (show) {
|
||||
this.bindHideEvents()
|
||||
} else {
|
||||
this.unbindHideEvents()
|
||||
}
|
||||
},
|
||||
target(target) {
|
||||
this.bindEvents()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.bindEvents()
|
||||
},
|
||||
methods: {
|
||||
// 初始化事件
|
||||
bindEvents() {
|
||||
this.$nextTick(() => {
|
||||
if (!this.target || this.binded) return
|
||||
this.triggerShowFn = this.contextMenuHandler.bind(this)
|
||||
this.target.addEventListener('contextmenu', this.triggerShowFn)
|
||||
this.binded = true
|
||||
})
|
||||
},
|
||||
// 取消绑定事件
|
||||
unbindEvents() {
|
||||
if (!this.target) return
|
||||
this.target.removeEventListener('contextmenu', this.triggerShowFn)
|
||||
},
|
||||
// 绑定隐藏菜单事件
|
||||
bindHideEvents() {
|
||||
this.triggerHideFn = this.clickDocumentHandler.bind(this)
|
||||
document.addEventListener('mousedown', this.triggerHideFn)
|
||||
document.addEventListener('mousewheel', this.triggerHideFn)
|
||||
},
|
||||
// 取消绑定隐藏菜单事件
|
||||
unbindHideEvents() {
|
||||
document.removeEventListener('mousedown', this.triggerHideFn)
|
||||
document.removeEventListener('mousewheel', this.triggerHideFn)
|
||||
},
|
||||
// 鼠标按压事件处理器
|
||||
clickDocumentHandler(e) {
|
||||
this.$emit('update:show', false)
|
||||
},
|
||||
// 右键事件事件处理
|
||||
contextMenuHandler(e) {
|
||||
this.x = e.clientX
|
||||
this.y = e.clientY
|
||||
this.layout()
|
||||
this.$emit('update:show', true)
|
||||
this.$emit('get-context-menu', e)
|
||||
e.preventDefault()
|
||||
},
|
||||
// 布局
|
||||
layout() {
|
||||
this.style = {
|
||||
left: this.x + 'px',
|
||||
top: this.y + 'px',
|
||||
display: 'block'
|
||||
}
|
||||
}
|
||||
const x = ref(null)
|
||||
const y = ref(null)
|
||||
const style = ref({})
|
||||
const binded = ref(false)
|
||||
const emit = defineEmits(['update:show', 'get-context-menu'])
|
||||
|
||||
// 监听show的变化
|
||||
watch(
|
||||
() => props.show,
|
||||
(newValue) => {
|
||||
newValue ? bindHideEvents() : unbindHideEvents()
|
||||
}
|
||||
)
|
||||
watch(
|
||||
() => props.target,
|
||||
(newValue) => {
|
||||
bindEvents()
|
||||
}
|
||||
)
|
||||
|
||||
// 初始化事件
|
||||
const bindEvents = (e) => {
|
||||
nextTick(() => {
|
||||
if (!props.target || binded.value) return
|
||||
props.target.addEventListener('contextmenu', contextMenuHandler)
|
||||
binded.value = true
|
||||
})
|
||||
}
|
||||
|
||||
// 绑定隐藏菜单事件
|
||||
const bindHideEvents = () => {
|
||||
document.addEventListener('mousedown', clickDocumentHandler)
|
||||
document.addEventListener('mousewheel', clickDocumentHandler)
|
||||
}
|
||||
|
||||
// 取消绑定隐藏菜单事件
|
||||
const unbindHideEvents = () => {
|
||||
document.removeEventListener('mousedown', clickDocumentHandler)
|
||||
document.removeEventListener('mousewheel', clickDocumentHandler)
|
||||
}
|
||||
|
||||
// 鼠标按压事件处理器
|
||||
const clickDocumentHandler = () => {
|
||||
emit('update:show', false)
|
||||
}
|
||||
|
||||
// 右键事件事件处理
|
||||
const contextMenuHandler = (e) => {
|
||||
x.value = e.clientX
|
||||
y.value = e.clientY
|
||||
layout()
|
||||
emit('update:show', true)
|
||||
emit('get-context-menu', e)
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
// 布局
|
||||
const layout = () => {
|
||||
style.value = {
|
||||
left: x.value + 'px',
|
||||
top: y.value + 'px',
|
||||
display: 'block'
|
||||
}
|
||||
}
|
||||
|
||||
// 取消绑定事件
|
||||
const unbindEvents = () => {
|
||||
if (!props.target) return
|
||||
props.target.removeEventListener('contextmenu', contextMenuHandler)
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -4,44 +4,50 @@
|
|||
<slot :name="slotKey" />
|
||||
</template>
|
||||
</a-modal>
|
||||
<a-drawer v-else :visible="visible" v-bind="$attrs" :footer-style="{ textAlign: 'right' }">
|
||||
<a-drawer v-else :visible="visible" v-bind="$attrs" @close="cancel" :footer-style="{ textAlign: 'right' }">
|
||||
<template v-for="slotKey in slotKeys" #[slotKey]>
|
||||
<slot :name="slotKey" />
|
||||
</template>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'pinia'
|
||||
<script setup>
|
||||
import { useSlots } from 'vue'
|
||||
const slots = useSlots()
|
||||
|
||||
import { globalStore } from '@/store'
|
||||
const store = globalStore()
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const FormContainerTypeEnum = {
|
||||
DRAWER: 'drawer',
|
||||
MODAL: 'modal'
|
||||
}
|
||||
export default {
|
||||
name: 'XnFormContainer',
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(globalStore, ['formStyle']),
|
||||
slotKeys() {
|
||||
return Object.keys(this.$slots)
|
||||
},
|
||||
isModal() {
|
||||
return FormContainerTypeEnum.MODAL === this.formStyle
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cancel() {
|
||||
this.$emit('close')
|
||||
}
|
||||
}
|
||||
|
||||
const formStyle = computed(() => {
|
||||
return store.formStyle
|
||||
})
|
||||
const slotKeys = computed(() => {
|
||||
return Object.keys(slots)
|
||||
})
|
||||
const isModal = computed(() => {
|
||||
return FormContainerTypeEnum.MODAL === formStyle.value
|
||||
})
|
||||
const emit = defineEmits(['close'])
|
||||
const cancel = () => {
|
||||
emit('close')
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// 声明额外的选项
|
||||
export default {
|
||||
inheritAttrs: false
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<!-- 本组件这兄弟写的很好 请参照:https://blog.csdn.net/weixin_41897680/article/details/124925222-->
|
||||
<div class="hljs-container" :codetype="props.language">
|
||||
<highlightjs :language="props.language" :autodetect="!props.language" :code="props.code"></highlightjs>
|
||||
<highlightjs :language="props.language" :autodetect="!props.language" :code="props.code" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -54,8 +54,8 @@
|
|||
}*/
|
||||
|
||||
/** 滚动条 */
|
||||
:deep(.hljs,.hljs-container) {
|
||||
max-height: 300px!important;
|
||||
:deep(.hljs, .hljs-container) {
|
||||
max-height: 300px !important;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,46 +37,50 @@ const app = createApp(App)
|
|||
app.use(vueEsign)
|
||||
// 局部
|
||||
import vueEsign from 'vue-esign'
|
||||
components: { vueEsign }
|
||||
// vue3 中只需需引入组件就可以使用无需注册
|
||||
```
|
||||
2. 页面中使用
|
||||
**必须设置 `ref` ,用来调用组件的两个内置方法 `reset()` 和 `generate()`**
|
||||
// 在组件中使用 ref="esign"
|
||||
**在script中必须设置 `const esign = ref()` ,用来调用组件的两个内置方法 `reset()` 和 `generate()`**
|
||||
|
||||
无需给组件设置 `style` 的宽高,如果画布的 `width`属性值没超出父元素的样式宽度,则该组件的样式宽度就是画布宽度,超出的话,组件样式宽度则是父元素的100%; 所以只需设置好父元素的宽度即可;
|
||||
```html
|
||||
<!-- vue2 -->
|
||||
<vue-esign ref="esign" :width="800" :height="300" :isCrop="isCrop" :lineWidth="lineWidth" :lineColor="lineColor" :bgColor.sync="bgColor" />
|
||||
|
||||
<!-- vue3 -->
|
||||
<vue-esign ref="esign" :width="800" :height="300" :isCrop="isCrop" :lineWidth="lineWidth" :lineColor="lineColor" v-model:bgColor="bgColor" />
|
||||
<vue-esign ref="esign" :width="800" :height="300" :isCrop="isCrop" :lineWidth="lineWidth" :lineColor="lineColor" v-model:bgColor="bgColor" :quality="1"/>
|
||||
|
||||
<!-- isClearBgColor为false时,不必再给bgColor加sync修饰符或v-model -->
|
||||
|
||||
<button @click="handleReset">清空画板</button>
|
||||
<button @click="handleGenerate">生成图片</button>
|
||||
```
|
||||
```js
|
||||
data () {
|
||||
return {
|
||||
lineWidth: 6,
|
||||
lineColor: '#000000',
|
||||
bgColor: '',
|
||||
resultImg: '',
|
||||
isCrop: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleReset () {
|
||||
this.$refs.esign.reset()
|
||||
},
|
||||
handleGenerate () {
|
||||
this.$refs.esign.generate().then(res => {
|
||||
this.resultImg = res
|
||||
}).catch(err => {
|
||||
alert(err) // 画布没有签字时会执行这里 'Not Signned'
|
||||
})
|
||||
}
|
||||
}
|
||||
<a-button type="primary" @click="handleGenerate">预览</a-button>
|
||||
<a-button @click="handleReset">清屏</a-button>
|
||||
```
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
const esign = ref(false) // 相当于$ref
|
||||
|
||||
// 这里const相当于vue2中的data()
|
||||
const resultImg = ref('')
|
||||
const isCrop = ref(false)
|
||||
const lineWidth = ref(6)
|
||||
const lineColor = ref('#000000')
|
||||
const bgColor = ref('')
|
||||
|
||||
const handleReset = () => {
|
||||
esign.value.reset()
|
||||
resultImg.value = ''
|
||||
}
|
||||
const handleGenerate = () => {
|
||||
esign.value
|
||||
.generate()
|
||||
.then((res) => {
|
||||
resultImg.value = res
|
||||
})
|
||||
.catch(() => {
|
||||
message.warning('无任何签字') // 画布没有签字时会执行这里 'Not Signned'
|
||||
})
|
||||
}
|
||||
</script>
|
||||
3. 说明
|
||||
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|
@ -95,7 +99,7 @@ methods: {
|
|||
|
||||
**清空画布**
|
||||
```js
|
||||
this.$refs.esign.reset()
|
||||
esign.value.reset()
|
||||
```
|
||||
|
||||
**生成图片**
|
||||
|
@ -103,7 +107,7 @@ this.$refs.esign.reset()
|
|||
```js
|
||||
// 可选配置参数 ,在未设置format或quality属性时可在生成图片时配置 例如: {format:'image/jpeg', quality: 0.5}
|
||||
// this.$refs.esign.generate({format:'image/jpeg', quality: 0.5})
|
||||
this.$refs.esign.generate().then(res => {
|
||||
esign.value.generate().then(res => {
|
||||
console.log(res) // base64图片
|
||||
}).catch(err => {
|
||||
alert(err) // 画布没有签字时会执行这里 'Not Signned'
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
<!--
|
||||
本插件来源于:https://github.com/JaimeCheng/vue-esign#readme
|
||||
因为集成进来跟我的Vue版本不一致,打包出问题,所以集成源码方式,感谢作者的源码
|
||||
-->
|
||||
<template>
|
||||
<canvas
|
||||
ref="canvas"
|
||||
|
@ -14,283 +10,283 @@
|
|||
></canvas>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
width: {
|
||||
type: Number,
|
||||
default: 800
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 300
|
||||
},
|
||||
lineWidth: {
|
||||
type: Number,
|
||||
default: 4
|
||||
},
|
||||
lineColor: {
|
||||
type: String,
|
||||
default: '#000000'
|
||||
},
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isCrop: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isClearBgColor: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
default: 'image/png'
|
||||
},
|
||||
quality: {
|
||||
type: Number,
|
||||
default: 1
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasDrew: false,
|
||||
resultImg: '',
|
||||
points: [],
|
||||
canvasTxt: null,
|
||||
startX: 0,
|
||||
startY: 0,
|
||||
isDrawing: false,
|
||||
sratio: 1
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
ratio() {
|
||||
return this.height / this.width
|
||||
},
|
||||
stageInfo() {
|
||||
return this.$refs.canvas.getBoundingClientRect()
|
||||
},
|
||||
myBg() {
|
||||
return this.bgColor ? this.bgColor : 'rgba(255, 255, 255, 0)'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
myBg: function (newVal) {
|
||||
this.$refs.canvas.style.background = newVal
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
window.addEventListener('resize', this.$_resizeHandler)
|
||||
},
|
||||
// eslint-disable-next-line vue/no-deprecated-destroyed-lifecycle
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.$_resizeHandler)
|
||||
},
|
||||
mounted() {
|
||||
const canvas = this.$refs.canvas
|
||||
canvas.height = this.height
|
||||
canvas.width = this.width
|
||||
canvas.style.background = this.myBg
|
||||
this.$_resizeHandler()
|
||||
// 在画板以外松开鼠标后冻结画笔
|
||||
document.onmouseup = () => {
|
||||
this.isDrawing = false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
$_resizeHandler() {
|
||||
const canvas = this.$refs.canvas
|
||||
canvas.style.width = this.width + 'px'
|
||||
const realw = parseFloat(window.getComputedStyle(canvas).width)
|
||||
canvas.style.height = this.ratio * realw + 'px'
|
||||
this.canvasTxt = canvas.getContext('2d')
|
||||
this.canvasTxt.scale(Number(this.sratio), Number(this.sratio))
|
||||
this.sratio = realw / this.width
|
||||
this.canvasTxt.scale(1 / this.sratio, 1 / this.sratio)
|
||||
},
|
||||
// pc
|
||||
mouseDown(e) {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
this.isDrawing = true
|
||||
this.hasDrew = true
|
||||
let obj = {
|
||||
x: e.offsetX,
|
||||
y: e.offsetY
|
||||
}
|
||||
this.drawStart(obj)
|
||||
},
|
||||
mouseMove(e) {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
if (this.isDrawing) {
|
||||
let obj = {
|
||||
x: e.offsetX,
|
||||
y: e.offsetY
|
||||
}
|
||||
this.drawMove(obj)
|
||||
}
|
||||
},
|
||||
mouseUp(e) {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
let obj = {
|
||||
x: e.offsetX,
|
||||
y: e.offsetY
|
||||
}
|
||||
this.drawEnd(obj)
|
||||
this.isDrawing = false
|
||||
},
|
||||
// mobile
|
||||
touchStart(e) {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
this.hasDrew = true
|
||||
if (e.touches.length === 1) {
|
||||
let obj = {
|
||||
x: e.targetTouches[0].clientX - this.$refs.canvas.getBoundingClientRect().left,
|
||||
y: e.targetTouches[0].clientY - this.$refs.canvas.getBoundingClientRect().top
|
||||
}
|
||||
this.drawStart(obj)
|
||||
}
|
||||
},
|
||||
touchMove(e) {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
if (e.touches.length === 1) {
|
||||
let obj = {
|
||||
x: e.targetTouches[0].clientX - this.$refs.canvas.getBoundingClientRect().left,
|
||||
y: e.targetTouches[0].clientY - this.$refs.canvas.getBoundingClientRect().top
|
||||
}
|
||||
this.drawMove(obj)
|
||||
}
|
||||
},
|
||||
touchEnd(e) {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
if (e.touches.length === 1) {
|
||||
let obj = {
|
||||
x: e.targetTouches[0].clientX - this.$refs.canvas.getBoundingClientRect().left,
|
||||
y: e.targetTouches[0].clientY - this.$refs.canvas.getBoundingClientRect().top
|
||||
}
|
||||
this.drawEnd(obj)
|
||||
}
|
||||
},
|
||||
// 绘制
|
||||
drawStart(obj) {
|
||||
this.startX = obj.x
|
||||
this.startY = obj.y
|
||||
this.canvasTxt.beginPath()
|
||||
this.canvasTxt.moveTo(this.startX, this.startY)
|
||||
this.canvasTxt.lineTo(obj.x, obj.y)
|
||||
this.canvasTxt.lineCap = 'round'
|
||||
this.canvasTxt.lineJoin = 'round'
|
||||
this.canvasTxt.lineWidth = this.lineWidth * this.sratio
|
||||
this.canvasTxt.stroke()
|
||||
this.canvasTxt.closePath()
|
||||
this.points.push(obj)
|
||||
},
|
||||
drawMove(obj) {
|
||||
this.canvasTxt.beginPath()
|
||||
this.canvasTxt.moveTo(this.startX, this.startY)
|
||||
this.canvasTxt.lineTo(obj.x, obj.y)
|
||||
this.canvasTxt.strokeStyle = this.lineColor
|
||||
this.canvasTxt.lineWidth = this.lineWidth * this.sratio
|
||||
this.canvasTxt.lineCap = 'round'
|
||||
this.canvasTxt.lineJoin = 'round'
|
||||
this.canvasTxt.stroke()
|
||||
this.canvasTxt.closePath()
|
||||
this.startY = obj.y
|
||||
this.startX = obj.x
|
||||
this.points.push(obj)
|
||||
},
|
||||
drawEnd(obj) {
|
||||
this.canvasTxt.beginPath()
|
||||
this.canvasTxt.moveTo(this.startX, this.startY)
|
||||
this.canvasTxt.lineTo(obj.x, obj.y)
|
||||
this.canvasTxt.lineCap = 'round'
|
||||
this.canvasTxt.lineJoin = 'round'
|
||||
this.canvasTxt.stroke()
|
||||
this.canvasTxt.closePath()
|
||||
this.points.push(obj)
|
||||
this.points.push({ x: -1, y: -1 })
|
||||
},
|
||||
// 操作
|
||||
generate(options) {
|
||||
let imgFormat = options && options.format ? options.format : this.format
|
||||
let imgQuality = options && options.quality ? options.quality : this.quality
|
||||
const pm = new Promise((resolve, reject) => {
|
||||
if (!this.hasDrew) {
|
||||
reject(`Warning: Not Signned!`)
|
||||
return
|
||||
}
|
||||
var resImgData = this.canvasTxt.getImageData(0, 0, this.$refs.canvas.width, this.$refs.canvas.height)
|
||||
this.canvasTxt.globalCompositeOperation = 'destination-over'
|
||||
this.canvasTxt.fillStyle = this.myBg
|
||||
this.canvasTxt.fillRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height)
|
||||
this.resultImg = this.$refs.canvas.toDataURL(imgFormat, imgQuality)
|
||||
var resultImg = this.resultImg
|
||||
this.canvasTxt.clearRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height)
|
||||
this.canvasTxt.putImageData(resImgData, 0, 0)
|
||||
this.canvasTxt.globalCompositeOperation = 'source-over'
|
||||
if (this.isCrop) {
|
||||
const crop_area = this.getCropArea(resImgData.data)
|
||||
var crop_canvas = document.createElement('canvas')
|
||||
const crop_ctx = crop_canvas.getContext('2d')
|
||||
crop_canvas.width = crop_area[2] - crop_area[0]
|
||||
crop_canvas.height = crop_area[3] - crop_area[1]
|
||||
const crop_imgData = this.canvasTxt.getImageData(...crop_area)
|
||||
crop_ctx.globalCompositeOperation = 'destination-over'
|
||||
crop_ctx.putImageData(crop_imgData, 0, 0)
|
||||
crop_ctx.fillStyle = this.myBg
|
||||
crop_ctx.fillRect(0, 0, crop_canvas.width, crop_canvas.height)
|
||||
resultImg = crop_canvas.toDataURL(imgFormat, imgQuality)
|
||||
crop_canvas = null
|
||||
}
|
||||
resolve(resultImg)
|
||||
})
|
||||
return pm
|
||||
},
|
||||
reset() {
|
||||
this.canvasTxt.clearRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height)
|
||||
if (this.isClearBgColor) {
|
||||
this.$emit('update:bgColor', '')
|
||||
this.$refs.canvas.style.background = 'rgba(255, 255, 255, 0)'
|
||||
}
|
||||
this.points = []
|
||||
this.hasDrew = false
|
||||
this.resultImg = ''
|
||||
},
|
||||
getCropArea(imgData) {
|
||||
var topX = this.$refs.canvas.width
|
||||
var btmX = 0
|
||||
var topY = this.$refs.canvas.height
|
||||
var btnY = 0
|
||||
for (var i = 0; i < this.$refs.canvas.width; i++) {
|
||||
for (var j = 0; j < this.$refs.canvas.height; j++) {
|
||||
var pos = (i + this.$refs.canvas.width * j) * 4
|
||||
if (imgData[pos] > 0 || imgData[pos + 1] > 0 || imgData[pos + 2] || imgData[pos + 3] > 0) {
|
||||
btnY = Math.max(j, btnY)
|
||||
btmX = Math.max(i, btmX)
|
||||
topY = Math.min(j, topY)
|
||||
topX = Math.min(i, topX)
|
||||
}
|
||||
}
|
||||
}
|
||||
topX++
|
||||
btmX++
|
||||
topY++
|
||||
btnY++
|
||||
const data = [topX, topY, btmX, btnY]
|
||||
return data
|
||||
<script setup>
|
||||
const canvas = ref()
|
||||
const emit = defineEmits(['update:bgColor'])
|
||||
|
||||
const props = defineProps({
|
||||
width: {
|
||||
type: Number,
|
||||
default: 800
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 300
|
||||
},
|
||||
lineWidth: {
|
||||
type: Number,
|
||||
default: 4
|
||||
},
|
||||
lineColor: {
|
||||
type: String,
|
||||
default: '#000000'
|
||||
},
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isCrop: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isClearBgColor: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
default: 'image/png'
|
||||
},
|
||||
quality: {
|
||||
type: Number,
|
||||
default: 1
|
||||
}
|
||||
})
|
||||
|
||||
const hasDrew = ref(false)
|
||||
const resultImg = ref('')
|
||||
const points = ref([])
|
||||
const canvasTxt = ref(null)
|
||||
const startX = ref(0)
|
||||
const startY = ref(0)
|
||||
const isDrawing = ref(false)
|
||||
const sratio = ref(1)
|
||||
|
||||
const ratio = computed(() => {
|
||||
return props.height / props.width
|
||||
})
|
||||
const stageInfo = computed(() => {
|
||||
return canvas.value.getBoundingClientRect()
|
||||
})
|
||||
const myBg = computed(() => {
|
||||
return props.bgColor ? props.bgColor : 'rgba(255, 255, 255, 0)'
|
||||
})
|
||||
|
||||
watch(myBg, (newVal) => {
|
||||
canvas.value.style.background = newVal
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
window.addEventListener('resize', $_resizeHandler)
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', $_resizeHandler)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
canvas.value.height = props.height
|
||||
canvas.value.width = props.width
|
||||
canvas.value.style.background = myBg.value
|
||||
$_resizeHandler()
|
||||
// 在画板以外松开鼠标后冻结画笔
|
||||
document.onmouseup = () => {
|
||||
isDrawing.value = false
|
||||
}
|
||||
})
|
||||
|
||||
const $_resizeHandler = () => {
|
||||
canvas.value.style.width = props.width + 'px'
|
||||
const realw = parseFloat(window.getComputedStyle(canvas.value).width)
|
||||
canvas.value.style.height = ratio.value * realw + 'px'
|
||||
canvasTxt.value = canvas.value.getContext('2d', { willReadFrequently: true })
|
||||
canvasTxt.value.scale(Number(sratio.value), Number(sratio.value))
|
||||
sratio.value = realw / props.width
|
||||
canvasTxt.value.scale(1 / sratio.value, 1 / sratio.value)
|
||||
}
|
||||
|
||||
// pc
|
||||
const mouseDown = (e) => {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
isDrawing.value = true
|
||||
hasDrew.value = true
|
||||
let obj = {
|
||||
x: e.offsetX,
|
||||
y: e.offsetY
|
||||
}
|
||||
drawStart(obj)
|
||||
}
|
||||
const mouseMove = (e) => {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
if (isDrawing.value) {
|
||||
let obj = {
|
||||
x: e.offsetX,
|
||||
y: e.offsetY
|
||||
}
|
||||
drawMove(obj)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
const mouseUp = (e) => {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
let obj = {
|
||||
x: e.offsetX,
|
||||
y: e.offsetY
|
||||
}
|
||||
drawEnd(obj)
|
||||
isDrawing.value = false
|
||||
}
|
||||
|
||||
// mobile
|
||||
const touchStart = (e) => {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
hasDrew.value = true
|
||||
if (e.touches.length === 1) {
|
||||
let obj = {
|
||||
x: e.targetTouches[0].clientX - canvas.value.getBoundingClientRect().left,
|
||||
y: e.targetTouches[0].clientY - canvas.value.getBoundingClientRect().top
|
||||
}
|
||||
drawStart(obj)
|
||||
}
|
||||
}
|
||||
const touchMove = (e) => {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
if (e.touches.length === 1) {
|
||||
let obj = {
|
||||
x: e.targetTouches[0].clientX - canvas.value.getBoundingClientRect().left,
|
||||
y: e.targetTouches[0].clientY - canvas.value.getBoundingClientRect().top
|
||||
}
|
||||
drawMove(obj)
|
||||
}
|
||||
}
|
||||
const touchEnd = (e) => {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
if (e.touches.length === 1) {
|
||||
let obj = {
|
||||
x: e.targetTouches[0].clientX - canvas.value.getBoundingClientRect().left,
|
||||
y: e.targetTouches[0].clientY - canvas.value.getBoundingClientRect().top
|
||||
}
|
||||
drawEnd(obj)
|
||||
}
|
||||
}
|
||||
// 绘制
|
||||
const drawStart = (obj) => {
|
||||
startX.value = obj.x
|
||||
startY.value = obj.y
|
||||
canvasTxt.value.beginPath()
|
||||
canvasTxt.value.moveTo(startX.value, startY.value)
|
||||
canvasTxt.value.lineTo(obj.x, obj.y)
|
||||
canvasTxt.value.lineCap = 'round'
|
||||
canvasTxt.value.lineJoin = 'round'
|
||||
canvasTxt.value.lineWidth = props.lineWidth * sratio.value
|
||||
canvasTxt.value.stroke()
|
||||
canvasTxt.value.closePath()
|
||||
points.value.push(obj)
|
||||
}
|
||||
const drawMove = (obj) => {
|
||||
canvasTxt.value.beginPath()
|
||||
canvasTxt.value.moveTo(startX.value, startY.value)
|
||||
canvasTxt.value.lineTo(obj.x, obj.y)
|
||||
canvasTxt.value.strokeStyle = props.lineColor
|
||||
canvasTxt.value.lineWidth = props.lineWidth * sratio.value
|
||||
canvasTxt.value.lineCap = 'round'
|
||||
canvasTxt.value.lineJoin = 'round'
|
||||
canvasTxt.value.stroke()
|
||||
canvasTxt.value.closePath()
|
||||
startY.value = obj.y
|
||||
startX.value = obj.x
|
||||
points.value.push(obj)
|
||||
}
|
||||
const drawEnd = (obj) => {
|
||||
canvasTxt.value.beginPath()
|
||||
canvasTxt.value.moveTo(startX.value, startY.value)
|
||||
canvasTxt.value.lineTo(obj.x, obj.y)
|
||||
canvasTxt.value.lineCap = 'round'
|
||||
canvasTxt.value.lineJoin = 'round'
|
||||
canvasTxt.value.stroke()
|
||||
canvasTxt.value.closePath()
|
||||
points.value.push(obj)
|
||||
points.value.push({ x: -1, y: -1 })
|
||||
}
|
||||
|
||||
// 操作
|
||||
const generate = (options) => {
|
||||
let imgFormat = options && options.format ? options.format : props.format
|
||||
let imgQuality = options && options.quality ? options.quality : props.quality
|
||||
const pm = new Promise((resolve, reject) => {
|
||||
if (!hasDrew.value) {
|
||||
reject(`Warning: Not Signned!`)
|
||||
return
|
||||
}
|
||||
var resImgData = canvasTxt.value.getImageData(0, 0, canvas.value.width, canvas.value.height)
|
||||
canvasTxt.value.globalCompositeOperation = 'destination-over'
|
||||
canvasTxt.value.fillStyle = myBg.value
|
||||
canvasTxt.value.fillRect(0, 0, canvas.value.width, canvas.value.height)
|
||||
resultImg.value = canvas.value.toDataURL(imgFormat, imgQuality)
|
||||
var resultImgData = resultImg.value
|
||||
canvasTxt.value.clearRect(0, 0, canvas.value.width, canvas.value.height)
|
||||
canvasTxt.value.putImageData(resImgData, 0, 0)
|
||||
canvasTxt.value.globalCompositeOperation = 'source-over'
|
||||
if (props.isCrop) {
|
||||
const crop_area = getCropArea(resImgData.data)
|
||||
var crop_canvas = document.createElement('canvas')
|
||||
const crop_ctx = crop_canvas.getContext('2d', { willReadFrequently: true })
|
||||
crop_canvas.width = crop_area[2] - crop_area[0]
|
||||
crop_canvas.height = crop_area[3] - crop_area[1]
|
||||
const crop_imgData = canvasTxt.value.getImageData(...crop_area)
|
||||
crop_ctx.globalCompositeOperation = 'destination-over'
|
||||
crop_ctx.putImageData(crop_imgData, 0, 0)
|
||||
crop_ctx.fillStyle = myBg.value
|
||||
crop_ctx.fillRect(0, 0, crop_canvas.width, crop_canvas.height)
|
||||
resultImgData = crop_canvas.toDataURL(imgFormat, imgQuality)
|
||||
crop_canvas = null
|
||||
}
|
||||
resolve(resultImgData)
|
||||
})
|
||||
return pm
|
||||
}
|
||||
const reset = () => {
|
||||
canvasTxt.value.clearRect(0, 0, canvas.value.width, canvas.value.height)
|
||||
if (props.isClearBgColor) {
|
||||
emit('update:bgColor', '')
|
||||
canvas.value.style.background = 'rgba(255, 255, 255, 0)'
|
||||
}
|
||||
points.value = []
|
||||
hasDrew.value = false
|
||||
resultImg.value = ''
|
||||
}
|
||||
const getCropArea = (imgData) => {
|
||||
let topX = canvas.value.width
|
||||
let btmX = 0
|
||||
let topY = canvas.value.height
|
||||
let btnY = 0
|
||||
for (let i = 0; i < canvas.value.width; i++) {
|
||||
for (let j = 0; j < canvas.value.height; j++) {
|
||||
let pos = (i + canvas.value.width * j) * 4
|
||||
if (imgData[pos] > 0 || imgData[pos + 1] > 0 || imgData[pos + 2] || imgData[pos + 3] > 0) {
|
||||
btnY = Math.max(j, btnY)
|
||||
btmX = Math.max(i, btmX)
|
||||
topY = Math.min(j, topY)
|
||||
topX = Math.min(i, topX)
|
||||
}
|
||||
}
|
||||
}
|
||||
topX++
|
||||
btmX++
|
||||
topY++
|
||||
btnY++
|
||||
return [topX, topY, btmX, btnY]
|
||||
}
|
||||
// 向父组件暴露使用的方法
|
||||
defineExpose({
|
||||
generate,
|
||||
reset
|
||||
})
|
||||
</script>
|
||||
<style scoped>
|
||||
canvas {
|
||||
max-width: 100%;
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
* 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
|
||||
* 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
|
||||
*/
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
/**
|
||||
* 图标选择器基础数据
|
||||
* 推荐前往https://icones.js.org下载图标的Vue文件,然后放在src/assets/icons文件夹里面
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
:href="navMenu.path"
|
||||
target="_blank"
|
||||
@click.stop="() => {}"
|
||||
>{{ navMenu.meta.title }}</a
|
||||
>{{ navMenu.meta.title }}</a
|
||||
>
|
||||
<a v-else>{{ navMenu.meta.title }}</a>
|
||||
</a-menu-item>
|
||||
|
|
|
@ -1,49 +1,53 @@
|
|||
<template>
|
||||
<div v-show="$route.meta.type === 'iframe'" class="iframe-pages">
|
||||
<div v-show="route.meta.type === 'iframe'" class="iframe-pages">
|
||||
<div></div>
|
||||
<iframe
|
||||
v-for="item in iframeList"
|
||||
v-show="$route.meta.url === item.meta.url"
|
||||
v-show="route.meta.url === item.meta.url"
|
||||
:key="item.meta.url"
|
||||
:src="item.meta.url"
|
||||
frameborder="0"
|
||||
></iframe>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapActions } from 'pinia'
|
||||
<script setup>
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { iframeStore, globalStore } from '@/store'
|
||||
const iStore = iframeStore()
|
||||
const store = globalStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
...mapState(iframeStore, ['iframeList']),
|
||||
...mapState(globalStore, ['isMobile', 'layoutTags'])
|
||||
},
|
||||
watch: {
|
||||
$route(e) {
|
||||
this.push(e)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.push(this.$route)
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
...mapActions(iframeStore, ['setIframeList', 'pushIframeList', 'clearIframeList']),
|
||||
push(route) {
|
||||
if (route.meta.type === 'iframe') {
|
||||
if (this.isMobile || !this.layoutTags) {
|
||||
this.setIframeList(route)
|
||||
} else {
|
||||
this.pushIframeList(route)
|
||||
}
|
||||
} else if (this.isMobile || !this.layoutTags) {
|
||||
this.clearIframeList()
|
||||
}
|
||||
const iframeList = computed(() => {
|
||||
return iStore.iframeList
|
||||
})
|
||||
|
||||
const isMobile = computed(() => {
|
||||
return store.isMobile
|
||||
})
|
||||
const layoutTags = computed(() => {
|
||||
return store.layoutTags
|
||||
})
|
||||
|
||||
watch(route, () => {
|
||||
push(router.currentRoute.value)
|
||||
})
|
||||
onBeforeMount(() => {
|
||||
push(router.currentRoute.value)
|
||||
})
|
||||
|
||||
const setIframeList = iStore.setIframeList
|
||||
const pushIframeList = iStore.pushIframeList
|
||||
const clearIframeList = iStore.clearIframeList
|
||||
const push = (route) => {
|
||||
if (route.meta.type === 'iframe') {
|
||||
if (isMobile || !layoutTags) {
|
||||
setIframeList(route)
|
||||
} else {
|
||||
pushIframeList(route)
|
||||
}
|
||||
} else if (isMobile || !layoutTags) {
|
||||
clearIframeList()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
</a-form-item>
|
||||
<a-form-item label="查收情况:" name="receiveInfoList">
|
||||
<s-table
|
||||
ref="table"
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:alert="false"
|
||||
|
@ -146,7 +146,7 @@
|
|||
Object.assign(message, data)
|
||||
formData.value = message
|
||||
receiveInfoList.value = data.receiveInfoList
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
})
|
||||
unreadMessageNum.value = Math.max(unreadMessageNum.value - 1, 0)
|
||||
}
|
||||
|
@ -161,7 +161,7 @@
|
|||
const formRef = ref()
|
||||
const receiveInfoList = ref([])
|
||||
const formData = ref({})
|
||||
const table = ref()
|
||||
const tableRef = ref()
|
||||
const columns = [
|
||||
{
|
||||
title: '姓名',
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
moduleBackColor.value
|
||||
? moduleMenu.classList.add('module-menu-color')
|
||||
: moduleMenu.classList.remove('module-menu-color')
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (err) {}
|
||||
setSelectedKeys()
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
/>
|
||||
</div>
|
||||
<a-divider />
|
||||
<a-form ref="form" class="text-right">
|
||||
<a-form ref="formRef" class="text-right">
|
||||
<a-form-item label="模块坞">
|
||||
<a-switch :checked="moduleUnfoldOpen" @change="toggleState('moduleUnfoldOpen')" />
|
||||
</a-form-item>
|
||||
|
@ -86,14 +86,12 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { colorList } from '@/config/settingConfig'
|
||||
import { ThemeModeEnum } from '@/utils/enum'
|
||||
import { globalStore } from '@/store'
|
||||
import { mapState, mapStores } from 'pinia'
|
||||
import tool from '@/utils/tool'
|
||||
|
||||
const store = globalStore()
|
||||
const toolDataNameMap = {
|
||||
menuIsCollapse: 'MENU_COLLAPSE',
|
||||
sideUniqueOpen: 'SIDE_UNIQUE_OPEN',
|
||||
|
@ -103,109 +101,121 @@
|
|||
topHeaderThemeColorSpread: 'TOP_HEADER_THEME_COLOR_SPREAD',
|
||||
moduleUnfoldOpen: 'MODULE_UNFOLD_OPEN'
|
||||
}
|
||||
export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
sideStyleList: [
|
||||
{
|
||||
tips: '暗色主题风格',
|
||||
value: ThemeModeEnum.DARK,
|
||||
style: 'snowy-setting-checkbox-item-dark'
|
||||
},
|
||||
{
|
||||
tips: '亮色主题风格',
|
||||
value: ThemeModeEnum.LIGHT,
|
||||
style: 'snowy-setting-checkbox-item-light'
|
||||
},
|
||||
{
|
||||
tips: '暗黑模式',
|
||||
value: ThemeModeEnum.REAL_DARK,
|
||||
style: 'snowy-setting-checkbox-item-realdark'
|
||||
}
|
||||
],
|
||||
layoutList: [
|
||||
{
|
||||
tips: '经典',
|
||||
value: 'classical',
|
||||
style: 'snowy-setting-layout-menu-classical'
|
||||
},
|
||||
{
|
||||
tips: '双排菜单',
|
||||
value: 'doublerow',
|
||||
style: 'snowy-setting-layout-menu-doublerow'
|
||||
}
|
||||
],
|
||||
xnFormStyleOptions: [
|
||||
{
|
||||
label: '抽屉',
|
||||
value: 'drawer'
|
||||
},
|
||||
{
|
||||
label: '对话框',
|
||||
value: 'modal'
|
||||
}
|
||||
],
|
||||
colorList
|
||||
}
|
||||
const sideStyleList = ref([
|
||||
{
|
||||
tips: '暗色主题风格',
|
||||
value: ThemeModeEnum.DARK,
|
||||
style: 'snowy-setting-checkbox-item-dark'
|
||||
},
|
||||
computed: {
|
||||
...mapStores(globalStore),
|
||||
...mapState(globalStore, [
|
||||
'theme',
|
||||
'themeColor',
|
||||
'layout',
|
||||
'menuIsCollapse',
|
||||
'sideUniqueOpen',
|
||||
'layoutTagsOpen',
|
||||
'breadcrumbOpen',
|
||||
'moduleUnfoldOpen',
|
||||
'topHeaderThemeColorOpen',
|
||||
'topHeaderThemeColorSpread',
|
||||
'formStyle'
|
||||
])
|
||||
{
|
||||
tips: '亮色主题风格',
|
||||
value: ThemeModeEnum.LIGHT,
|
||||
style: 'snowy-setting-checkbox-item-light'
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
changeTopHanderThemeColorOpen() {
|
||||
this.toggleState('topHeaderThemeColorOpen')
|
||||
if (!this.topHeaderThemeColorOpen) {
|
||||
this.globalStore.topHeaderThemeColorSpread = false
|
||||
tool.data.set('SNOWY_TOP_HEADER_THEME_COLOR_SPREAD', false)
|
||||
}
|
||||
},
|
||||
changeTopHanderThemeColorSpread() {
|
||||
this.toggleState('topHeaderThemeColorSpread')
|
||||
},
|
||||
toggleState(stateName) {
|
||||
this.globalStore.toggleConfig(stateName)
|
||||
const toolDataName = toolDataNameMap[stateName]
|
||||
tool.data.set(`SNOWY_${toolDataName}`, this.globalStore[stateName])
|
||||
},
|
||||
// 设置整体风格主题
|
||||
setSideStyle(value) {
|
||||
this.globalStore.setTheme(value)
|
||||
tool.data.set('SNOWY_THEME', value)
|
||||
},
|
||||
// 设置整体界面布局
|
||||
layoutStyle(value) {
|
||||
this.globalStore.setLayout(value)
|
||||
tool.data.set('SNOWY_LAYOUT', value)
|
||||
},
|
||||
// 切换颜色
|
||||
tagColor(value) {
|
||||
tool.data.set('SNOWY_THEME_COLOR', value)
|
||||
this.globalStore.setThemeColor(value)
|
||||
},
|
||||
// 切换表单风格
|
||||
formStyleChange(value) {
|
||||
tool.data.set('SNOWY_FORM_STYLE', value)
|
||||
this.globalStore.setFormStyle(value)
|
||||
}
|
||||
{
|
||||
tips: '暗黑模式',
|
||||
value: ThemeModeEnum.REAL_DARK,
|
||||
style: 'snowy-setting-checkbox-item-realdark'
|
||||
}
|
||||
])
|
||||
|
||||
const layoutList = ref([
|
||||
{
|
||||
tips: '经典',
|
||||
value: 'classical',
|
||||
style: 'snowy-setting-layout-menu-classical'
|
||||
},
|
||||
{
|
||||
tips: '双排菜单',
|
||||
value: 'doublerow',
|
||||
style: 'snowy-setting-layout-menu-doublerow'
|
||||
}
|
||||
])
|
||||
|
||||
const xnFormStyleOptions = ref([
|
||||
{
|
||||
label: '抽屉',
|
||||
value: 'drawer'
|
||||
},
|
||||
{
|
||||
label: '对话框',
|
||||
value: 'modal'
|
||||
}
|
||||
])
|
||||
|
||||
const theme = computed(() => {
|
||||
return store.theme
|
||||
})
|
||||
const themeColor = computed(() => {
|
||||
return store.themeColor
|
||||
})
|
||||
const layout = computed(() => {
|
||||
return store.layout
|
||||
})
|
||||
const menuIsCollapse = computed(() => {
|
||||
return store.menuIsCollapse
|
||||
})
|
||||
const sideUniqueOpen = computed(() => {
|
||||
return store.sideUniqueOpen
|
||||
})
|
||||
const layoutTagsOpen = computed(() => {
|
||||
return store.layoutTagsOpen
|
||||
})
|
||||
const breadcrumbOpen = computed(() => {
|
||||
return store.breadcrumbOpen
|
||||
})
|
||||
const moduleUnfoldOpen = computed(() => {
|
||||
return store.moduleUnfoldOpen
|
||||
})
|
||||
const topHeaderThemeColorOpen = computed(() => {
|
||||
return store.topHeaderThemeColorOpen
|
||||
})
|
||||
const topHeaderThemeColorSpread = computed(() => {
|
||||
return store.topHeaderThemeColorSpread
|
||||
})
|
||||
const formStyle = computed(() => {
|
||||
return store.formStyle
|
||||
})
|
||||
|
||||
const changeTopHanderThemeColorOpen = () => {
|
||||
toggleState('topHeaderThemeColorOpen')
|
||||
if (!topHeaderThemeColorOpen) {
|
||||
store.topHeaderThemeColorSpread = false
|
||||
tool.data.set('SNOWY_TOP_HEADER_THEME_COLOR_SPREAD', false)
|
||||
}
|
||||
}
|
||||
|
||||
const changeTopHanderThemeColorSpread = () => {
|
||||
toggleState('topHeaderThemeColorSpread')
|
||||
}
|
||||
const toggleState = (stateName) => {
|
||||
store.toggleConfig(stateName)
|
||||
const toolDataName = toolDataNameMap[stateName]
|
||||
tool.data.set(`SNOWY_${toolDataName}`, store[stateName])
|
||||
}
|
||||
// 设置整体风格主题
|
||||
const setSideStyle = (value) => {
|
||||
store.setTheme(value)
|
||||
tool.data.set('SNOWY_THEME', value)
|
||||
}
|
||||
// 设置整体界面布局
|
||||
const layoutStyle = (value) => {
|
||||
store.setLayout(value)
|
||||
tool.data.set('SNOWY_LAYOUT', value)
|
||||
}
|
||||
// 切换颜色
|
||||
const tagColor = (value) => {
|
||||
tool.data.set('SNOWY_THEME_COLOR', value)
|
||||
store.setThemeColor(value)
|
||||
}
|
||||
// 切换表单风格
|
||||
const formStyleChange = (value) => {
|
||||
tool.data.set('SNOWY_FORM_STYLE', value)
|
||||
store.setFormStyle(value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style type="less" scoped>
|
||||
<style lang="less" scoped>
|
||||
.snowy-setting-checkbox {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
|
|
|
@ -16,108 +16,100 @@
|
|||
</a-menu>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import NavMenu from './NavMenu.vue'
|
||||
import { globalStore } from '@/store'
|
||||
import { mapState } from 'pinia'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
NavMenu
|
||||
},
|
||||
directives: {
|
||||
drag(el) {
|
||||
const oDiv = el // 当前元素
|
||||
let firstTime = ''
|
||||
let lastTime = ''
|
||||
// 禁止选择网页上的文字
|
||||
// document.onselectstart = function() {
|
||||
// return false;
|
||||
// };
|
||||
oDiv.onmousedown = function (e) {
|
||||
// 鼠标按下,计算当前元素距离可视区的距离
|
||||
const disX = e.clientX - oDiv.offsetLeft
|
||||
const disY = e.clientY - oDiv.offsetTop
|
||||
document.onmousemove = function (e) {
|
||||
oDiv.setAttribute('drag-flag', true)
|
||||
firstTime = new Date().getTime()
|
||||
// 通过事件委托,计算移动的距离
|
||||
const l = e.clientX - disX
|
||||
const t = e.clientY - disY
|
||||
// 移动当前元素
|
||||
if (t > 0 && t < document.body.clientHeight - 50) {
|
||||
oDiv.style.top = `${t}px`
|
||||
}
|
||||
if (l > 0 && l < document.body.clientWidth - 50) {
|
||||
oDiv.style.left = `${l}px`
|
||||
}
|
||||
}
|
||||
document.onmouseup = function () {
|
||||
lastTime = new Date().getTime()
|
||||
if (lastTime - firstTime > 200) {
|
||||
oDiv.setAttribute('drag-flag', false)
|
||||
}
|
||||
document.onmousemove = null
|
||||
document.onmouseup = null
|
||||
}
|
||||
// return false不加的话可能导致黏连,就是拖到一个地方时div粘在鼠标上不下来,相当于onmouseup失效
|
||||
return false
|
||||
const router = useRouter()
|
||||
const store = globalStore()
|
||||
|
||||
const vDrag = (el) => {
|
||||
const oDiv = el // 当前元素
|
||||
let firstTime = ''
|
||||
let lastTime = ''
|
||||
// 禁止选择网页上的文字
|
||||
// document.onselectstart = function() {
|
||||
// return false;
|
||||
// };
|
||||
oDiv.onmousedown = function (e) {
|
||||
// 鼠标按下,计算当前元素距离可视区的距离
|
||||
const disX = e.clientX - oDiv.offsetLeft
|
||||
const disY = e.clientY - oDiv.offsetTop
|
||||
document.onmousemove = function (e) {
|
||||
oDiv.setAttribute('drag-flag', true)
|
||||
firstTime = new Date().getTime()
|
||||
// 通过事件委托,计算移动的距离
|
||||
const l = e.clientX - disX
|
||||
const t = e.clientY - disY
|
||||
// 移动当前元素
|
||||
if (t > 0 && t < document.body.clientHeight - 50) {
|
||||
oDiv.style.top = `${t}px`
|
||||
}
|
||||
if (l > 0 && l < document.body.clientWidth - 50) {
|
||||
oDiv.style.left = `${l}px`
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
menu: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(globalStore, ['sysBaseConfig'])
|
||||
},
|
||||
created() {
|
||||
const menu = this.$router.getMenu()
|
||||
this.menu = this.filterUrl(menu)
|
||||
},
|
||||
methods: {
|
||||
showMobileNav(e) {
|
||||
const isdrag = e.currentTarget.getAttribute('drag-flag')
|
||||
this.visible = true
|
||||
if (isdrag === 'true') {
|
||||
return false
|
||||
} else {
|
||||
this.visible = true
|
||||
document.onmouseup = function () {
|
||||
lastTime = new Date().getTime()
|
||||
if (lastTime - firstTime > 200) {
|
||||
oDiv.setAttribute('drag-flag', false)
|
||||
}
|
||||
},
|
||||
// 当菜单被选中时
|
||||
onSelect(obj) {
|
||||
const pathLength = obj.keyPath.length
|
||||
const path = obj.keyPath[pathLength - 1]
|
||||
this.$router.push({ path })
|
||||
this.visible = false
|
||||
},
|
||||
// 转换外部链接的路由
|
||||
filterUrl(map) {
|
||||
map.forEach((item, index) => {
|
||||
item.meta = item.meta ? item.meta : {}
|
||||
// 处理隐藏
|
||||
if (item.meta.hidden) {
|
||||
map.splice(index, 1)
|
||||
}
|
||||
// 处理http
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if (item.meta.type == 'iframe') {
|
||||
item.path = `/i/${item.name}`
|
||||
}
|
||||
// 递归循环
|
||||
if (item.children && item.children.length > 0) {
|
||||
item.children = this.filterUrl(item.children)
|
||||
}
|
||||
})
|
||||
return map
|
||||
document.onmousemove = null
|
||||
document.onmouseup = null
|
||||
}
|
||||
// return false不加的话可能导致黏连,就是拖到一个地方时div粘在鼠标上不下来,相当于onmouseup失效
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const visible = ref(false)
|
||||
const menu = ref([])
|
||||
|
||||
const sysBaseConfig = computed(() => {
|
||||
return store.sysBaseConfig
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
const menus = router.getMenu()
|
||||
menu.value = filterUrl(menus)
|
||||
})
|
||||
|
||||
const showMobileNav = (e) => {
|
||||
const isdrag = e.currentTarget.getAttribute('drag-flag')
|
||||
visible.value = true
|
||||
if (isdrag === 'true') {
|
||||
return false
|
||||
} else {
|
||||
visible.value = true
|
||||
}
|
||||
}
|
||||
// 当菜单被选中时
|
||||
const onSelect = (obj) => {
|
||||
const pathLength = obj.keyPath.length
|
||||
const path = obj.keyPath[pathLength - 1]
|
||||
router.push({ path })
|
||||
visible.value = false
|
||||
}
|
||||
// 转换外部链接的路由
|
||||
const filterUrl = (map) => {
|
||||
map.forEach((item, index) => {
|
||||
item.meta = item.meta ? item.meta : {}
|
||||
// 处理隐藏
|
||||
if (item.meta.hidden) {
|
||||
map.splice(index, 1)
|
||||
}
|
||||
// 处理http
|
||||
if (item.meta.type === 'iframe') {
|
||||
item.path = `/i/${item.name}`
|
||||
}
|
||||
// 递归循环
|
||||
if (item.children && item.children.length > 0) {
|
||||
item.children = filterUrl(item.children)
|
||||
}
|
||||
})
|
||||
return map
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -58,242 +58,245 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tool from '@/utils/tool'
|
||||
<script setup>
|
||||
import XnContextMenu from '@/components/XnContextMenu/index.vue'
|
||||
import { globalStore, iframeStore, keepAliveStore, viewTagsStore } from '@/store'
|
||||
import { mapState, mapActions } from 'pinia'
|
||||
import routerUtil from '@/utils/routerUtil'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { watch } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'Tags',
|
||||
components: { XnContextMenu },
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
// tagList: [],
|
||||
activeKey: this.$route.fullPath,
|
||||
maxTabs: 20,
|
||||
contextMenuTarget: null,
|
||||
contextMenuVisible: false,
|
||||
currentContextMenuTabIndex: 0
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const store = globalStore()
|
||||
const kStore = keepAliveStore()
|
||||
const iStore = iframeStore()
|
||||
const vStore = viewTagsStore()
|
||||
|
||||
const activeKey = ref()
|
||||
const maxTabs = ref(20)
|
||||
const contextMenuTarget = ref(null)
|
||||
const contextMenuVisible = ref(false)
|
||||
const currentContextMenuTabIndex = ref(0)
|
||||
|
||||
const viewTags = computed(() => {
|
||||
return vStore.viewTags
|
||||
})
|
||||
|
||||
const layoutTagsOpen = computed(() => {
|
||||
return store.layoutTagsOpen
|
||||
})
|
||||
|
||||
const tagList = computed(() => {
|
||||
return viewTags.value
|
||||
})
|
||||
|
||||
watch(route, (to) => {
|
||||
addViewTags(to)
|
||||
activeKey.value = to.fullPath
|
||||
})
|
||||
watch(layoutTagsOpen, () => {
|
||||
// closeOtherCacheTabs()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
const tabNavList = document.querySelector('.ant-tabs-nav-list')
|
||||
if (tabNavList) {
|
||||
contextMenuTarget.value = tabNavList
|
||||
}
|
||||
})
|
||||
// 增加tag
|
||||
const addViewTags = (to) => {
|
||||
activeKey.value = to.fullPath
|
||||
if (to.name && !to.meta.fullpage) {
|
||||
vStore.pushViewTags(to)
|
||||
kStore.pushKeepLive(to.name)
|
||||
}
|
||||
if (tagList.value.length - 1 > maxTabs.value) {
|
||||
const firstTag = tagList.value[1]
|
||||
vStore.removeViewTags(firstTag)
|
||||
}
|
||||
}
|
||||
|
||||
// 查找树
|
||||
const treeFind = (tree, func) => {
|
||||
for (const data of tree) {
|
||||
if (func(data)) return data
|
||||
if (data.children) {
|
||||
const res = treeFind(data.children, func)
|
||||
if (res) return res
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(viewTagsStore, ['viewTags']),
|
||||
...mapState(globalStore, ['layoutTagsOpen']),
|
||||
tagList() {
|
||||
return this.viewTags
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route(to) {
|
||||
this.addViewTags(to)
|
||||
},
|
||||
layoutTagsOpen() {
|
||||
this.closeOtherCacheTabs()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const module = this.$router.getMenu()
|
||||
const indexMenu = routerUtil.getIndexMenu(module).path
|
||||
// eslint-disable-next-line eqeqeq
|
||||
const dashboardRoute = this.treeFind(module, (node) => node.path === indexMenu)
|
||||
if (dashboardRoute) {
|
||||
dashboardRoute.fullPath = dashboardRoute.path
|
||||
this.addViewTags(dashboardRoute)
|
||||
this.addViewTags(this.$route)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const tabNavList = document.querySelector('.ant-tabs-nav-list')
|
||||
if (tabNavList) {
|
||||
this.contextMenuTarget = tabNavList
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions(viewTagsStore, ['addViewTags', 'pushViewTags', 'removeViewTags']),
|
||||
...mapActions(iframeStore, ['addIframe', 'removeIframeList', 'refreshIframe']),
|
||||
...mapActions(keepAliveStore, ['pushKeepLive', 'removeKeepLive', 'setRouteShow']),
|
||||
handleTabContextMenu(evt) {
|
||||
evt.preventDefault()
|
||||
let target = evt.target
|
||||
// 修复关闭时出现"使用了错误的类型或对象"的问题
|
||||
while (!target.classList.contains('ant-tabs-tab')) {
|
||||
if (target.classList.contains('ant-tabs')) {
|
||||
this.currentContextMenuTabIndex = 0
|
||||
return
|
||||
}
|
||||
target = target.parentNode
|
||||
}
|
||||
const tabList = document.querySelectorAll('.ant-tabs-nav-list .ant-tabs-tab')
|
||||
this.currentContextMenuTabIndex = Array.from(tabList).findIndex((tab) => tab === target)
|
||||
},
|
||||
onTabClick(tab) {
|
||||
this.$router.push(tab)
|
||||
},
|
||||
getCurrentTag() {
|
||||
return this.tagList[this.currentContextMenuTabIndex]
|
||||
},
|
||||
onTabRemove(tabKey, action) {
|
||||
if (action === 'remove') {
|
||||
const tag = this.tagList.find((tag) => tag.fullPath === tabKey)
|
||||
this.closeSelectedTag(tag)
|
||||
}
|
||||
},
|
||||
// 处理鼠标放开事件
|
||||
onTabUp(e) {
|
||||
// 鼠标中键
|
||||
if (e.which === 2) {
|
||||
this.handleTabContextMenu(e)
|
||||
this.closeTabs()
|
||||
}
|
||||
},
|
||||
getTabWrapEl() {
|
||||
return document.querySelector('.ant-tabs-nav-wrap')
|
||||
},
|
||||
scrollLeft() {
|
||||
const wrapEl = this.getTabWrapEl()
|
||||
if (wrapEl) {
|
||||
const event = new WheelEvent('wheel', { deltaX: 0, deltaY: -100 })
|
||||
wrapEl.dispatchEvent(event)
|
||||
}
|
||||
},
|
||||
scrollRight() {
|
||||
const wrapEl = this.getTabWrapEl()
|
||||
if (wrapEl) {
|
||||
const event = new WheelEvent('wheel', { deltaX: 0, deltaY: 100 })
|
||||
wrapEl.dispatchEvent(event)
|
||||
}
|
||||
},
|
||||
// 查找树
|
||||
treeFind(tree, func) {
|
||||
for (const data of tree) {
|
||||
if (func(data)) return data
|
||||
if (data.children) {
|
||||
const res = this.treeFind(data.children, func)
|
||||
if (res) return res
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
// 增加tag
|
||||
addViewTags(route) {
|
||||
this.activeKey = route.fullPath
|
||||
if (route.name && !route.meta.fullpage) {
|
||||
this.pushViewTags(route)
|
||||
this.pushKeepLive(route.name)
|
||||
}
|
||||
if (this.tagList.length - 1 > this.maxTabs) {
|
||||
const firstTag = this.tagList[1]
|
||||
this.removeViewTags(firstTag)
|
||||
}
|
||||
},
|
||||
// 高亮tag
|
||||
isActive(route) {
|
||||
return route.path === this.$route.path
|
||||
},
|
||||
// 关闭tag
|
||||
closeSelectedTag(tag, autoPushLatestView = true) {
|
||||
this.removeViewTags(tag)
|
||||
this.removeIframeList(tag)
|
||||
this.removeKeepLive(tag.name)
|
||||
if (autoPushLatestView && this.isActive(tag)) {
|
||||
const latestView = this.tagList.slice(-1)[0]
|
||||
if (latestView) {
|
||||
this.$router.push(latestView)
|
||||
} else {
|
||||
this.$router.push('/')
|
||||
}
|
||||
}
|
||||
},
|
||||
// TAB 刷新
|
||||
refreshTab() {
|
||||
this.contextMenuVisible = false
|
||||
const nowTag = this.getCurrentTag()
|
||||
// 判断是否当前路由,否的话跳转
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if (this.$route.fullPath !== nowTag.fullPath) {
|
||||
this.$router.push({
|
||||
path: nowTag.fullPath,
|
||||
query: nowTag.query
|
||||
})
|
||||
}
|
||||
this.refreshIframe(nowTag)
|
||||
setTimeout(() => {
|
||||
this.removeKeepLive(nowTag.name)
|
||||
this.setRouteShow(false)
|
||||
this.$nextTick(() => {
|
||||
this.pushKeepLive(nowTag.name)
|
||||
this.setRouteShow(true)
|
||||
})
|
||||
}, 0)
|
||||
},
|
||||
// TAB 关闭
|
||||
closeTabs() {
|
||||
this.contextMenuVisible = false
|
||||
const nowTag = this.getCurrentTag()
|
||||
if (!nowTag.meta.affix) {
|
||||
this.closeSelectedTag(nowTag)
|
||||
}
|
||||
},
|
||||
// TAB 关闭其他
|
||||
closeOtherTabs() {
|
||||
this.contextMenuVisible = false
|
||||
const nowTag = this.getCurrentTag()
|
||||
// 判断是否当前路由,否的话跳转
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if (this.$route.fullPath !== nowTag.fullPath) {
|
||||
this.$router.push({
|
||||
path: nowTag.fullPath,
|
||||
query: nowTag.query
|
||||
})
|
||||
}
|
||||
const tags = [...this.tagList]
|
||||
tags.forEach((tag) => {
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if ((tag.meta && tag.meta.affix) || nowTag.fullPath === tag.fullPath) {
|
||||
return true
|
||||
} else {
|
||||
this.closeSelectedTag(tag, false)
|
||||
}
|
||||
})
|
||||
},
|
||||
// 多标签功能关闭时关闭被缓存的标签
|
||||
closeOtherCacheTabs() {
|
||||
const tags = [...this.tagList]
|
||||
tags.forEach((tag) => {
|
||||
this.closeSelectedTag(tag, false)
|
||||
})
|
||||
},
|
||||
// TAB 最大化(包括标签栏)
|
||||
maximize() {
|
||||
this.contextMenuVisible = false
|
||||
const nowTag = this.getCurrentTag()
|
||||
// 判断是否当前路由,否的话跳转
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if (this.$route.fullPath !== nowTag.fullPath) {
|
||||
this.$router.push({
|
||||
path: nowTag.fullPath,
|
||||
query: nowTag.query
|
||||
})
|
||||
}
|
||||
document.getElementById('app').classList.add('main-maximize')
|
||||
},
|
||||
// 新窗口打开
|
||||
openWindow() {
|
||||
this.contextMenuVisible = false
|
||||
const nowTag = this.getCurrentTag()
|
||||
const url = nowTag.href || '/'
|
||||
if (!nowTag.meta.affix) {
|
||||
this.closeSelectedTag(nowTag)
|
||||
}
|
||||
window.open(url)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const getCurrentTag = () => {
|
||||
return tagList.value[currentContextMenuTabIndex.value]
|
||||
}
|
||||
|
||||
// 高亮tag
|
||||
const isActive = (to) => {
|
||||
return to.path === route.path
|
||||
}
|
||||
// 关闭tag
|
||||
const closeSelectedTag = (tag, autoPushLatestView = true) => {
|
||||
vStore.removeViewTags(tag)
|
||||
iStore.removeIframeList(tag)
|
||||
kStore.removeKeepLive(tag.name)
|
||||
if (autoPushLatestView && isActive(tag)) {
|
||||
const latestView = tagList.value.slice(-1)[0]
|
||||
if (latestView) {
|
||||
router.push(latestView)
|
||||
} else {
|
||||
router.push('/')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
// TAB 刷新
|
||||
const refreshTab = () => {
|
||||
contextMenuVisible.value = false
|
||||
const nowTag = getCurrentTag()
|
||||
// 判断是否当前路由,否的话跳转
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if (route.fullPath !== nowTag.fullPath) {
|
||||
router.push({
|
||||
path: nowTag.fullPath,
|
||||
query: nowTag.query
|
||||
})
|
||||
}
|
||||
iStore.refreshIframe(nowTag)
|
||||
setTimeout(() => {
|
||||
kStore.removeKeepLive(nowTag.name)
|
||||
kStore.setRouteShow(false)
|
||||
nextTick(() => {
|
||||
kStore.pushKeepLive(nowTag.name)
|
||||
kStore.setRouteShow(true)
|
||||
})
|
||||
}, 0)
|
||||
}
|
||||
|
||||
// TAB 关闭
|
||||
const closeTabs = () => {
|
||||
contextMenuVisible.value = false
|
||||
const nowTag = getCurrentTag()
|
||||
if (!nowTag.meta.affix) {
|
||||
closeSelectedTag(nowTag)
|
||||
}
|
||||
}
|
||||
// TAB 关闭其他
|
||||
const closeOtherTabs = () => {
|
||||
contextMenuVisible.value = false
|
||||
const nowTag = getCurrentTag()
|
||||
// 判断是否当前路由,否的话跳转
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if (route.fullPath !== nowTag.fullPath) {
|
||||
router.push({
|
||||
path: nowTag.fullPath,
|
||||
query: nowTag.query
|
||||
})
|
||||
}
|
||||
const tags = [...tagList.value]
|
||||
tags.forEach((tag) => {
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if ((tag.meta && tag.meta.affix) || nowTag.fullPath === tag.fullPath) {
|
||||
return true
|
||||
} else {
|
||||
closeSelectedTag(tag, false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 多标签功能关闭时关闭被缓存的标签
|
||||
const closeOtherCacheTabs = () => {
|
||||
const tags = [...tagList]
|
||||
tags.forEach((tag) => {
|
||||
closeSelectedTag(tag, false)
|
||||
})
|
||||
}
|
||||
// TAB 最大化(包括标签栏)
|
||||
const maximize = () => {
|
||||
contextMenuVisible.value = false
|
||||
const nowTag = getCurrentTag()
|
||||
// 判断是否当前路由,否的话跳转
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if (route.fullPath !== nowTag.fullPath) {
|
||||
router.push({
|
||||
path: nowTag.fullPath,
|
||||
query: nowTag.query
|
||||
})
|
||||
}
|
||||
document.getElementById('app').classList.add('main-maximize')
|
||||
}
|
||||
// 新窗口打开
|
||||
const openWindow = () => {
|
||||
contextMenuVisible.value = false
|
||||
const nowTag = getCurrentTag()
|
||||
const url = nowTag.path || '/'
|
||||
if (!nowTag.meta.affix) {
|
||||
closeSelectedTag(nowTag)
|
||||
}
|
||||
window.open(url)
|
||||
}
|
||||
|
||||
const handleTabContextMenu = (evt) => {
|
||||
evt.preventDefault()
|
||||
let target = evt.target
|
||||
// 修复关闭时出现"使用了错误的类型或对象"的问题
|
||||
while (!target.classList.contains('ant-tabs-tab')) {
|
||||
if (target.classList.contains('ant-tabs')) {
|
||||
currentContextMenuTabIndex.value = 0
|
||||
return
|
||||
}
|
||||
target = target.parentNode
|
||||
}
|
||||
const tabList = document.querySelectorAll('.ant-tabs-nav-list .ant-tabs-tab')
|
||||
currentContextMenuTabIndex.value = Array.from(tabList).findIndex((tab) => tab === target)
|
||||
}
|
||||
|
||||
const module = router.getMenu()
|
||||
const indexMenu = routerUtil.getIndexMenu(module).path
|
||||
// eslint-disable-next-line eqeqeq
|
||||
const dashboardRoute = treeFind(module, (node) => node.path === indexMenu)
|
||||
if (dashboardRoute) {
|
||||
dashboardRoute.fullPath = dashboardRoute.path
|
||||
addViewTags(dashboardRoute)
|
||||
addViewTags(route)
|
||||
}
|
||||
|
||||
const onTabRemove = (tabKey, action) => {
|
||||
if (action === 'remove') {
|
||||
const tag = tagList.value.find((tag) => tag.fullPath === tabKey)
|
||||
closeSelectedTag(tag)
|
||||
}
|
||||
}
|
||||
const onTabClick = (tab) => {
|
||||
router.push(tab)
|
||||
}
|
||||
// 处理鼠标放开事件
|
||||
const onTabUp = (e) => {
|
||||
// 鼠标中键
|
||||
if (e.which === 2) {
|
||||
handleTabContextMenu(e)
|
||||
closeTabs()
|
||||
}
|
||||
}
|
||||
const getTabWrapEl = () => {
|
||||
return document.querySelector('.ant-tabs-nav-wrap')
|
||||
}
|
||||
const scrollLeft = () => {
|
||||
const wrapEl = getTabWrapEl()
|
||||
if (wrapEl) {
|
||||
const event = new WheelEvent('wheel', { deltaX: 0, deltaY: -100 })
|
||||
wrapEl.dispatchEvent(event)
|
||||
}
|
||||
}
|
||||
const scrollRight = () => {
|
||||
const wrapEl = getTabWrapEl()
|
||||
if (wrapEl) {
|
||||
const event = new WheelEvent('wheel', { deltaX: 0, deltaY: 100 })
|
||||
wrapEl.dispatchEvent(event)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
.snowy-admin-tabs {
|
||||
&.ant-tabs {
|
||||
|
@ -316,7 +319,9 @@
|
|||
background: none;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
transition: background-color 0.3s, color 0.3s;
|
||||
transition:
|
||||
background-color 0.3s,
|
||||
color 0.3s;
|
||||
padding: 0 16px;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
|
|
|
@ -15,27 +15,22 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
breadList: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.getBreadcrumb()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getBreadcrumb()
|
||||
},
|
||||
methods: {
|
||||
getBreadcrumb() {
|
||||
const matched = this.$route.meta.breadcrumb
|
||||
this.breadList = matched
|
||||
}
|
||||
}
|
||||
const route = useRoute()
|
||||
const breadList = ref([])
|
||||
|
||||
watch(route, () => {
|
||||
getBreadcrumb()
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
getBreadcrumb()
|
||||
})
|
||||
|
||||
const getBreadcrumb = () => {
|
||||
breadList.value = route.meta.breadcrumb
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -53,9 +53,9 @@
|
|||
<Tags v-if="!isMobile && layoutTagsOpen" />
|
||||
<a-layout-content class="main-content-wrapper">
|
||||
<div id="admin-ui-main" class="admin-ui-main">
|
||||
<router-view v-slot="{ Component }" :key="route.fullPath">
|
||||
<keep-alive :include="keepLiveRoute">
|
||||
<component :is="Component" :key="route.name" v-if="routeShow" />
|
||||
<router-view v-slot="{ Component }">
|
||||
<keep-alive :include="kStore.keepLiveRoute">
|
||||
<component :is="Component" v-if="kStore.routeShow" :key="route.name" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
<iframe-view />
|
||||
|
@ -149,12 +149,12 @@
|
|||
</div>
|
||||
</div>
|
||||
<!-- 多标签 -->
|
||||
<Tags v-if="!isMobile && layoutTagsOpen"></Tags>
|
||||
<Tags v-if="!isMobile && layoutTagsOpen" />
|
||||
<a-layout-content class="main-content-wrapper">
|
||||
<div id="admin-ui-main" class="admin-ui-main">
|
||||
<router-view v-slot="{ Component }" :key="route.fullPath">
|
||||
<keep-alive :include="keepLiveRoute">
|
||||
<component :is="Component" v-if="routeShow" :key="route.name" />
|
||||
<router-view v-slot="{ Component }">
|
||||
<keep-alive :include="kStore.keepLiveRoute">
|
||||
<component :is="Component" v-if="kStore.routeShow" :key="route.name" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
<iframe-view />
|
||||
|
@ -215,6 +215,10 @@
|
|||
return store.theme
|
||||
})
|
||||
const layoutTagsOpen = computed(() => {
|
||||
// 当关闭多标签时,清理keepAlive的缓存
|
||||
if (!store.layoutTagsOpen) {
|
||||
kStore.keepLiveRoute = []
|
||||
}
|
||||
return store.layoutTagsOpen
|
||||
})
|
||||
const breadcrumbOpen = computed(() => {
|
||||
|
@ -235,12 +239,6 @@
|
|||
const module = computed(() => {
|
||||
return store.module
|
||||
})
|
||||
const keepLiveRoute = computed(() => {
|
||||
return kStore.keepLiveRoute
|
||||
})
|
||||
const routeShow = computed(() => {
|
||||
return kStore.routeShow
|
||||
})
|
||||
const sideTheme = computed(() => {
|
||||
return theme.value === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : theme.value
|
||||
})
|
||||
|
@ -355,6 +353,7 @@
|
|||
topHeaderThemeColorSpread.value
|
||||
? headerLogin.classList.add('snowy-header-logo-primary-color')
|
||||
: headerLogin.classList.remove('snowy-header-logo-primary-color')
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (e) {}
|
||||
// 如果是双排菜单,吧第二排的也给渲染了
|
||||
if (layout.value === 'doublerow') {
|
||||
|
@ -363,6 +362,7 @@
|
|||
topHeaderThemeColorSpread.value
|
||||
? snowyDoublerowSideTop.classList.add('snowy-doublerow-side-top-primary-color')
|
||||
: snowyDoublerowSideTop.classList.remove('snowy-doublerow-side-top-primary-color')
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
<template>
|
||||
<a-result status="403" title="403" sub-title="对不起,您没有访问此页面的权限。"> </a-result>
|
||||
<a-result status="403" title="403" sub-title="对不起,您没有访问此页面的权限。" />
|
||||
</template>
|
||||
|
|
|
@ -6,16 +6,13 @@
|
|||
</template>
|
||||
</a-result>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
gohome() {
|
||||
location.href = '/'
|
||||
},
|
||||
goback() {
|
||||
this.$router.go(-1)
|
||||
}
|
||||
}
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
const router = useRouter()
|
||||
const gohome = () => {
|
||||
location.href = '/'
|
||||
}
|
||||
const goback = () => {
|
||||
router.go(-1)
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -20,7 +20,7 @@ export default {
|
|||
searchKey: 'Search Key',
|
||||
imports: 'Import',
|
||||
more: 'More',
|
||||
export: 'Export',
|
||||
export: 'Export'
|
||||
},
|
||||
model: {
|
||||
user: 'user',
|
||||
|
|
|
@ -22,7 +22,7 @@ export default {
|
|||
searchKey: '关键词',
|
||||
imports: '导入',
|
||||
more: '更多',
|
||||
export: '导出',
|
||||
export: '导出'
|
||||
},
|
||||
model: {
|
||||
user: '用户',
|
||||
|
|
|
@ -109,7 +109,7 @@ router.beforeEach(async (to, from, next) => {
|
|||
apiMenu[0] = cloneDeep(userRoutes.module[0])
|
||||
}
|
||||
const childrenApiMenu = apiMenu[0].children
|
||||
apiMenu[0].children = [...childrenApiMenu ? childrenApiMenu : [], ...userRoutes.menu]
|
||||
apiMenu[0].children = [...(childrenApiMenu ? childrenApiMenu : []), ...userRoutes.menu]
|
||||
let menuRouter = filterAsyncRouter(apiMenu)
|
||||
menuRouter = flatAsyncRoutes(menuRouter)
|
||||
menuRouter.forEach((item) => {
|
||||
|
@ -148,7 +148,7 @@ router.getMenu = () => {
|
|||
apiMenu[0] = cloneDeep(userRoutes.module[0])
|
||||
}
|
||||
const childrenApiMenu = apiMenu[0].children
|
||||
apiMenu[0].children = [...childrenApiMenu ? childrenApiMenu : [], ...userRoutes.menu]
|
||||
apiMenu[0].children = [...(childrenApiMenu ? childrenApiMenu : []), ...userRoutes.menu]
|
||||
return filterUrl(apiMenu)
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ export default {
|
|||
app.use(customIcons)
|
||||
// 注册代码高亮组件 (博客:https://blog.csdn.net/weixin_41897680/article/details/124925222)
|
||||
// 注意:解决Vue使用highlight.js build打包发布后样式消失问题,原因是webpack在打包的时候没有把未被使用的代码打包进去,因此,在此处引用一下,看似无意义实则有用
|
||||
hljsCommon.highlightAuto('<h1>Highlight.js has been registered successfully!</h1>').value
|
||||
hljsCommon.highlightAuto('<h1>Highlight.js has been registered successfully!</h1>').value
|
||||
app.use(hljsVuePlugin)
|
||||
|
||||
// 全局代码错误捕捉
|
||||
|
|
|
@ -30,78 +30,133 @@ const getCacheConfig = (value) => {
|
|||
/**
|
||||
* deprecated 请使用 useGlobalStore
|
||||
*/
|
||||
export const globalStore = defineStore({
|
||||
id: 'global',
|
||||
state: () => ({
|
||||
// 移动端布局
|
||||
isMobile: false,
|
||||
// 布局
|
||||
layout: getCacheConfig('SNOWY_LAYOUT'),
|
||||
// 菜单是否折叠 toggle
|
||||
menuIsCollapse: getCacheConfig('SNOWY_MENU_COLLAPSE'),
|
||||
// 侧边菜单是否排他展开
|
||||
sideUniqueOpen: getCacheConfig('SNOWY_SIDE_UNIQUE_OPEN'),
|
||||
// 多标签栏
|
||||
layoutTagsOpen: getCacheConfig('SNOWY_LAYOUT_TAGS_OPEN'),
|
||||
// 是否展示面包屑
|
||||
breadcrumbOpen: getCacheConfig('SNOWY_BREADCRUMD_OPEN'),
|
||||
// 顶栏是否应用主题色
|
||||
topHeaderThemeColorOpen: getCacheConfig('SNOWY_TOP_HEADER_THEME_COLOR_OPEN'),
|
||||
// 顶栏主题色通栏
|
||||
topHeaderThemeColorSpread: getCacheConfig('SNOWY_TOP_HEADER_THEME_COLOR_SPREAD'),
|
||||
// 模块坞
|
||||
moduleUnfoldOpen: getCacheConfig('SNOWY_MODULE_UNFOLD_OPEN'),
|
||||
// 主题
|
||||
theme: getCacheConfig('SNOWY_THEME'),
|
||||
// 主题颜色
|
||||
themeColor: toolDataGet('SNOWY_THEME_COLOR') || config.COLOR,
|
||||
// 整体表单风格
|
||||
formStyle: getCacheConfig('SNOWY_FORM_STYLE'),
|
||||
// 用户信息
|
||||
userInfo: toolDataGet('USER_INFO') || {},
|
||||
// 系统配置
|
||||
sysBaseConfig: toolDataGet('SNOWY_SYS_BASE_CONFIG') || config.SYS_BASE_CONFIG,
|
||||
// 默认应用
|
||||
module: getCacheConfig('SNOWY_MENU_MODULE_ID')
|
||||
}),
|
||||
getters: {},
|
||||
actions: {
|
||||
setIsMobile(key) {
|
||||
this.isMobile = key
|
||||
},
|
||||
setLayout(key) {
|
||||
this.layout = key
|
||||
},
|
||||
setTheme(key) {
|
||||
this.theme = key
|
||||
const closeMessage = message.loading(`加载中...`)
|
||||
changeColor(this.themeColor, key).then(closeMessage)
|
||||
},
|
||||
setThemeColor(key) {
|
||||
this.themeColor = key
|
||||
const closeMessage = message.loading(`加载中...`)
|
||||
changeColor(key, this.theme).then(closeMessage)
|
||||
},
|
||||
initTheme() {
|
||||
const closeMessage = message.loading(`加载中...`)
|
||||
changeColor(this.themeColor, this.theme).then(closeMessage)
|
||||
},
|
||||
toggleConfig(key) {
|
||||
this[key] = !this[key]
|
||||
},
|
||||
setFormStyle(key) {
|
||||
this.formStyle = key
|
||||
},
|
||||
setUserInfo(key) {
|
||||
this.userInfo = key
|
||||
},
|
||||
setSysBaseConfig(key) {
|
||||
this.sysBaseConfig = key
|
||||
},
|
||||
setModule(key) {
|
||||
this.module = key
|
||||
export const globalStore = defineStore('global', () => {
|
||||
// 利用Vue3组合式API,ref()定义state的属性
|
||||
// function() 定义actions
|
||||
// computed 定义getters
|
||||
|
||||
// 定义state
|
||||
// 移动端布局
|
||||
const isMobile = ref(false)
|
||||
// 布局
|
||||
const layout = ref(getCacheConfig('SNOWY_LAYOUT'))
|
||||
|
||||
// 菜单是否折叠 toggle
|
||||
const menuIsCollapse = ref(getCacheConfig('SNOWY_MENU_COLLAPSE'))
|
||||
// 侧边菜单是否排他展开
|
||||
const sideUniqueOpen = ref(getCacheConfig('SNOWY_SIDE_UNIQUE_OPEN'))
|
||||
// 多标签栏
|
||||
const layoutTagsOpen = ref(getCacheConfig('SNOWY_LAYOUT_TAGS_OPEN'))
|
||||
// 是否展示面包屑
|
||||
const breadcrumbOpen = ref(getCacheConfig('SNOWY_BREADCRUMD_OPEN'))
|
||||
// 顶栏是否应用主题色
|
||||
const topHeaderThemeColorOpen = ref(getCacheConfig('SNOWY_TOP_HEADER_THEME_COLOR_OPEN'))
|
||||
// 顶栏主题色通栏
|
||||
const topHeaderThemeColorSpread = ref(getCacheConfig('SNOWY_TOP_HEADER_THEME_COLOR_SPREAD'))
|
||||
// 模块坞
|
||||
const moduleUnfoldOpen = ref(getCacheConfig('SNOWY_MODULE_UNFOLD_OPEN'))
|
||||
|
||||
// 主题
|
||||
const theme = ref(getCacheConfig('SNOWY_THEME'))
|
||||
// 主题颜色
|
||||
const themeColor = ref(toolDataGet('SNOWY_THEME_COLOR') || config.COLOR)
|
||||
// 整体表单风格
|
||||
const formStyle = ref(getCacheConfig('SNOWY_FORM_STYLE'))
|
||||
// 用户信息
|
||||
const userInfo = ref(toolDataGet('USER_INFO') || {})
|
||||
// 系统配置
|
||||
const sysBaseConfig = ref(toolDataGet('SNOWY_SYS_BASE_CONFIG') || config.SYS_BASE_CONFIG)
|
||||
// 默认应用
|
||||
const module = ref(getCacheConfig('SNOWY_MENU_MODULE_ID'))
|
||||
|
||||
// 定义action
|
||||
const setIsMobile = (key) => {
|
||||
isMobile.value = key
|
||||
}
|
||||
const setLayout = (key) => {
|
||||
layout.value = key
|
||||
}
|
||||
const setTheme = (key) => {
|
||||
theme.value = key
|
||||
const closeMessage = message.loading(`加载中...`)
|
||||
changeColor(themeColor.value, key).then(closeMessage)
|
||||
}
|
||||
const setThemeColor = (key) => {
|
||||
themeColor.value = key
|
||||
const closeMessage = message.loading(`加载中...`)
|
||||
changeColor(key, theme.value).then(closeMessage)
|
||||
}
|
||||
const initTheme = () => {
|
||||
const closeMessage = message.loading(`加载中...`)
|
||||
changeColor(themeColor.value, theme.value).then(closeMessage)
|
||||
}
|
||||
const toggleConfig = (key) => {
|
||||
switch (key) {
|
||||
case 'menuIsCollapse':
|
||||
menuIsCollapse.value = !menuIsCollapse.value
|
||||
break
|
||||
case 'topHeaderThemeColorSpread':
|
||||
topHeaderThemeColorSpread.value = !topHeaderThemeColorSpread.value
|
||||
break
|
||||
case 'sideUniqueOpen':
|
||||
sideUniqueOpen.value = !sideUniqueOpen.value
|
||||
break
|
||||
case 'layoutTagsOpen':
|
||||
layoutTagsOpen.value = !layoutTagsOpen.value
|
||||
break
|
||||
case 'breadcrumbOpen':
|
||||
breadcrumbOpen.value = !breadcrumbOpen.value
|
||||
break
|
||||
case 'topHeaderThemeColorOpen':
|
||||
topHeaderThemeColorOpen.value = !topHeaderThemeColorOpen.value
|
||||
topHeaderThemeColorSpread.value = topHeaderThemeColorOpen.value
|
||||
? topHeaderThemeColorSpread.value
|
||||
: topHeaderThemeColorOpen.value
|
||||
break
|
||||
case 'moduleUnfoldOpen':
|
||||
moduleUnfoldOpen.value = !moduleUnfoldOpen.value
|
||||
break
|
||||
}
|
||||
}
|
||||
const setFormStyle = (key) => {
|
||||
formStyle.value = key
|
||||
}
|
||||
const setUserInfo = (key) => {
|
||||
userInfo.value = key
|
||||
}
|
||||
const setSysBaseConfig = (key) => {
|
||||
sysBaseConfig.value = key
|
||||
}
|
||||
const setModule = (key) => {
|
||||
module.value = key
|
||||
}
|
||||
return {
|
||||
isMobile,
|
||||
layout,
|
||||
menuIsCollapse,
|
||||
sideUniqueOpen,
|
||||
layoutTagsOpen,
|
||||
breadcrumbOpen,
|
||||
topHeaderThemeColorOpen,
|
||||
topHeaderThemeColorSpread,
|
||||
moduleUnfoldOpen,
|
||||
theme,
|
||||
themeColor,
|
||||
formStyle,
|
||||
userInfo,
|
||||
sysBaseConfig,
|
||||
module,
|
||||
setIsMobile,
|
||||
setLayout,
|
||||
setTheme,
|
||||
setThemeColor,
|
||||
initTheme,
|
||||
toggleConfig,
|
||||
setFormStyle,
|
||||
setUserInfo,
|
||||
setSysBaseConfig,
|
||||
setModule
|
||||
}
|
||||
})
|
||||
|
||||
export const useGlobalStore = globalStore
|
||||
|
|
|
@ -10,43 +10,49 @@
|
|||
*/
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const iframeStore = defineStore({
|
||||
id: 'iframe',
|
||||
state: () => ({
|
||||
iframeList: []
|
||||
}),
|
||||
getters: {},
|
||||
actions: {
|
||||
setIframeList(route) {
|
||||
this.iframeList = []
|
||||
this.iframeList.push(route)
|
||||
},
|
||||
pushIframeList(route) {
|
||||
const target = this.iframeList.find((item) => item.path === route.path)
|
||||
if (!target) {
|
||||
this.iframeList.push(route)
|
||||
}
|
||||
},
|
||||
removeIframeList(route) {
|
||||
this.iframeList.forEach((item, index) => {
|
||||
if (item.path === route.path) {
|
||||
this.iframeList.splice(index, 1)
|
||||
}
|
||||
})
|
||||
},
|
||||
refreshIframe(route) {
|
||||
this.iframeList.forEach((item) => {
|
||||
if (item.path === route.path) {
|
||||
const url = route.meta.url
|
||||
item.meta.url = ''
|
||||
setTimeout(() => {
|
||||
item.meta.url = url
|
||||
}, 200)
|
||||
}
|
||||
})
|
||||
},
|
||||
clearIframeList() {
|
||||
this.iframeList = []
|
||||
export const iframeStore = defineStore('iframe', () => {
|
||||
// 定义state
|
||||
const iframeList = ref([])
|
||||
const setIframeList = (route) => {
|
||||
iframeList.value = []
|
||||
iframeList.value.push(route)
|
||||
}
|
||||
|
||||
// 定义action
|
||||
const pushIframeList = (route) => {
|
||||
const target = iframeList.value.find((item) => item.path === route.path)
|
||||
if (!target) {
|
||||
iframeList.value.push(route)
|
||||
}
|
||||
}
|
||||
const removeIframeList = (route) => {
|
||||
iframeList.value.forEach((item, index) => {
|
||||
if (item.path === route.path) {
|
||||
iframeList.value.splice(index, 1)
|
||||
}
|
||||
})
|
||||
}
|
||||
const refreshIframe = (route) => {
|
||||
iframeList.value.forEach((item) => {
|
||||
if (item.path === route.path) {
|
||||
const url = route.meta.url
|
||||
item.meta.url = ''
|
||||
setTimeout(() => {
|
||||
item.meta.url = url
|
||||
}, 200)
|
||||
}
|
||||
})
|
||||
}
|
||||
const clearIframeList = () => {
|
||||
iframeList.value = []
|
||||
}
|
||||
|
||||
return {
|
||||
iframeList,
|
||||
setIframeList,
|
||||
pushIframeList,
|
||||
removeIframeList,
|
||||
refreshIframe,
|
||||
clearIframeList
|
||||
}
|
||||
})
|
||||
|
|
|
@ -10,37 +10,46 @@
|
|||
*/
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const keepAliveStore = defineStore({
|
||||
id: 'keepAlive',
|
||||
state: () => ({
|
||||
keepLiveRoute: [],
|
||||
routeKey: null,
|
||||
routeShow: true
|
||||
}),
|
||||
getters: {},
|
||||
actions: {
|
||||
pushKeepLive(component) {
|
||||
if (!this.keepLiveRoute.includes(component)) {
|
||||
this.keepLiveRoute.push(component)
|
||||
}
|
||||
},
|
||||
removeKeepLive(component) {
|
||||
const index = this.keepLiveRoute.indexOf(component)
|
||||
if (index !== -1) {
|
||||
this.keepLiveRoute.splice(index, 1)
|
||||
}
|
||||
},
|
||||
clearKeepLive() {
|
||||
this.keepLiveRoute = []
|
||||
},
|
||||
setRouteKey(key) {
|
||||
this.routeKey = key
|
||||
},
|
||||
setRouteShow(key) {
|
||||
this.routeShow = key
|
||||
},
|
||||
setRouteKeyAction(key) {
|
||||
this.setRouteKey(key)
|
||||
export const keepAliveStore = defineStore('keepAlive', () => {
|
||||
// 定义state
|
||||
const keepLiveRoute = ref([])
|
||||
const routeKey = ref(null)
|
||||
const routeShow = ref(true)
|
||||
|
||||
// 定义action
|
||||
const pushKeepLive = (component) => {
|
||||
if (!keepLiveRoute.value.includes(component)) {
|
||||
keepLiveRoute.value.push(component)
|
||||
}
|
||||
}
|
||||
const removeKeepLive = (component) => {
|
||||
const index = keepLiveRoute.value.indexOf(component)
|
||||
if (index !== -1) {
|
||||
keepLiveRoute.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
const clearKeepLive = () => {
|
||||
keepLiveRoute.value = []
|
||||
}
|
||||
const setRouteKey = (key) => {
|
||||
routeKey.value = key
|
||||
}
|
||||
const setRouteShow = (key) => {
|
||||
routeShow.value = key
|
||||
}
|
||||
const setRouteKeyAction = (key) => {
|
||||
setRouteKey(key)
|
||||
}
|
||||
|
||||
return {
|
||||
keepLiveRoute,
|
||||
routeKey,
|
||||
routeShow,
|
||||
pushKeepLive,
|
||||
removeKeepLive,
|
||||
clearKeepLive,
|
||||
setRouteKey,
|
||||
setRouteShow,
|
||||
setRouteKeyAction
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,57 +1,63 @@
|
|||
import '@/utils/objects'
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const searchStore = defineStore({
|
||||
id: 'search',
|
||||
state: () => ({
|
||||
active: false,
|
||||
hotkey: {
|
||||
open: 's',
|
||||
close: 'esc'
|
||||
},
|
||||
pool: []
|
||||
}),
|
||||
getters: {},
|
||||
actions: {
|
||||
toggleActive() {
|
||||
this.active = !this.active
|
||||
},
|
||||
setActive(active) {
|
||||
this.active = active
|
||||
},
|
||||
init(menu) {
|
||||
const pool = []
|
||||
const getFullName = function (meta) {
|
||||
if (meta.breadcrumb) {
|
||||
let list = []
|
||||
meta.breadcrumb.forEach((item) => {
|
||||
list.push(item.meta.title)
|
||||
})
|
||||
return list.join(' / ')
|
||||
}
|
||||
return meta.title
|
||||
}
|
||||
const push = function (menu) {
|
||||
menu.forEach((m) => {
|
||||
if ('menu' === m.meta.type) {
|
||||
if (m.children) {
|
||||
push(m.children)
|
||||
} else if (m.children === null) {
|
||||
pool.push({
|
||||
icon: m.meta.icon,
|
||||
path: m.path,
|
||||
fullPath: m.path,
|
||||
name: m.meta.title,
|
||||
fullName: getFullName(m.meta),
|
||||
namePinyin: m.meta.title.toPinyin(),
|
||||
namePinyinFirst: m.meta.title.toPinyin(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
export const searchStore = defineStore('search', () => {
|
||||
// 定义state
|
||||
const pool = ref([])
|
||||
const hotkey = ref({
|
||||
open: 's',
|
||||
close: 'esc'
|
||||
})
|
||||
const active = ref(false)
|
||||
|
||||
// 定义action
|
||||
const toggleActive = () => {
|
||||
active.value = !active.value
|
||||
}
|
||||
const setActive = (val) => {
|
||||
active.value = val
|
||||
}
|
||||
const init = (menu) => {
|
||||
const poolList = []
|
||||
const getFullName = function (meta) {
|
||||
if (meta.breadcrumb) {
|
||||
let list = []
|
||||
meta.breadcrumb.forEach((item) => {
|
||||
list.push(item.meta.title)
|
||||
})
|
||||
return list.join(' / ')
|
||||
}
|
||||
push(menu)
|
||||
this.pool = pool
|
||||
return meta.title
|
||||
}
|
||||
const push = function (menu) {
|
||||
menu.forEach((m) => {
|
||||
if ('menu' === m.meta.type) {
|
||||
if (m.children) {
|
||||
push(m.children)
|
||||
} else if (m.children === null) {
|
||||
poolList.push({
|
||||
icon: m.meta.icon,
|
||||
path: m.path,
|
||||
fullPath: m.path,
|
||||
name: m.meta.title,
|
||||
fullName: getFullName(m.meta),
|
||||
namePinyin: m.meta.title.toPinyin(),
|
||||
namePinyinFirst: m.meta.title.toPinyin(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
push(menu)
|
||||
pool.value = poolList
|
||||
}
|
||||
|
||||
return {
|
||||
pool,
|
||||
hotkey,
|
||||
active,
|
||||
toggleActive,
|
||||
setActive,
|
||||
init
|
||||
}
|
||||
})
|
||||
|
|
|
@ -10,51 +10,59 @@
|
|||
*/
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const viewTagsStore = defineStore({
|
||||
id: 'viewTags',
|
||||
state: () => ({
|
||||
viewTags: []
|
||||
}),
|
||||
getters: {},
|
||||
actions: {
|
||||
pushViewTags(route) {
|
||||
const target = this.viewTags.find((item) => item.path === route.path)
|
||||
const isName = route.name
|
||||
if (!target && isName) {
|
||||
this.viewTags.push(route)
|
||||
}
|
||||
if (target) {
|
||||
this.viewTags.forEach((item) => {
|
||||
if (item.path === route.path) {
|
||||
Object.assign(item, route)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
removeViewTags(route) {
|
||||
this.viewTags.forEach((item, index) => {
|
||||
if (item.fullPath === route.fullPath) {
|
||||
this.viewTags.splice(index, 1)
|
||||
export const viewTagsStore = defineStore('viewTags', () => {
|
||||
// 定义state
|
||||
const viewTags = ref([])
|
||||
|
||||
// 定义action
|
||||
const pushViewTags = (route) => {
|
||||
const target = viewTags.value.find((item) => item.path === route.path)
|
||||
const isName = route.name
|
||||
if (!target && isName) {
|
||||
viewTags.value.push(route)
|
||||
}
|
||||
if (target) {
|
||||
viewTags.value.forEach((item, index) => {
|
||||
if (item.path === route.path) {
|
||||
viewTags.value[index] = { ...route, ...item }
|
||||
// Object.assign(item, route)
|
||||
}
|
||||
})
|
||||
},
|
||||
updateViewTags(route) {
|
||||
this.viewTags.forEach((item) => {
|
||||
if (item.fullPath == route.fullPath) {
|
||||
Object.assign(item, route)
|
||||
}
|
||||
})
|
||||
},
|
||||
updateViewTagsTitle(title = '') {
|
||||
const nowFullPath = location.hash.substring(1)
|
||||
this.viewTags.forEach((item) => {
|
||||
if (item.fullPath == nowFullPath) {
|
||||
item.meta.title = title
|
||||
}
|
||||
})
|
||||
},
|
||||
clearViewTags() {
|
||||
this.viewTags = []
|
||||
}
|
||||
}
|
||||
const removeViewTags = (route) => {
|
||||
viewTags.value.forEach((item, index) => {
|
||||
if (item.fullPath === route.fullPath) {
|
||||
viewTags.value.splice(index, 1)
|
||||
}
|
||||
})
|
||||
}
|
||||
const updateViewTags = (route) => {
|
||||
viewTags.value.forEach((item, index) => {
|
||||
if (item.fullPath === route.fullPath) {
|
||||
viewTags.value[index] = { ...route, ...item }
|
||||
// Object.assign(item, route)
|
||||
}
|
||||
})
|
||||
}
|
||||
const updateViewTagsTitle = (title = '') => {
|
||||
const nowFullPath = location.hash.substring(1)
|
||||
viewTags.value.forEach((item) => {
|
||||
if (item.fullPath === nowFullPath) {
|
||||
item.meta.title = title
|
||||
}
|
||||
})
|
||||
}
|
||||
const clearViewTags = () => {
|
||||
viewTags.value = []
|
||||
}
|
||||
|
||||
return {
|
||||
viewTags,
|
||||
pushViewTags,
|
||||
removeViewTags,
|
||||
updateViewTags,
|
||||
updateViewTagsTitle,
|
||||
clearViewTags
|
||||
}
|
||||
})
|
||||
|
|
|
@ -21,7 +21,7 @@ export default {
|
|||
RgbToHex(a, b, c) {
|
||||
const hexs = [a.toString(16), b.toString(16), c.toString(16)]
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if (hexs[i].length == 1) hexs[i] = `0${hexs[i]}`
|
||||
if (hexs[i].length === 1) hexs[i] = `0${hexs[i]}`
|
||||
}
|
||||
return `#${hexs.join('')}`
|
||||
},
|
||||
|
|
|
@ -57,13 +57,11 @@ export const watermark = {
|
|||
if (wmInstance) {
|
||||
// 避免一直触发
|
||||
// observer.disconnect();
|
||||
// console.log('水印属性修改了');
|
||||
wmInstance.setAttribute('style', styleStr)
|
||||
} else {
|
||||
/* 此处根据用户登录状态,判断是否终止监听,避免用户退出后登录页面仍然有水印 */
|
||||
if (tool.data.get('TOKEN')) {
|
||||
//标签被移除,重新添加标签
|
||||
// console.log('水印标签被移除了');
|
||||
document.body.appendChild(watermark)
|
||||
} else {
|
||||
observer.disconnect()
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
import loginApi from '@/api/auth/loginApi'
|
||||
import userCenterApi from '@/api/sys/userCenterApi'
|
||||
import dictApi from '@/api/dev/dictApi'
|
||||
import { onMounted } from 'vue'
|
||||
|
||||
onMounted(() => {
|
||||
// 获取当前url
|
||||
|
|
|
@ -97,140 +97,145 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import loginApi from '@/api/auth/loginApi'
|
||||
import phoneLoginForm from './phoneLoginForm.vue'
|
||||
import threeLogin from './threeLogin.vue'
|
||||
import PhoneLoginForm from './phoneLoginForm.vue'
|
||||
import ThreeLogin from './threeLogin.vue'
|
||||
import smCrypto from '@/utils/smCrypto'
|
||||
import { required } from '@/utils/formRules'
|
||||
import { afterLogin } from './util'
|
||||
import config from '@/config'
|
||||
import configData from '@/config'
|
||||
import configApi from '@/api/dev/configApi'
|
||||
import tool from '@/utils/tool'
|
||||
import { globalStore, iframeStore, keepAliveStore, viewTagsStore } from '@/store'
|
||||
import { mapActions, mapState } from 'pinia'
|
||||
const { proxy } = getCurrentInstance()
|
||||
|
||||
export default {
|
||||
name: 'Login',
|
||||
components: {
|
||||
phoneLoginForm,
|
||||
threeLogin
|
||||
const activeKey = ref('userAccount')
|
||||
const captchaOpen = ref(configData.SYS_BASE_CONFIG.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN)
|
||||
const validCodeBase64 = ref('')
|
||||
const loading = ref(false)
|
||||
|
||||
const ruleForm = reactive({
|
||||
account: 'superAdmin',
|
||||
password: '123456',
|
||||
validCode: '',
|
||||
validCodeReqNo: '',
|
||||
autologin: false
|
||||
})
|
||||
|
||||
const rules = reactive({
|
||||
account: [required(proxy.$t('login.accountError'), 'blur')],
|
||||
password: [required(proxy.$t('login.PWError'), 'blur')]
|
||||
})
|
||||
const lang = ref([
|
||||
{
|
||||
name: '简体中文',
|
||||
value: 'zh-cn'
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeKey: 'userAccount',
|
||||
captchaOpen: config.SYS_BASE_CONFIG.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN,
|
||||
validCodeBase64: '',
|
||||
ruleForm: {
|
||||
account: 'superAdmin',
|
||||
password: '123456',
|
||||
validCode: '',
|
||||
validCodeReqNo: '',
|
||||
autologin: false
|
||||
},
|
||||
rules: {
|
||||
account: [required(this.$t('login.accountError'), 'blur')],
|
||||
password: [required(this.$t('login.PWError'), 'blur')]
|
||||
},
|
||||
loading: false,
|
||||
config: {
|
||||
lang: tool.data.get('APP_LANG') || this.$CONFIG.LANG,
|
||||
theme: tool.data.get('APP_THEME') || 'default'
|
||||
},
|
||||
lang: [
|
||||
{
|
||||
name: '简体中文',
|
||||
value: 'zh-cn'
|
||||
},
|
||||
{
|
||||
name: 'English',
|
||||
value: 'en'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(globalStore, ['sysBaseConfig']),
|
||||
},
|
||||
watch: {
|
||||
'config.theme': function (val) {
|
||||
document.body.setAttribute('data-theme', val)
|
||||
},
|
||||
'config.lang': function (val) {
|
||||
this.$i18n.locale = val
|
||||
tool.data.set('APP_LANG', val)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.clearViewTags()
|
||||
this.clearKeepLive()
|
||||
this.clearIframeList()
|
||||
},
|
||||
mounted() {
|
||||
let formData = ref(config.SYS_BASE_CONFIG)
|
||||
configApi.configSysBaseList().then((data) => {
|
||||
if (data) {
|
||||
data.forEach((item) => {
|
||||
formData.value[item.configKey] = item.configValue
|
||||
})
|
||||
this.captchaOpen = formData.value.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN
|
||||
tool.data.set('SNOWY_SYS_BASE_CONFIG', formData.value)
|
||||
this.setSysBaseConfig(formData.value)
|
||||
this.refreshSwitch()
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
...mapActions(keepAliveStore, ['clearKeepLive']),
|
||||
...mapActions(viewTagsStore, ['clearViewTags']),
|
||||
...mapActions(iframeStore, ['clearIframeList']),
|
||||
...mapActions(globalStore, ['setSysBaseConfig']),
|
||||
// 通过开关加载内容
|
||||
refreshSwitch() {
|
||||
// 判断是否开启验证码
|
||||
if (this.captchaOpen === 'true') {
|
||||
// 加载验证码
|
||||
this.loginCaptcha()
|
||||
// 加入校验
|
||||
this.rules.validCode = [required(this.$t('login.validError'), 'blur')]
|
||||
}
|
||||
},
|
||||
// 获取验证码
|
||||
loginCaptcha() {
|
||||
loginApi.getPicCaptcha().then((data) => {
|
||||
this.validCodeBase64 = data.validCodeBase64
|
||||
this.ruleForm.validCodeReqNo = data.validCodeReqNo
|
||||
{
|
||||
name: 'English',
|
||||
value: 'en'
|
||||
}
|
||||
])
|
||||
const config = ref({
|
||||
lang: tool.data.get('APP_LANG') || proxy.$CONFIG.LANG,
|
||||
theme: tool.data.get('APP_THEME') || 'default'
|
||||
})
|
||||
|
||||
const store = globalStore()
|
||||
const kStore = keepAliveStore()
|
||||
const iStore = iframeStore()
|
||||
const vStore = viewTagsStore()
|
||||
|
||||
const setSysBaseConfig = store.setSysBaseConfig
|
||||
const clearKeepLive = kStore.clearKeepLive
|
||||
const clearIframeList = iStore.clearIframeList
|
||||
const clearViewTags = vStore.clearViewTags
|
||||
|
||||
const sysBaseConfig = computed(() => {
|
||||
return store.sysBaseConfig
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
let formData = ref(configData.SYS_BASE_CONFIG)
|
||||
configApi.configSysBaseList().then((data) => {
|
||||
if (data) {
|
||||
data.forEach((item) => {
|
||||
formData.value[item.configKey] = item.configValue
|
||||
})
|
||||
},
|
||||
// 用户名密码登录
|
||||
async login() {
|
||||
this.$refs.loginForm.validate().then(async () => {
|
||||
this.loading = true
|
||||
const loginData = {
|
||||
account: this.ruleForm.account,
|
||||
// 密码进行SM2加密,传输过程中看到的只有密文,后端存储使用hash
|
||||
password: smCrypto.doSm2Encrypt(this.ruleForm.password),
|
||||
validCode: this.ruleForm.validCode,
|
||||
validCodeReqNo: this.ruleForm.validCodeReqNo
|
||||
}
|
||||
// 获取token
|
||||
try {
|
||||
const loginToken = await loginApi.login(loginData)
|
||||
afterLogin(loginToken)
|
||||
} catch (err) {
|
||||
this.loading = false
|
||||
this.loginCaptcha()
|
||||
}
|
||||
})
|
||||
},
|
||||
configLang(key) {
|
||||
this.config.lang = key
|
||||
captchaOpen.value = formData.value.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN
|
||||
tool.data.set('SNOWY_SYS_BASE_CONFIG', formData.value)
|
||||
setSysBaseConfig(formData.value)
|
||||
refreshSwitch()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
clearViewTags()
|
||||
clearKeepLive()
|
||||
clearIframeList()
|
||||
})
|
||||
|
||||
// 监听语言
|
||||
watch(
|
||||
() => config.value.lang,
|
||||
(newValue) => {
|
||||
proxy.$i18n.locale = newValue
|
||||
tool.data.set('APP_LANG', newValue)
|
||||
}
|
||||
)
|
||||
// 主题
|
||||
watch(
|
||||
() => config.value.theme,
|
||||
(newValue) => {
|
||||
document.body.setAttribute('data-theme', newValue)
|
||||
}
|
||||
)
|
||||
// 通过开关加载内容
|
||||
const refreshSwitch = () => {
|
||||
// 判断是否开启验证码
|
||||
if (captchaOpen.value === 'true') {
|
||||
// 加载验证码
|
||||
loginCaptcha()
|
||||
// 加入校验
|
||||
rules.validCode = [required(proxy.$t('login.validError'), 'blur')]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
// 获取验证码
|
||||
const loginCaptcha = () => {
|
||||
loginApi.getPicCaptcha().then((data) => {
|
||||
validCodeBase64.value = data.validCodeBase64
|
||||
ruleForm.validCodeReqNo = data.validCodeReqNo
|
||||
})
|
||||
}
|
||||
//登陆
|
||||
const loginForm = ref()
|
||||
const login = async () => {
|
||||
loginForm.value.validate().then(async () => {
|
||||
loading.value = true
|
||||
const loginData = {
|
||||
account: ruleForm.account,
|
||||
// 密码进行SM2加密,传输过程中看到的只有密文,后端存储使用hash
|
||||
password: smCrypto.doSm2Encrypt(ruleForm.password),
|
||||
validCode: ruleForm.validCode,
|
||||
validCodeReqNo: ruleForm.validCodeReqNo
|
||||
}
|
||||
// 获取token
|
||||
try {
|
||||
const loginToken = await loginApi.login(loginData)
|
||||
afterLogin(loginToken)
|
||||
} catch (err) {
|
||||
loading.value = false
|
||||
loginCaptcha()
|
||||
}
|
||||
})
|
||||
}
|
||||
const configLang = (key) => {
|
||||
config.value.lang = key
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import 'login';
|
||||
</style>
|
||||
|
|
|
@ -22,7 +22,7 @@ export const afterLogin = async (loginToken) => {
|
|||
// 重置系统默认应用
|
||||
tool.data.set('SNOWY_MENU_MODULE_ID', menu[0].id)
|
||||
message.success('登录成功')
|
||||
if (!!tool.data.get('LAST_VIEWS_PATH')) {
|
||||
if (tool.data.get('LAST_VIEWS_PATH')) {
|
||||
// 如果有缓存,将其登录跳转到最后访问的路由
|
||||
indexMenu = tool.data.get('LAST_VIEWS_PATH')
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<s-table ref="table" :columns="columns" :data="loadDataB" :alert="false" bordered :row-key="(record) => record.id">
|
||||
<s-table ref="tableRef" :columns="columns" :data="loadDataB" :alert="false" bordered :row-key="(record) => record.id">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'avatar'">
|
||||
<a-avatar :src="record.avatar" style="width: 25px; height: 25px" />
|
||||
|
@ -18,13 +18,13 @@
|
|||
</template>
|
||||
</template>
|
||||
</s-table>
|
||||
<token-info-list ref="tokenInfoList" @successful="table.refresh()" />
|
||||
<token-info-list ref="tokenInfoList" @successful="tableRef.refresh()" />
|
||||
</template>
|
||||
|
||||
<script setup name="monitorBTab">
|
||||
import monitorApi from '@/api/auth/monitorApi'
|
||||
import TokenInfoList from './tokenInfoList.vue'
|
||||
const table = ref(null)
|
||||
const tableRef = ref(null)
|
||||
const tokenInfoList = ref()
|
||||
const columns = [
|
||||
{
|
||||
|
@ -83,7 +83,7 @@
|
|||
}
|
||||
]
|
||||
monitorApi.monitorBExit(params).then(() => {
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<s-table ref="table" :columns="columns" :data="loadDataC" :alert="false" bordered :row-key="(record) => record.id">
|
||||
<s-table ref="tableRef" :columns="columns" :data="loadDataC" :alert="false" bordered :row-key="(record) => record.id">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'avatar'">
|
||||
<a-avatar :src="record.avatar" style="width: 25px; height: 25px" />
|
||||
|
@ -18,13 +18,13 @@
|
|||
</template>
|
||||
</template>
|
||||
</s-table>
|
||||
<token-info-list ref="tokenInfoList" @successful="table.refresh()" />
|
||||
<token-info-list ref="tokenInfoList" @successful="tableRef.refresh()" />
|
||||
</template>
|
||||
|
||||
<script setup name="monitorCTab">
|
||||
import monitorApi from '@/api/auth/monitorApi'
|
||||
import TokenInfoList from './tokenInfoList.vue'
|
||||
const table = ref(null)
|
||||
const tableRef = ref(null)
|
||||
const tokenInfoList = ref()
|
||||
const columns = [
|
||||
{
|
||||
|
@ -83,7 +83,7 @@
|
|||
}
|
||||
]
|
||||
monitorApi.monitorCExit(params).then(() => {
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
</template>
|
||||
|
||||
<script setup name="authMonitor">
|
||||
import analyse from './analyse.vue'
|
||||
import monitorBTab from './bTab.vue'
|
||||
import monitorCTab from './cTab.vue'
|
||||
import Analyse from './analyse.vue'
|
||||
import MonitorBTab from './bTab.vue'
|
||||
import MonitorCTab from './cTab.vue'
|
||||
const activeKey = ref('1')
|
||||
</script>
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
<template>
|
||||
<xn-form-container
|
||||
title="令牌列表"
|
||||
:width="650"
|
||||
:visible="visible"
|
||||
:destroy-on-close="true"
|
||||
@close="onClose"
|
||||
>
|
||||
<xn-form-container title="令牌列表" :width="650" :visible="visible" :destroy-on-close="true" @close="onClose">
|
||||
<a-button
|
||||
danger
|
||||
style="margin-bottom: 10px"
|
||||
|
@ -104,7 +98,7 @@
|
|||
// 字段数据
|
||||
const loadData = ref([])
|
||||
// 默认是关闭状态
|
||||
let visible = $ref(false)
|
||||
const visible = ref(false)
|
||||
// 多选的
|
||||
const selectedRowKeys = ref([])
|
||||
const exitLoading = ref(false)
|
||||
|
@ -116,13 +110,13 @@
|
|||
const onOpen = (tokenInfoList, type) => {
|
||||
monitorType.value = type
|
||||
loadData.value = cloneDeep(tokenInfoList)
|
||||
visible = true
|
||||
visible.value = true
|
||||
}
|
||||
// 关闭抽屉
|
||||
const onClose = () => {
|
||||
loadData.value = []
|
||||
monitorType.value = ''
|
||||
visible = false
|
||||
visible.value = false
|
||||
}
|
||||
// 多选
|
||||
const rowSelection = {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-button type="primary" @click="table.refresh(true)">查询</a-button>
|
||||
<a-button type="primary" @click="tableRef.refresh(true)">查询</a-button>
|
||||
<a-button style="margin: 0 8px" @click="reset">重置</a-button>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
@ -22,7 +22,7 @@
|
|||
</a-card>
|
||||
<a-card :bordered="false">
|
||||
<s-table
|
||||
ref="table"
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:alert="false"
|
||||
|
@ -45,9 +45,9 @@
|
|||
<script setup name="authThird">
|
||||
import thirdApi from '@/api/auth/thirdApi'
|
||||
import tool from '@/utils/tool'
|
||||
let searchFormState = reactive({})
|
||||
const searchFormState = ref({})
|
||||
const searchFormRef = ref()
|
||||
const table = ref()
|
||||
const tableRef = ref()
|
||||
const toolConfig = { refresh: true, height: true, columnSetting: false, striped: false }
|
||||
const columns = [
|
||||
{
|
||||
|
@ -83,14 +83,14 @@
|
|||
}
|
||||
]
|
||||
const loadData = (parameter) => {
|
||||
return thirdApi.thirdPage(Object.assign(parameter, searchFormState)).then((res) => {
|
||||
return thirdApi.thirdPage(Object.assign(parameter, searchFormState.value)).then((res) => {
|
||||
return res
|
||||
})
|
||||
}
|
||||
// 重置
|
||||
const reset = () => {
|
||||
searchFormRef.value.resetFields();
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
}
|
||||
// 分类
|
||||
const categoryOptions = tool.dictList('THIRD_CATEGORY')
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-button type="primary" @click="table.refresh(true)">
|
||||
<a-button type="primary" @click="tableRef.refresh(true)">
|
||||
<template #icon><SearchOutlined /></template>
|
||||
查询
|
||||
</a-button>
|
||||
|
@ -41,7 +41,7 @@
|
|||
</a-card>
|
||||
<a-card :bordered="false" style="margin-bottom: 10px">
|
||||
<s-table
|
||||
ref="table"
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:expand-row-by-click="true"
|
||||
|
@ -95,7 +95,7 @@
|
|||
})
|
||||
}
|
||||
// 定义tableDOM
|
||||
const table = ref(null)
|
||||
const tableRef = ref(null)
|
||||
const formRef = ref()
|
||||
const cardLoading = ref(true)
|
||||
const searchFormRef = ref()
|
||||
|
@ -136,7 +136,7 @@
|
|||
// 重置
|
||||
const reset = () => {
|
||||
searchFormRef.value.resetFields()
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
}
|
||||
// 加载左侧的树
|
||||
const loadTreeData = () => {
|
||||
|
@ -166,11 +166,11 @@
|
|||
delete searchFormState.value.parentId
|
||||
columns.splice(2, 1)
|
||||
}
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
}
|
||||
// 表单界面回调
|
||||
const formSuccessful = () => {
|
||||
table.value.refresh()
|
||||
tableRef.value.refresh()
|
||||
refreshStoreDict()
|
||||
}
|
||||
// 刷新store中的字典
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
// 定义emit事件
|
||||
const emit = defineEmits({ successful: null })
|
||||
// 默认是关闭状态
|
||||
let visible = $ref(false)
|
||||
const visible = ref(false)
|
||||
let UserSelectorPlus = ref()
|
||||
const formRef = ref()
|
||||
// 表单数据,也就是默认给一些数据
|
||||
|
@ -83,7 +83,7 @@
|
|||
|
||||
// 打开抽屉
|
||||
const onOpen = (record, parentId) => {
|
||||
visible = true
|
||||
visible.value = true
|
||||
formData.value = {
|
||||
sortCode: 99
|
||||
}
|
||||
|
@ -112,7 +112,7 @@
|
|||
}
|
||||
// 关闭抽屉
|
||||
const onClose = () => {
|
||||
visible = false
|
||||
visible.value = false
|
||||
}
|
||||
// 默认要校验的
|
||||
const formRules = {
|
||||
|
@ -152,7 +152,7 @@
|
|||
bizOrgApi
|
||||
.submitForm(formData.value, formData.value.id)
|
||||
.then(() => {
|
||||
visible = false
|
||||
visible.value = false
|
||||
emit('successful')
|
||||
})
|
||||
.finally(() => {
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-button type="primary" @click="table.refresh(true)">
|
||||
<a-button type="primary" @click="tableRef.refresh(true)">
|
||||
<template #icon><SearchOutlined /></template>
|
||||
查询
|
||||
</a-button>
|
||||
|
@ -37,7 +37,7 @@
|
|||
</a-card>
|
||||
<a-card :bordered="false">
|
||||
<s-table
|
||||
ref="table"
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:expand-row-by-click="true"
|
||||
|
@ -51,7 +51,7 @@
|
|||
<a-space>
|
||||
<a-button
|
||||
type="primary"
|
||||
@click="form.onOpen(undefined, searchFormState.parentId)"
|
||||
@click="formRef.onOpen(undefined, searchFormState.parentId)"
|
||||
v-if="hasPerm('bizOrgAdd')"
|
||||
>
|
||||
<template #icon><plus-outlined /></template>
|
||||
|
@ -69,7 +69,7 @@
|
|||
{{ $TOOL.dictTypeData('ORG_CATEGORY', record.category) }}
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<a @click="form.onOpen(record)" v-if="hasPerm('bizOrgEdit')">编辑</a>
|
||||
<a @click="formRef.onOpen(record)" v-if="hasPerm('bizOrgEdit')">编辑</a>
|
||||
<a-divider type="vertical" v-if="hasPerm(['bizOrgEdit', 'bizOrgDelete'], 'and')" />
|
||||
<a-popconfirm title="删除此机构与下级机构吗?" @confirm="removeOrg(record)">
|
||||
<a-button type="link" danger size="small" v-if="hasPerm('bizOrgDelete')">删除</a-button>
|
||||
|
@ -80,7 +80,7 @@
|
|||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<Form ref="form" @successful="table.refresh()" />
|
||||
<Form ref="formRef" @successful="tableRef.refresh()" />
|
||||
</template>
|
||||
|
||||
<script setup name="bizOrg">
|
||||
|
@ -129,8 +129,8 @@
|
|||
}
|
||||
const toolConfig = { refresh: true, height: true, columnSetting: true }
|
||||
// 定义tableDOM
|
||||
const table = ref(null)
|
||||
const form = ref()
|
||||
const tableRef = ref(null)
|
||||
const formRef = ref()
|
||||
const searchFormRef = ref()
|
||||
const searchFormState = ref({})
|
||||
// 默认展开的节点
|
||||
|
@ -150,7 +150,7 @@
|
|||
// 重置
|
||||
const reset = () => {
|
||||
searchFormRef.value.resetFields()
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
}
|
||||
// 加载左侧的树
|
||||
const loadTreeData = () => {
|
||||
|
@ -188,7 +188,7 @@
|
|||
} else {
|
||||
delete searchFormState.value.parentId
|
||||
}
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
}
|
||||
// 删除
|
||||
const removeOrg = (record) => {
|
||||
|
@ -198,13 +198,13 @@
|
|||
}
|
||||
]
|
||||
bizOrgApi.orgDelete(params).then(() => {
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
})
|
||||
}
|
||||
// 批量删除
|
||||
const deleteBatchOrg = (params) => {
|
||||
bizOrgApi.orgDelete(params).then(() => {
|
||||
table.value.clearRefreshSelected()
|
||||
tableRef.value.clearRefreshSelected()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-button type="primary" @click="table.refresh(true)">
|
||||
<a-button type="primary" @click="tableRef.refresh(true)">
|
||||
<template #icon><SearchOutlined /></template>
|
||||
查询
|
||||
</a-button>
|
||||
|
@ -37,7 +37,7 @@
|
|||
</a-card>
|
||||
<a-card :bordered="false">
|
||||
<s-table
|
||||
ref="table"
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:expand-row-by-click="true"
|
||||
|
@ -80,7 +80,7 @@
|
|||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<Form ref="formRef" @successful="table.refresh(true)" />
|
||||
<Form ref="formRef" @successful="tableRef.refresh(true)" />
|
||||
</template>
|
||||
|
||||
<script setup name="bizPosition">
|
||||
|
@ -129,7 +129,7 @@
|
|||
}
|
||||
const toolConfig = { refresh: true, height: true, columnSetting: true }
|
||||
// 定义tableDOM
|
||||
const table = ref(null)
|
||||
const tableRef = ref(null)
|
||||
const formRef = ref()
|
||||
const searchFormRef = ref()
|
||||
const searchFormState = ref({})
|
||||
|
@ -149,7 +149,7 @@
|
|||
// 重置
|
||||
const reset = () => {
|
||||
searchFormRef.value.resetFields()
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
}
|
||||
// 加载左侧的树
|
||||
bizOrgApi
|
||||
|
@ -185,7 +185,7 @@
|
|||
} else {
|
||||
delete searchFormState.value.orgId
|
||||
}
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
}
|
||||
// 删除
|
||||
const removeOrg = (record) => {
|
||||
|
@ -195,13 +195,13 @@
|
|||
}
|
||||
]
|
||||
bizPositionApi.positionDelete(params).then(() => {
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
})
|
||||
}
|
||||
// 批量删除
|
||||
const deleteBatchPosition = (params) => {
|
||||
bizPositionApi.positionDelete(params).then(() => {
|
||||
table.value.clearRefreshSelected()
|
||||
tableRef.value.clearRefreshSelected()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-button type="primary" @click="table.refresh(true)">
|
||||
<a-button type="primary" @click="tableRef.refresh(true)">
|
||||
<template #icon><SearchOutlined /></template>
|
||||
{{ $t('common.searchButton') }}
|
||||
</a-button>
|
||||
|
@ -49,7 +49,7 @@
|
|||
</a-card>
|
||||
<a-card :bordered="false">
|
||||
<s-table
|
||||
ref="table"
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:expand-row-by-click="true"
|
||||
|
@ -140,7 +140,7 @@
|
|||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<Form ref="formRef" @successful="table.refresh()" />
|
||||
<Form ref="formRef" @successful="tableRef.refresh()" />
|
||||
<role-selector-plus
|
||||
ref="RoleSelectorPlusRef"
|
||||
:org-tree-api="selectorApiFunction.orgTreeApi"
|
||||
|
@ -216,7 +216,7 @@
|
|||
const searchFormRef = ref()
|
||||
const defaultExpandedKeys = ref([])
|
||||
const searchFormState = ref({})
|
||||
const table = ref(null)
|
||||
const tableRef = ref(null)
|
||||
const treeData = ref([])
|
||||
const selectedRowKeys = ref([])
|
||||
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
||||
|
@ -234,7 +234,7 @@
|
|||
// 重置
|
||||
const reset = () => {
|
||||
searchFormRef.value.resetFields()
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
}
|
||||
// 左侧树查询
|
||||
bizOrgApi
|
||||
|
@ -284,7 +284,7 @@
|
|||
} else {
|
||||
delete searchFormState.value.orgId
|
||||
}
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
}
|
||||
// 修改状态
|
||||
const editStatus = (record) => {
|
||||
|
@ -293,7 +293,7 @@
|
|||
bizUserApi
|
||||
.userDisableUser(record)
|
||||
.then(() => {
|
||||
table.value.refresh()
|
||||
tableRef.value.refresh()
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
|
@ -302,7 +302,7 @@
|
|||
bizUserApi
|
||||
.userEnableUser(record)
|
||||
.then(() => {
|
||||
table.value.refresh()
|
||||
tableRef.value.refresh()
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
|
@ -317,7 +317,7 @@
|
|||
}
|
||||
]
|
||||
bizUserApi.userDelete(params).then(() => {
|
||||
table.value.refresh()
|
||||
tableRef.value.refresh()
|
||||
})
|
||||
}
|
||||
// 批量导出校验并加参数
|
||||
|
@ -348,13 +348,13 @@
|
|||
const exportBatchUser = (params) => {
|
||||
bizUserApi.userExport(params).then((res) => {
|
||||
downloadUtil.resultDownload(res)
|
||||
table.value.clearSelected()
|
||||
tableRef.value.clearSelected()
|
||||
})
|
||||
}
|
||||
// 批量删除
|
||||
const deleteBatchUser = (params) => {
|
||||
bizUserApi.userDelete(params).then(() => {
|
||||
table.value.clearRefreshSelected()
|
||||
tableRef.value.clearRefreshSelected()
|
||||
})
|
||||
}
|
||||
// 打开角色选择器
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
</template>
|
||||
|
||||
<script setup name="emailConfig">
|
||||
import localEmailForm from './localEmailForm.vue'
|
||||
import aliyunEmailForm from './aliyunEmailForm.vue'
|
||||
import tencentEmailForm from './tencentEmailForm.vue'
|
||||
import LocalEmailForm from './localEmailForm.vue'
|
||||
import AliyunEmailForm from './aliyunEmailForm.vue'
|
||||
import TencentEmailForm from './tencentEmailForm.vue'
|
||||
const activeKey = ref('localEmail')
|
||||
</script>
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
</template>
|
||||
|
||||
<script setup name="fileConfig">
|
||||
import localFileForm from './localFileForm.vue'
|
||||
import aliyunFileForm from './aliyunFileForm.vue'
|
||||
import tencentFileForm from './tencentFileForm.vue'
|
||||
import minioFileForm from './minioFileForm.vue'
|
||||
import LocalFileForm from './localFileForm.vue'
|
||||
import AliyunFileForm from './aliyunFileForm.vue'
|
||||
import TencentFileForm from './tencentFileForm.vue'
|
||||
import MinioFileForm from './minioFileForm.vue'
|
||||
const activeKey = ref('localFile')
|
||||
</script>
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
import { required } from '@/utils/formRules'
|
||||
import configApi from '@/api/dev/configApi'
|
||||
// 默认是关闭状态
|
||||
let visible = $ref(false)
|
||||
const visible = ref(false)
|
||||
const emit = defineEmits({ successful: null })
|
||||
const formRef = ref()
|
||||
// 表单数据
|
||||
|
@ -44,7 +44,7 @@
|
|||
|
||||
// 打开抽屉
|
||||
const onOpen = (record) => {
|
||||
visible = true
|
||||
visible.value = true
|
||||
formData.value = {
|
||||
sortCode: 99
|
||||
}
|
||||
|
@ -55,7 +55,7 @@
|
|||
// 关闭抽屉
|
||||
const onClose = () => {
|
||||
formRef.value.resetFields()
|
||||
visible = false
|
||||
visible.value = false
|
||||
}
|
||||
// 默认要校验的
|
||||
const formRules = {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<s-table
|
||||
ref="table"
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:alert="false"
|
||||
|
@ -10,7 +10,7 @@
|
|||
>
|
||||
<template #operator class="table-operator">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="form.onOpen()">
|
||||
<a-button type="primary" @click="formRef.onOpen()">
|
||||
<template #icon>
|
||||
<plus-outlined />
|
||||
</template>
|
||||
|
@ -21,14 +21,14 @@
|
|||
placeholder="请输入关键字"
|
||||
enter-button
|
||||
allowClear
|
||||
@search="table.refresh(true)"
|
||||
@search="tableRef.refresh(true)"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'action'">
|
||||
<a-space>
|
||||
<a @click="form.onOpen(record)">编辑</a>
|
||||
<a @click="formRef.onOpen(record)">编辑</a>
|
||||
<a-divider type="vertical" />
|
||||
<a-popconfirm title="确定要删除此配置吗?" @confirm="deleteConfig(record)">
|
||||
<a-button type="link" danger size="small">删除</a-button>
|
||||
|
@ -37,16 +37,15 @@
|
|||
</template>
|
||||
</template>
|
||||
</s-table>
|
||||
<Form ref="form" @successful="table.refresh(true)" />
|
||||
<Form ref="formRef" @successful="tableRef.refresh(true)" />
|
||||
</template>
|
||||
|
||||
<script setup name="sysModule">
|
||||
import Form from './form.vue'
|
||||
import configApi from '@/api/dev/configApi'
|
||||
let searchFormState = reactive({})
|
||||
const searchFormState = ref({})
|
||||
const formRef = ref()
|
||||
const table = ref()
|
||||
let form = ref()
|
||||
const tableRef = ref()
|
||||
const toolConfig = { refresh: true, height: true, columnSetting: false, striped: false }
|
||||
const columns = [
|
||||
{
|
||||
|
@ -77,7 +76,7 @@
|
|||
}
|
||||
]
|
||||
const loadData = (parameter) => {
|
||||
return configApi.configPage(Object.assign(parameter, searchFormState)).then((res) => {
|
||||
return configApi.configPage(Object.assign(parameter, searchFormState.value)).then((res) => {
|
||||
return res
|
||||
})
|
||||
}
|
||||
|
@ -89,7 +88,7 @@
|
|||
}
|
||||
]
|
||||
configApi.configDelete(params).then(() => {
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
</template>
|
||||
|
||||
<script setup name="smsConfig">
|
||||
import aliyunSmsForm from './aliyunSmsForm.vue'
|
||||
import tencentSmsForm from './tencentSmsForm.vue'
|
||||
import AliyunSmsForm from './aliyunSmsForm.vue'
|
||||
import TencentSmsForm from './tencentSmsForm.vue'
|
||||
const activeKey = ref('aliyunSms')
|
||||
</script>
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
import { message } from 'ant-design-vue'
|
||||
import configApi from '@/api/dev/configApi'
|
||||
import tool from '@/utils/tool'
|
||||
import menuTreeSelect from '@/components/TreeSelect/menuTreeSelect.vue'
|
||||
import MenuTreeSelect from '@/components/TreeSelect/menuTreeSelect.vue'
|
||||
|
||||
// 定义emit事件
|
||||
const emit = defineEmits({ successful: null })
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
</template>
|
||||
|
||||
<script setup name="thirdConfig">
|
||||
import wechatThirdForm from './wechatThirdForm.vue'
|
||||
import giteeThirdForm from './giteeThirdForm.vue'
|
||||
import WechatThirdForm from './wechatThirdForm.vue'
|
||||
import GiteeThirdForm from './giteeThirdForm.vue'
|
||||
const activeKey = ref('wechatThird')
|
||||
</script>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-button type="primary" @click="$refs.table.refresh(true)">
|
||||
<a-button type="primary" @click="tableRef.refresh(true)">
|
||||
<template #icon><SearchOutlined /></template>
|
||||
查询
|
||||
</a-button>
|
||||
|
@ -33,7 +33,7 @@
|
|||
</a-form>
|
||||
<a-divider class="m-3 mx-0" />
|
||||
<s-table
|
||||
ref="table"
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:expand-row-by-click="true"
|
||||
|
@ -42,7 +42,7 @@
|
|||
:row-key="(record) => record.id"
|
||||
>
|
||||
<template #operator class="table-operator">
|
||||
<a-button type="primary" @click="form.onOpen(undefined, 'BIZ', searchFormState.parentId)">
|
||||
<a-button type="primary" @click="formRef.onOpen(undefined, 'BIZ', searchFormState.parentId)">
|
||||
<template #icon><plus-outlined /></template>
|
||||
新增
|
||||
</a-button>
|
||||
|
@ -53,7 +53,7 @@
|
|||
<a-tag color="green" v-else>子级</a-tag>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<a @click="form.onOpen(record, 'BIZ')">编辑</a>
|
||||
<a @click="formRef.onOpen(record, 'BIZ')">编辑</a>
|
||||
<a-divider type="vertical" />
|
||||
<a-popconfirm title="删除此字典与下级字典吗?" @confirm="remove(record)">
|
||||
<a-button type="link" danger size="small">删除</a-button>
|
||||
|
@ -63,14 +63,14 @@
|
|||
</s-table>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<Form ref="form" @successful="formSuccessful()" />
|
||||
<Form ref="formRef" @successful="formSuccessful()" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Empty } from 'ant-design-vue'
|
||||
import dictApi from '@/api/dev/dictApi'
|
||||
import Form from './form.vue'
|
||||
const { proxy } = getCurrentInstance()
|
||||
import tool from '@/utils/tool'
|
||||
const columns = [
|
||||
{
|
||||
title: '字典名称',
|
||||
|
@ -94,10 +94,10 @@
|
|||
}
|
||||
]
|
||||
// 定义tableDOM
|
||||
const table = ref(null)
|
||||
const form = ref()
|
||||
const tableRef = ref(null)
|
||||
const formRef = ref()
|
||||
const searchFormRef = ref()
|
||||
let searchFormState = reactive({})
|
||||
const searchFormState = ref({})
|
||||
// 默认展开的节点
|
||||
let defaultExpandedKeys = ref([])
|
||||
const treeData = ref([])
|
||||
|
@ -109,9 +109,9 @@
|
|||
const loadData = (parameter) => {
|
||||
loadTreeData()
|
||||
parameter.category = 'BIZ'
|
||||
return dictApi.dictPage(Object.assign(parameter, searchFormState)).then((data) => {
|
||||
return dictApi.dictPage(Object.assign(parameter, searchFormState.value)).then((data) => {
|
||||
if (data.records) {
|
||||
if (searchFormState.parentId) {
|
||||
if (searchFormState.value.parentId) {
|
||||
let dataArray = []
|
||||
data.records.forEach((item) => {
|
||||
const obj = data.records.find((f) => f.id === item.parentId)
|
||||
|
@ -135,7 +135,7 @@
|
|||
// 重置
|
||||
const reset = () => {
|
||||
searchFormRef.value.resetFields()
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
}
|
||||
// 加载左侧的树
|
||||
const loadTreeData = () => {
|
||||
|
@ -151,7 +151,7 @@
|
|||
// 点击树查询
|
||||
const treeSelect = (selectedKeys) => {
|
||||
if (selectedKeys && selectedKeys.length > 0) {
|
||||
searchFormState.parentId = selectedKeys.toString()
|
||||
searchFormState.value.parentId = selectedKeys.toString()
|
||||
if (!columns.find((f) => f.title === '层级')) {
|
||||
columns.splice(2, 0, {
|
||||
title: '层级',
|
||||
|
@ -160,10 +160,10 @@
|
|||
})
|
||||
}
|
||||
} else {
|
||||
delete searchFormState.parentId
|
||||
delete searchFormState.value.parentId
|
||||
columns.splice(2, 1)
|
||||
}
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
}
|
||||
// 删除
|
||||
const remove = (record) => {
|
||||
|
@ -173,19 +173,19 @@
|
|||
}
|
||||
]
|
||||
dictApi.dictDelete(params).then(() => {
|
||||
table.value.refresh(true)
|
||||
tableRef.value.refresh(true)
|
||||
})
|
||||
refreshStoreDict()
|
||||
}
|
||||
// 表单界面回调
|
||||
const formSuccessful = () => {
|
||||
table.value.refresh()
|
||||
tableRef.value.refresh()
|
||||
refreshStoreDict()
|
||||
}
|
||||
// 刷新store中的字典
|
||||
const refreshStoreDict = () => {
|
||||
dictApi.dictTree().then((res) => {
|
||||
proxy.$TOOL.data.set('DICT_TYPE_TREE_DATA', res)
|
||||
tool.data.set('DICT_TYPE_TREE_DATA', res)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue