Merge pull request #3 from adtkcn/dev

Dev
This commit is contained in:
x
2024-10-25 18:37:44 +08:00
committed by GitHub
298 changed files with 16203 additions and 8499 deletions

View File

@@ -53,7 +53,7 @@ stages:
- mkdir -p /www/wwwroot/likeadmin
- tar zxvf ~/gitee_go/deploy/x_admin.tar.gz -C /www/wwwroot/likeadmin
- '# sh /home/admin/app/deploy.sh restart'
- pm2 reload 4
- pm2 reload x_admin
- echo 'Go部署完成'
notify: []
strategy:

View File

@@ -1,4 +1,2 @@
NODE_ENV = 'development'
# 请求域名
VITE_APP_BASE_URL='http://127.0.0.1:8001'

View File

@@ -1,4 +1,2 @@
NODE_ENV = 'production'
# 请求域名
VITE_APP_BASE_URL=''
VITE_APP_BASE_URL=''

View File

@@ -3,13 +3,14 @@ require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
ignorePatterns: ['/auto-imports.d.ts', '/components.d.ts'],
// ignorePatterns 忽略特定的文件和目录
ignorePatterns: ['/auto-imports.d.ts', '/components.d.ts', 'scripts'],
extends: [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript/recommended',
'@vue/eslint-config-prettier',
'./.eslintrc-auto-import.json'
'@vue/eslint-config-prettier'
// './.eslintrc-auto-import.json'
],
rules: {
'prettier/prettier': [
@@ -26,12 +27,18 @@ module.exports = {
trailingComma: 'none'
}
],
// 'vue/no-undef-components': [
// 'error',
// {
// ignorePatterns: ['el(\\-\\w+)+']
// }
// ],
'vue/multi-word-component-names': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'no-undef': 'off',
'vue/prefer-import-from-vue': 'off',
'no-prototype-builtins': 'off',
// 'no-undef': 'off',
// 'vue/prefer-import-from-vue': 'off',
// 'no-prototype-builtins': 'off',
'prefer-spread': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',

View File

@@ -10,10 +10,14 @@
"scss.validate": false,
"cSpell.words": [
"brotli",
"btns",
"daterange",
"datetimerange",
"dbclick",
"echarts",
"execa",
"highlightjs",
"iconfont",
"logicflow",
"nprogress",
"pinia",

View File

@@ -10,33 +10,33 @@
"build": "node ./scripts/build.mjs",
"type-check": "vue-tsc --noEmit --checkJs true --skipLibCheck",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"preinstall": "npx only-allow pnpm"
"preinstall": "npx only-allow pnpm",
"outdated": "pnpm outdated"
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@highlightjs/vue-plugin": "^2.1.0",
"@logicflow/core": "^1.2.27",
"@logicflow/extension": "^1.2.27",
"@vue/shared": "^3.4.27",
"@vueuse/core": "^10.10.0",
"@logicflow/core": "^2.0.6",
"@logicflow/extension": "^2.0.10",
"@vueuse/core": "^10.11.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"axios": "^1.7.2",
"axios": "^1.7.7",
"crypto-js": "^4.2.0",
"css-color-function": "^1.3.3",
"dayjs": "^1.11.11",
"echarts": "^5.5.0",
"element-plus": "^2.7.5",
"highlight.js": "^11.9.0",
"dayjs": "^1.11.13",
"echarts": "^5.5.1",
"element-plus": "^2.8.6",
"highlight.js": "^11.10.0",
"lodash-es": "^4.17.21",
"nprogress": "^0.2.0",
"pinia": "^2.1.7",
"query-string": "^9.0.0",
"pinia": "^2.2.1",
"query-string": "^9.1.0",
"vform3-builds": "^3.0.10",
"vue": "^3.4.27",
"vue": "^3.5.12",
"vue-clipboard3": "^2.0.0",
"vue-echarts": "^6.7.3",
"vue-router": "^4.3.3",
"vue-echarts": "^7.0.1",
"vue-router": "^4.4.5",
"vue3-video-play": "^1.3.2",
"vuedraggable": "^4.1.0"
},
@@ -45,28 +45,28 @@
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.14.2",
"@types/nprogress": "^0.2.3",
"@vitejs/plugin-vue": "^5.0.5",
"@vitejs/plugin-vue-jsx": "^4.0.0",
"@vitejs/plugin-vue": "^5.1.4",
"@vitejs/plugin-vue-jsx": "^4.0.1",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^13.0.0",
"@vue/tsconfig": "^0.5.1",
"autoprefixer": "^10.4.19",
"autoprefixer": "^10.4.20",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.26.0",
"execa": "^9.2.0",
"eslint-plugin-vue": "^9.27.0",
"execa": "^9.3.0",
"fs-extra": "^11.2.0",
"postcss": "^8.4.38",
"prettier": "^3.3.1",
"prettier": "^3.3.3",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.77.4",
"tailwindcss": "^3.4.4",
"typescript": "~5.4.5",
"unplugin-auto-import": "^0.17.6",
"unplugin-vue-components": "^0.27.0",
"vite": "^5.2.13",
"sass": "^1.77.8",
"tailwindcss": "^3.4.13",
"typescript": "~5.6.2",
"unplugin-auto-import": "^0.18.3",
"unplugin-vue-components": "^0.27.4",
"vite": "^5.4.7",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-style-import": "^2.0.0",
"vite-plugin-svg-icons": "^2.0.1",
"vue-tsc": "^2.0.21"
"vue-tsc": "^2.1.6"
}
}

View File

@@ -1,4 +1,8 @@
<script setup lang="ts">
import { onMounted, watch } from 'vue'
import { RouterView } from 'vue-router'
import { useDark, useWindowSize, useThrottleFn } from '@vueuse/core'
// import zhCn from "element-plus/lib/locale/lang/zh-cn";
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'

View File

@@ -1,26 +1,83 @@
import request from '@/utils/request'
import type { Pages } from '@/utils/request'
export type type_flow_apply = {
id?: number
templateId?: number
applyUserId?: number
applyUserNickname?: string
flowName?: string
flowGroup?: number
flowRemark?: string
flowFormData?: string
flowProcessData?: string
flowProcessDataList?: string
formValue?: string
status?: number
isDelete?: number
createTime?: string
updateTime?: string
deleteTime?: string
}
// 查询
export type type_flow_apply_query = {
templateId?: number
applyUserId?: number
applyUserNickname?: string
flowName?: string
flowGroup?: number
flowRemark?: string
flowFormData?: string
flowProcessData?: string
flowProcessDataList?: string
formValue?: string
status?: number
createTimeStart?: string
createTimeEnd?: string
updateTimeStart?: string
updateTimeEnd?: string
}
// 添加编辑
export type type_flow_apply_edit = {
id?: number
templateId?: number
applyUserId?: number
applyUserNickname?: string
flowName?: string
flowGroup?: number
flowRemark?: string
flowFormData?: string
flowProcessData?: string
flowProcessDataList?: string
formValue?: string
status?: number
}
// 申请流程列表
export function flow_apply_lists(params?: Record<string, any>) {
return request.get({ url: '/flow/flow_apply/list', params })
export function flow_apply_lists(params?: type_flow_apply_query) {
return request.get<Pages<type_flow_apply>>({ url: '/flow/flow_apply/list', params })
}
// 申请流程列表-所有
export function flow_apply_list_all(params?: type_flow_apply_query) {
return request.get<type_flow_apply[]>({ url: '/flow/flow_apply/listAll', params })
}
// 申请流程详情
export function flow_apply_detail(params: Record<string, any>) {
return request.get({ url: '/flow/flow_apply/detail', params })
return request.get<type_flow_apply>({ url: '/flow/flow_apply/detail', params: params })
}
// 申请流程新增
export function flow_apply_add(data: Record<string, any>) {
return request.post({ url: '/flow/flow_apply/add', data })
export function flow_apply_add(data: type_flow_apply_edit) {
return request.post<null>({ url: '/flow/flow_apply/add', data })
}
// 申请流程编辑
export function flow_apply_edit(data: Record<string, any>) {
return request.post({ url: '/flow/flow_apply/edit', data })
export function flow_apply_edit(data: type_flow_apply_edit) {
return request.post<null>({ url: '/flow/flow_apply/edit', data })
}
// 申请流程删除
export function flow_apply_delete(data: Record<string, any>) {
return request.post({ url: '/flow/flow_apply/del', data })
export function flow_apply_delete(id: number | string) {
return request.post<null>({ url: '/flow/flow_apply/del', data: { id } })
}

View File

@@ -1,32 +1,87 @@
import request from '@/utils/request/index'
import type { Pages } from '@/utils/request'
export type type_flow_history = {
id?: number
applyId?: number
templateId?: number
applyUserId?: number
applyUserNickname?: string
approverId?: number
approverNickname?: string
nodeId?: string
nodeType?: string
nodeLabel?: string
formValue?: string
passStatus?: number
passRemark?: string
createTime?: string
updateTime?: string
deleteTime?: string
}
// 查询
export type type_flow_history_query = {
applyId?: number
templateId?: number
applyUserId?: number
applyUserNickname?: string
approverId?: number
approverNickname?: string
nodeId?: string
nodeType?: string
nodeLabel?: string
formValue?: string
passStatus?: number
passRemark?: string
createTimeStart?: string
createTimeEnd?: string
updateTimeStart?: string
updateTimeEnd?: string
}
// 添加编辑
export type type_flow_history_edit = {
id?: number
applyId?: number
templateId?: number
applyUserId?: number
applyUserNickname?: string
approverId?: number
approverNickname?: string
nodeId?: string
nodeType?: string
nodeLabel?: string
formValue?: string
passStatus?: number
passRemark?: string
}
// 流程历史列表
export function flow_history_list(params?: Record<string, any>) {
return request.get({ url: '/flow/flow_history/list', params })
export function flow_history_list(params?: type_flow_history_query) {
return request.get<Pages<type_flow_history>>({ url: '/flow/flow_history/list', params })
}
// 流程历史列表-所有
export function flow_history_list_all(params?: Record<string, any>) {
return request.get({ url: '/flow/flow_history/listAll', params })
export function flow_history_list_all(params?: type_flow_history_query) {
return request.get<type_flow_history[]>({ url: '/flow/flow_history/listAll', params })
}
// 流程历史详情
export function flow_history_detail(params: Record<string, any>) {
return request.get({ url: '/flow/flow_history/detail', params })
export function flow_history_detail(id: number | string) {
return request.get<type_flow_history>({ url: '/flow/flow_history/detail', params: { id } })
}
// 流程历史新增
export function flow_history_add(data: Record<string, any>) {
return request.post({ url: '/flow/flow_history/add', data })
export function flow_history_add(data: type_flow_history_edit) {
return request.post<null>({ url: '/flow/flow_history/add', data })
}
// 流程历史编辑
export function flow_history_edit(data: Record<string, any>) {
return request.post({ url: '/flow/flow_history/edit', data })
export function flow_history_edit(data: type_flow_history_edit) {
return request.post<null>({ url: '/flow/flow_history/edit', data })
}
// 流程历史删除
export function flow_history_delete(data: Record<string, any>) {
return request.post({ url: '/flow/flow_history/del', data })
export function flow_history_delete(id: number | string) {
return request.post<null>({ url: '/flow/flow_history/del', data: { id } })
}
// 获取下一个审批节点,中间可能有系统任务和结束节点被跳过

View File

@@ -1,31 +1,68 @@
import request from '@/utils/request'
import type { Pages } from '@/utils/request'
// 流程模板列表
export function flow_template_lists(params?: Record<string, any>) {
return request.get({ url: '/flow/flow_template/list', params })
export type type_flow_template = {
id?: number
flowName?: string
flowGroup?: number
flowRemark?: string
flowFormData?: string
flowProcessData?: string
flowProcessDataList?: string
isDelete?: number
createTime?: string
updateTime?: string
deleteTime?: string
}
// 查询
export type type_flow_template_query = {
flowName?: string
flowGroup?: number
flowRemark?: string
flowFormData?: string
flowProcessData?: string
flowProcessDataList?: string
createTimeStart?: string
createTimeEnd?: string
updateTimeStart?: string
updateTimeEnd?: string
}
// 添加编辑
export type type_flow_template_edit = {
id?: number
flowName?: string
flowGroup?: number
flowRemark?: string
flowFormData?: string
flowProcessData?: string
flowProcessDataList?: string
}
// 流程模板列表
export function flow_template_lists(params?: type_flow_template_query) {
return request.get<Pages<type_flow_template>>({ url: '/flow/flow_template/list', params })
}
// 流程模板列表-所有
export function flow_template_lists_all(params?: Record<string, any>) {
return request.get({ url: '/flow/flow_template/listAll', params })
export function flow_template_lists_all(params?: type_flow_template_query) {
return request.get<type_flow_template[]>({ url: '/flow/flow_template/listAll', params })
}
// 流程模板详情
export function flow_template_detail(params: Record<string, any>) {
return request.get({ url: '/flow/flow_template/detail', params })
export function flow_template_detail(id: number | string) {
return request.get<type_flow_template>({ url: '/flow/flow_template/detail', params: { id } })
}
// 流程模板新增
export function flow_template_add(data: Record<string, any>) {
return request.post({ url: '/flow/flow_template/add', data })
export function flow_template_add(data: type_flow_template_edit) {
return request.post<null>({ url: '/flow/flow_template/add', data })
}
// 流程模板编辑
export function flow_template_edit(data: Record<string, any>) {
return request.post({ url: '/flow/flow_template/edit', data })
export function flow_template_edit(data: type_flow_template_edit) {
return request.post<null>({ url: '/flow/flow_template/edit', data })
}
// 流程模板删除
export function flow_template_delete(data: Record<string, any>) {
return request.post({ url: '/flow/flow_template/del', data })
export function flow_template_delete(id: number | string) {
return request.post<null>({ url: '/flow/flow_template/del', data: { id } })
}

View File

@@ -0,0 +1,103 @@
import request from '@/utils/request'
import type { Pages } from '@/utils/request'
import config from '@/config'
import queryString from 'query-string'
import { getToken } from '@/utils/auth'
import { clearEmpty } from '@/utils/util'
export type type_monitor_client = {
Id?: number
ProjectKey?: string
ClientId?: string
UserId?: string
Os?: string
Browser?: string
City?: string
Width?: number
Height?: number
Ua?: string
CreateTime?: string
}
// 查询
export type type_monitor_client_query = {
ProjectKey?: string
ClientId?: string
UserId?: string
Os?: string
Browser?: string
City?: string
Width?: number
Height?: number
Ua?: string
CreateTimeStart?: string
CreateTimeEnd?: string
ClientTimeStart?: string
ClientTimeEnd?: string
}
// 添加编辑
export type type_monitor_client_edit = {
Id?: number
ProjectKey?: string
ClientId?: string
UserId?: string
Os?: string
Browser?: string
City?: string
Width?: number
Height?: number
Ua?: string
}
// 监控-客户端信息列表
export function monitor_client_list(params?: type_monitor_client_query) {
return request.get<Pages<type_monitor_client>>({
url: '/monitor_client/list',
params: clearEmpty(params)
})
}
// 监控-客户端信息列表-所有
export function monitor_client_list_all(params?: type_monitor_client_query) {
return request.get<type_monitor_client[]>({
url: '/monitor_client/listAll',
params: clearEmpty(params)
})
}
// 监控-客户端信息详情
export function monitor_client_detail(Id: number | string) {
return request.get<type_monitor_client>({ url: '/monitor_client/detail', params: { Id } })
}
export function monitor_client_errorUsers(Id: number | string) {
return request.get<type_monitor_client[]>({ url: '/monitor_client/errorUsers', params: { Id } })
}
// 监控-客户端信息新增
export function monitor_client_add(data: type_monitor_client_edit) {
return request.post<null>({ url: '/monitor_client/add', data })
}
// 监控-客户端信息编辑
export function monitor_client_edit(data: type_monitor_client_edit) {
return request.post<null>({ url: '/monitor_client/edit', data })
}
// 监控-客户端信息删除
export function monitor_client_delete(Id: number | string) {
return request.post<null>({ url: '/monitor_client/del', data: { Id } })
}
// 监控-客户端信息删除-批量
export function monitor_client_delete_batch(data: { Ids: string }) {
return request.post<null>({ url: '/monitor_client/delBatch', data })
}
// 监控-客户端信息导入
export const monitor_client_import_file = '/monitor_client/ImportFile'
// 监控-客户端信息导出
export function monitor_client_export_file(params: any) {
return (window.location.href =
`${config.baseUrl}${config.urlPrefix}/monitor_client/ExportFile?token=${getToken()}&` +
queryString.stringify(clearEmpty(params)))
}

View File

@@ -0,0 +1,83 @@
import request from '@/utils/request'
import type { Pages } from '@/utils/request'
import config from '@/config'
import queryString from 'query-string'
import { getToken } from '@/utils/auth'
import { clearEmpty } from '@/utils/util'
export type type_monitor_error = {
Id?: number
ProjectKey?: string
EventType?: string
Path?: string
Message?: string
Stack?: string
Md5?: string
CreateTime?: string
}
// 查询
export type type_monitor_error_query = {
ProjectKey?: string
EventType?: string
Path?: string
Message?: string
Stack?: string
Md5?: string
CreateTimeStart?: string
CreateTimeEnd?: string
}
// 添加编辑
export type type_monitor_error_edit = {
Id?: number
ProjectKey?: string
EventType?: string
Path?: string
Message?: string
Stack?: string
Md5?: string
}
// 监控-错误列列表
export function monitor_error_list(params?: type_monitor_error_query) {
return request.get<Pages<type_monitor_error>>({
url: '/monitor_error/list',
params: clearEmpty(params)
})
}
// 监控-错误列列表-所有
export function monitor_error_list_all(params?: type_monitor_error_query) {
return request.get<type_monitor_error[]>({
url: '/monitor_error/listAll',
params: clearEmpty(params)
})
}
// 监控-错误列详情
export function monitor_error_detail(Id: number | string) {
return request.get<type_monitor_error>({ url: '/monitor_error/detail', params: { Id } })
}
// 监控-错误列新增
export function monitor_error_add(data: type_monitor_error_edit) {
return request.post<null>({ url: '/monitor_error/add', data })
}
// 监控-错误列删除
export function monitor_error_delete(Id: number | string) {
return request.post<null>({ url: '/monitor_error/del', data: { Id } })
}
// 监控-错误列删除-批量
export function monitor_error_delete_batch(data: { Ids: string }) {
return request.post<null>({ url: '/monitor_error/delBatch', data })
}
// 监控-错误列导入
export const monitor_error_import_file = '/monitor_error/ImportFile'
// 监控-错误列导出
export function monitor_error_export_file(params: any) {
return (window.location.href =
`${config.baseUrl}${config.urlPrefix}/monitor_error/ExportFile?token=${getToken()}&` +
queryString.stringify(clearEmpty(params)))
}

View File

@@ -0,0 +1,87 @@
import request from '@/utils/request'
import type { Pages } from '@/utils/request'
import config from '@/config'
import queryString from 'query-string'
import { getToken } from '@/utils/auth'
import { clearEmpty } from '@/utils/util'
export type type_monitor_project = {
Id?: number
ProjectKey?: string
ProjectName?: string
ProjectType?: string
Status?: number
IsDelete?: number
CreateTime?: string
UpdateTime?: string
DeleteTime?: string
}
// 查询
export type type_monitor_project_query = {
ProjectKey?: string
ProjectName?: string
ProjectType?: string
Status?: number
CreateTimeStart?: string
CreateTimeEnd?: string
UpdateTimeStart?: string
UpdateTimeEnd?: string
}
// 添加编辑
export type type_monitor_project_edit = {
Id?: number
ProjectKey?: string
ProjectName?: string
ProjectType?: string
Status?: number
}
// 监控项目列表
export function monitor_project_list(params?: type_monitor_project_query) {
return request.get<Pages<type_monitor_project>>({
url: '/monitor_project/list',
params: clearEmpty(params)
})
}
// 监控项目列表-所有
export function monitor_project_list_all(params?: type_monitor_project_query) {
return request.get<type_monitor_project[]>({
url: '/monitor_project/listAll',
params: clearEmpty(params)
})
}
// 监控项目详情
export function monitor_project_detail(Id: number | string) {
return request.get<type_monitor_project>({ url: '/monitor_project/detail', params: { Id } })
}
// 监控项目新增
export function monitor_project_add(data: type_monitor_project_edit) {
return request.post<null>({ url: '/monitor_project/add', data })
}
// 监控项目编辑
export function monitor_project_edit(data: type_monitor_project_edit) {
return request.post<null>({ url: '/monitor_project/edit', data })
}
// 监控项目删除
export function monitor_project_delete(Id: number | string) {
return request.post<null>({ url: '/monitor_project/del', data: { Id } })
}
// 监控项目删除-批量
export function monitor_project_delete_batch(data: { Ids: string }) {
return request.post<null>({ url: '/monitor_project/delBatch', data })
}
// 监控项目导入
export const monitor_project_import_file = '/monitor_project/ImportFile'
// 监控项目导出
export function monitor_project_export_file(params: any) {
return (window.location.href =
`${config.baseUrl}${config.urlPrefix}/monitor_project/ExportFile?token=${getToken()}&` +
queryString.stringify(clearEmpty(params)))
}

View File

@@ -1,86 +0,0 @@
import request from '@/utils/request'
import type { Pages } from '@/utils/request'
import config from '@/config'
import queryString from 'query-string'
import { getToken } from '@/utils/auth'
export type type_monitor_client = {
id?: number;
projectKey?: string;
clientId?: string;
userId?: string;
os?: string;
browser?: string;
city?: string;
width?: number;
height?: number;
ua?: string;
createTime?: string;
clientTime?: string;
}
// 查询
export type type_monitor_client_query = {
projectKey?: string;
clientId?: string;
userId?: string;
os?: string;
browser?: string;
city?: string;
width?: number;
height?: number;
ua?: string;
createTimeStart?: string;
createTimeEnd?: string;
clientTimeStart?: string;
clientTimeEnd?: string;
}
// 添加编辑
export type type_monitor_client_edit = {
clientId?: string;
userId?: string;
os?: string;
browser?: string;
city?: string;
width?: number;
height?: number;
ua?: string;
clientTime?: string;
}
// 监控-客户端信息列表
export function monitor_client_list(params?: type_monitor_client_query) {
return request.get<Pages<type_monitor_client>>({ url: '/monitor_client/list', params })
}
// 监控-客户端信息列表-所有
export function monitor_client_list_all(params?: type_monitor_client_query) {
return request.get<Pages<type_monitor_client>>({ url: '/monitor_client/listAll', params })
}
// 监控-客户端信息详情
export function monitor_client_detail(id: number | string) {
return request.get<type_monitor_client>({ url: '/monitor_client/detail', params: { id } })
}
// 监控-客户端信息新增
export function monitor_client_add(data: type_monitor_client_edit) {
return request.post<null>({ url: '/monitor_client/add', data })
}
// 监控-客户端信息编辑
export function monitor_client_edit(data: type_monitor_client_edit) {
return request.post<null>({ url: '/monitor_client/edit', data })
}
// 监控-客户端信息删除
export function monitor_client_delete(id: number | string) {
return request.post<null>({ url: '/monitor_client/del', data: { id } })
}
// 监控-客户端信息导入
export const monitor_client_import_file = '/monitor_client/ImportFile'
// 监控-客户端信息导出
export function monitor_client_export_file(params: any) {
return (window.location.href =`${config.baseUrl}${config.urlPrefix}/monitor_client/ExportFile?token=${getToken()}&` + queryString.stringify(params))
}

View File

@@ -1,30 +0,0 @@
import request from '@/utils/request'
// 错误项目列表
export function monitor_project_list(params?: Record<string, any>) {
return request.get({ url: '/monitor_project/list', params })
}
// 错误项目列表-所有
export function monitor_project_list_all(params?: Record<string, any>) {
return request.get({ url: '/monitor_project/listAll', params })
}
// 错误项目详情
export function monitor_project_detail(params: Record<string, any>) {
return request.get({ url: '/monitor_project/detail', params })
}
// 错误项目新增
export function monitor_project_add(data: Record<string, any>) {
return request.post({ url: '/monitor_project/add', data })
}
// 错误项目编辑
export function monitor_project_edit(data: Record<string, any>) {
return request.post({ url: '/monitor_project/edit', data })
}
// 错误项目删除
export function monitor_project_delete(data: Record<string, any>) {
return request.post({ url: '/monitor_project/del', data })
}

View File

@@ -1,43 +0,0 @@
import request from '@/utils/request'
import config from '@/config'
import queryString from 'query-string'
import { getToken } from '@/utils/auth'
// 错误收集error列表
export function monitor_web_list(params?: Record<string, any>) {
return request.get({ url: '/monitor_web/list', params })
}
// 错误收集error列表-所有
export function monitor_web_list_all(params?: Record<string, any>) {
return request.get({ url: '/monitor_web/listAll', params })
}
// 错误收集error详情
export function monitor_web_detail(params: Record<string, any>) {
return request.get({ url: '/monitor_web/detail', params })
}
// 错误收集error新增
export function monitor_web_add(data: Record<string, any>) {
return request.post({ url: '/monitor_web/add', data })
}
// 错误收集error编辑
export function monitor_web_edit(data: Record<string, any>) {
return request.post({ url: '/monitor_web/edit', data })
}
// 错误收集error删除
export function monitor_web_delete(data: Record<string, any>) {
return request.post({ url: '/monitor_web/del', data })
}
// 错误收集error导入
export const monitor_web_import_file = '/monitor_web/ImportFile'
// 错误收集error导出
export function monitor_web_export_file(params: any) {
return (window.location.href =
`${config.baseUrl}${config.urlPrefix}/monitor_web/ExportFile?token=${getToken()}&` +
queryString.stringify(params))
}

View File

@@ -6,6 +6,10 @@ import config from '@/config'
export function adminLists(params: any) {
return request.get({ url: '/system/admin/list', params })
}
// 管理员列表
export function adminListAll(params: any) {
return request.get({ url: '/system/admin/listAll', params })
}
// 管理员详情
export function adminDetail(params: any) {
return request.get({ url: '/system/admin/detail', params })

View File

@@ -0,0 +1,84 @@
import request from '@/utils/request'
import type { Pages } from '@/utils/request'
import config from '@/config'
import queryString from 'query-string'
import { getToken } from '@/utils/auth'
import { clearEmpty } from '@/utils/util'
export type type_user_protocol = {
Id?: number
Title?: string
Content?: string
Sort?: number
IsDelete?: number
CreateTime?: string
UpdateTime?: string
DeleteTime?: string
}
// 查询
export type type_user_protocol_query = {
Title?: string
Content?: string
Sort?: number
CreateTimeStart?: string
CreateTimeEnd?: string
UpdateTimeStart?: string
UpdateTimeEnd?: string
}
// 添加编辑
export type type_user_protocol_edit = {
Id?: number
Title?: string
Content?: string
Sort?: number
}
// 用户协议列表
export function user_protocol_list(params?: type_user_protocol_query) {
return request.get<Pages<type_user_protocol>>({
url: '/user_protocol/list',
params: clearEmpty(params)
})
}
// 用户协议列表-所有
export function user_protocol_list_all(params?: type_user_protocol_query) {
return request.get<type_user_protocol[]>({
url: '/user_protocol/listAll',
params: clearEmpty(params)
})
}
// 用户协议详情
export function user_protocol_detail(Id: number | string) {
return request.get<type_user_protocol>({ url: '/user_protocol/detail', params: { Id } })
}
// 用户协议新增
export function user_protocol_add(data: type_user_protocol_edit) {
return request.post<null>({ url: '/user_protocol/add', data })
}
// 用户协议编辑
export function user_protocol_edit(data: type_user_protocol_edit) {
return request.post<null>({ url: '/user_protocol/edit', data })
}
// 用户协议删除
export function user_protocol_delete(Id: number | string) {
return request.post<null>({ url: '/user_protocol/del', data: { Id } })
}
// 用户协议删除-批量
export function user_protocol_delete_batch(data: { Ids: string }) {
return request.post<null>({ url: '/user_protocol/delBatch', data })
}
// 用户协议导入
export const user_protocol_import_file = '/user_protocol/ImportFile'
// 用户协议导出
export function user_protocol_export_file(params: any) {
return (window.location.href =
`${config.baseUrl}${config.urlPrefix}/user_protocol/ExportFile?token=${getToken()}&` +
queryString.stringify(clearEmpty(params)))
}

View File

@@ -5,6 +5,7 @@
</template>
<script lang="ts" setup>
import { computed } from 'vue'
/**
* @description 兼容第三方页面的跳转
*/

View File

@@ -21,14 +21,7 @@ const color = defineModel({
return props.defaultColor
}
})
// const color = computed({
// get() {
// return props.modelValue
// },
// set(value) {
// emit('update:modelValue', value)
// }
// })
const predefineColors = ['#409EFF', '#28C76F', '#EA5455', '#FF9F43', '#01CFE8', '#4A5DFF']
const reset = () => {
color.value = props.defaultColor

View File

@@ -13,6 +13,7 @@
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue'
/* Props S */
const props = defineProps({
startTime: {
@@ -44,20 +45,4 @@ watch([() => props.startTime, () => props.endTime], () => {
console.log('watch', props)
content.value = [props.startTime, props.endTime]
})
// const content = computed<any>({
// get: () => {
// return [props.startTime, props.endTime]
// },
// set: (value: Event | any) => {
// console.log('change', value)
// if (value === null) {
// emit('update:startTime', '')
// emit('update:endTime', '')
// } else {
// emit('update:startTime', value[0])
// emit('update:endTime', value[1])
// }
// }
// })
</script>

View File

@@ -8,6 +8,7 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
props: {
showClose: {

View File

@@ -1,18 +1,29 @@
<template>
<div>
<template v-for="(item, index) in getOptions" :key="index">
<span :style="{ color: item.color }">{{ index != 0 ? '、' : '' }}{{ item.name }}</span>
<span :style="{ color: item.color }"
>{{ index != 0 ? '、' : '' }}{{ item[props.labelKey] }}</span
>
</template>
</div>
</template>
<script lang="ts" setup>
import { computed, withDefaults } from 'vue'
defineOptions({
name: 'dict-value'
})
const props = withDefaults(
defineProps<{
options: any[]
value: any
labelKey?: string
valueKey?: string
}>(),
{
options: () => []
options: () => [],
value: null,
labelKey: 'name',
valueKey: 'value'
}
)
@@ -25,6 +36,6 @@ const values = computed(() => {
})
const getOptions = computed(() => {
return props.options.filter((item) => values.value.includes(item.value))
return props.options.filter((item) => values.value.includes(item[props.valueKey]))
})
</script>

View File

@@ -7,7 +7,7 @@
:mode="mode"
/>
<w-editor
class="overflow-y-auto flex-1"
class="overflow-y-auto flex-1 border-solid border rounded-s"
v-model="valueHtml"
:defaultConfig="editorConfig"
:mode="mode"
@@ -28,6 +28,8 @@ import { Editor as WEditor, Toolbar } from '@wangeditor/editor-for-vue'
import type { IEditorConfig, IToolbarConfig } from '@wangeditor/editor'
import MaterialPicker from '@/components/material/picker.vue'
import { addUnit } from '@/utils/util'
import { withDefaults, computed, shallowRef, ref, onBeforeUnmount } from 'vue'
import type { CSSProperties } from 'vue'
const props = withDefaults(

View File

@@ -12,7 +12,7 @@
style="height: 100vh"
class="flow-config-dialog"
>
<template #header="{ close }">
<template #header>
<header class="page__header">
<div class="page-actions">
{{ title }}
@@ -30,7 +30,7 @@
</div>
</div>
<el-button class="publish-btn" @click="close">关闭</el-button>
<el-button class="publish-btn" @click="exit">关闭</el-button>
<el-button class="publish-btn" type="primary" @click="publish">发布</el-button>
</header>
</template>
@@ -48,168 +48,151 @@
v-show="activeStep === 'formDesign'"
tabName="formDesign"
/>
<Diagram
ref="processDesign"
v-show="activeStep === 'processDesign'"
tabName="processDesign"
<FlowEdit
ref="flowEdit"
v-show="activeStep === 'flowEdit'"
tabName="flowEdit"
:fieldList="fieldList"
:conf="mockData.flowProcessData"
></Diagram>
></FlowEdit>
</div>
</el-dialog>
</template>
<script>
import { defineComponent } from 'vue'
<script setup lang="ts">
import { ref, shallowRef, watch } from 'vue'
import XForm from './XForm/index.vue'
import Diagram from './flowEdit/Diagram.vue'
import FlowEdit from './flowEdit/index.vue'
import BasicSetting from './BasicSetting/index.vue'
import feedback from '@/utils/feedback'
const beforeUnload = function (e) {
const confirmationMessage = '离开网站可能会丢失您编辑得内容'
;(e || window.event).returnValue = confirmationMessage // Gecko and Trident
return confirmationMessage // Gecko and WebKit
e.preventDefault()
e.returnValue = '离开网站可能会丢失您编辑得内容' // Gecko and Trident
return false // Gecko and WebKit
}
export default defineComponent({
name: 'Approver',
components: {
// Process,
Diagram,
// DynamicForm,
XForm,
BasicSetting
defineOptions({
name: 'Approver'
})
const props = defineProps({
title: {
type: String,
default: '流程配置'
},
props: {
title: {
type: String,
default: '流程配置'
},
save: {
type: Function,
default: () => {}
}
},
data() {
return {
dialogVisible: false,
save: {
type: Function,
default: () => {}
}
})
activeStep: 'basicSetting', // 激活的步骤面板
mockData: {
id: '',
basicSetting: {},
flowFormData: {},
flowProcessData: {}
},
fieldList: [],
steps: [
{ label: '基础设置', key: 'basicSetting' },
{ label: '表单设计', key: 'formDesign' },
{ label: '流程设计', key: 'processDesign' }
]
}
},
beforeRouteEnter(to, from, next) {
window.addEventListener('beforeunload', beforeUnload)
next()
},
beforeRouteLeave(to, from, next) {
window.removeEventListener('beforeunload', beforeUnload)
next()
},
mounted() {},
methods: {
reset() {
this.mockData = {
id: '',
basicSetting: {},
flowFormData: {},
flowProcessData: {}
}
this.activeStep = 'basicSetting'
this.fieldList = []
},
open(data) {
this.reset()
console.log('data', data)
if (data) {
this.mockData = { ...data }
} else {
this.mockData = {
id: '',
basicSetting: {},
flowFormData: {},
flowProcessData: {}
}
}
this.dialogVisible = true
},
async changeSteps(item) {
const fieldList = this.$refs?.formDesign?.getFieldWidgets()
this.fieldList = fieldList
this.activeStep = item.key
},
// 发布
publish() {
const getCmpData = (name) => {
return this.$refs[name]?.getData()
}
// basicSetting formDesign processDesign 返回的是Promise 因为要做校验
const p1 = getCmpData('basicSetting')
const p2 = getCmpData('formDesign')
const p3 = getCmpData('processDesign')
Promise.all([p1, p2, p3])
.then((res) => {
console.log('res', res)
const param = {
id: this?.mockData?.id,
basicSetting: res[0].formData,
flowFormData: res[1].formData,
flowProcessData: res[2].formData,
flowProcessDataList: res[2].treeToList
}
console.log(param)
this.sendToServer(param)
})
.catch((err) => {
console.error(err)
err.target && (this.activeStep = err.target)
err.message && this.$message.error(err.message)
})
},
sendToServer(param) {
this.$notify({
title: '数据已整合完成',
message: '请在控制台中查看数据输出',
position: 'bottom-right'
})
this.save(param)
.then(() => {
this.dialogVisible = false
})
.catch((err) => {
err.message && this.$message.error(err.message)
})
console.log('配置数据', param)
},
exit() {
this.$confirm('离开此页面您得修改将会丢失, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
window.history.back()
})
.catch(() => {})
const basicSetting = shallowRef<InstanceType<typeof BasicSetting>>()
const formDesign = shallowRef<InstanceType<typeof XForm>>()
const flowEdit = shallowRef<InstanceType<typeof FlowEdit>>()
const dialogVisible = ref(false)
const activeStep = ref('basicSetting')
const mockData = ref({
id: '',
basicSetting: {},
flowFormData: {},
flowProcessData: {}
})
const fieldList = ref([])
const steps = [
{ label: '基础设置', key: 'basicSetting' },
{ label: '表单设计', key: 'formDesign' },
{ label: '流程设计', key: 'flowEdit' }
]
watch(
() => dialogVisible.value,
(val) => {
if (!val) {
window.removeEventListener('beforeunload', beforeUnload)
} else {
window.addEventListener('beforeunload', beforeUnload)
}
}
)
function reset() {
mockData.value = {
id: '',
basicSetting: {},
flowFormData: {},
flowProcessData: {}
}
activeStep.value = 'basicSetting'
fieldList.value = []
}
function open(data) {
reset()
console.log('data', data)
if (data) {
mockData.value = { ...data }
} else {
mockData.value = {
id: '',
basicSetting: {},
flowFormData: {},
flowProcessData: {}
}
}
dialogVisible.value = true
}
function changeSteps(item) {
fieldList.value = formDesign.value.getFieldWidgets()
console.log('fieldList', fieldList.value)
activeStep.value = item.key
}
// 发布
function publish() {
const p1 = basicSetting.value.getData()
const p2 = formDesign.value.getData()
const p3 = flowEdit.value.getData()
Promise.all([p1, p2, p3])
.then((res) => {
console.log('res', res)
const param = {
id: mockData.value?.id,
basicSetting: res[0].formData,
flowFormData: res[1].formData,
flowProcessData: res[2].formData,
flowProcessDataList: res[2].treeToList
}
console.log(param)
sendToServer(param)
})
.catch((err) => {
console.error(err)
err.target && (activeStep.value = err.target)
err.message && feedback.msgError(err.message)
})
}
function sendToServer(param) {
feedback.notify('数据已整合完成')
props
.save(param)
.then(() => {
dialogVisible.value = false
})
.catch((err) => {
err.message && feedback.msgError(err.message)
})
console.log('配置数据', param)
}
function exit() {
feedback
.confirm('离开此页面您得修改将会丢失, 是否继续?')
.then(() => {
dialogVisible.value = false
})
.catch(() => {})
}
defineExpose({
open
})
</script>
<style>

View File

@@ -88,10 +88,13 @@ onMounted(() => {
})
const elFormRef = shallowRef<FormInstance>()
function getData() {
return new Promise((resolve, reject) => {
return new Promise<{
formData: any
target: string
}>((resolve, reject) => {
elFormRef.value.validate((valid) => {
if (!valid) {
reject({ target: this.tabName })
reject({ target: props.tabName })
return
}
// this.formData.flowImg = this.activeIcon

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ref, onMounted } from 'vue'
import 'vform3-builds/dist/designer.style.css' //引入VForm3样式
const designerRef = ref(null)
function setData(json) {
@@ -16,7 +16,9 @@ function getFieldWidgets() {
return fieldList
}
function getData() {
return new Promise((resolve, reject) => {
return new Promise<{
formData: any
}>((resolve, reject) => {
try {
const jsonData = designerRef.value.getFormJson()
console.log('jsonData', jsonData)

View File

@@ -1,332 +0,0 @@
<template>
<div class="diagram">
<diagram-toolbar
v-if="lf"
class="diagram-toolbar"
:lf="lf"
:active-edges="activeEdges"
@saveGraph="$_saveGraph"
@importData="importData"
/>
<div class="diagram-main">
<diagram-sidebar class="diagram-sidebar" @dragInNode="$_dragInNode" />
<div ref="container" class="diagram-container">
<div class="diagram-wrapper">
<div ref="diagram" class="lf-diagram"></div>
</div>
</div>
</div>
<!-- 右侧属性面板 -->
<PropertyPanel ref="panelRef" @setProperties="$setProperties" />
</div>
</template>
<script>
import LogicFlow from '@logicflow/core'
import { SelectionSelect, Menu, BpmnElement } from '@logicflow/extension'
import '@logicflow/core/dist/style/index.css'
import '@logicflow/extension/lib/style/index.css'
import DiagramToolbar from './DiagramToolbar.vue'
import DiagramSidebar from './DiagramSidebar.vue'
import PropertyPanel from './PropertyPanel.vue'
import { registerCustomElement } from './node'
// import { Control } from "@logicflow/extension";
export default {
name: 'Diagram',
components: {
DiagramToolbar,
DiagramSidebar,
PropertyPanel
},
props: {
fieldList: {
type: Array,
default: () => {
return []
}
},
conf: {
type: Object,
default: () => {
return {}
}
}
},
data() {
return {
sidebarWidth: 200,
diagramWidth: 0,
diagramHeight: 0,
lf: null,
filename: '',
activeEdges: []
}
},
mounted() {
// const data = ''
this.filename = 'export.json'
// const d = window.sessionStorage.getItem(this.filename)
// if (d) {
// data = JSON.parse(d)
// }
this.initLogicFlow(this.conf)
},
methods: {
initLogicFlow(data) {
// 引入框选插件
LogicFlow.use(SelectionSelect)
LogicFlow.use(Menu)
LogicFlow.use(BpmnElement)
const lf = new LogicFlow({
container: this.$refs.diagram,
overlapMode: 1,
autoWrap: true,
metaKeyMultipleSelected: true,
keyboard: {
enabled: true
},
grid: {
size: 10,
type: 'dot'
}
})
lf.setTheme({
baseEdge: { strokeWidth: 1 },
baseNode: { strokeWidth: 1 },
nodeText: { overflowMode: 'autoWrap', lineHeight: 1.5 },
edgeText: { overflowMode: 'autoWrap', lineHeight: 1.5 }
})
// 注册自定义元素
registerCustomElement(lf)
lf.setDefaultEdgeType('pro-polyline')
lf.render(data)
this.lf = lf
this.lf.on('node:click', (e) => {
console.log('点击节点', e.data)
this.$refs.panelRef.open(e.data, this.fieldList)
})
// lf.renderRawData( )
},
$_dragInNode(type, text = '') {
this.lf.dnd.startDrag({
type,
text
})
},
// 获取可以进行设置的属性
$_getProperty() {
// this.lf.getProperties(node.id)
},
$setProperties(node, item) {
this.lf.setProperties(node.id, item)
},
$_setZIndex(node, type) {
this.lf.setElementZIndex(node.id, type)
},
importData(text) {
this.lf.renderRawData(text)
},
$_saveGraph() {
const data = this.lf.getGraphData()
this.download(this.filename, JSON.stringify(data))
},
download(filename, text) {
window.sessionStorage.setItem(filename, text)
const element = document.createElement('a')
element.setAttribute(
'href',
'data:text/plain;charset=utf-8,' + encodeURIComponent(text)
)
element.setAttribute('download', filename)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
},
getData() {
/**
* 校验目标
* 1. 必须存在开始节点和结束节点
* 2. 连线方向正确
* 3. 多余的节点(不重要)
* 4. 所有分支必须结束节点
* 5. 检查审批节点设置情况
* 6. 一个节点可以有多个子网关,子网关只能通过一个,不能有多个普通子节点
*
*/
return new Promise((resolve, reject) => {
const data = this.lf.getGraphData()
const nodes = data.nodes
const edges = data.edges
let haveMoreChildNode = false
const sourceNodeIdSum = {} //节点id->[子节点id]
edges.forEach((edge) => {
const targetNode = nodes.find((item) => item.id == edge.targetNodeId)
if (sourceNodeIdSum[edge.sourceNodeId]) {
sourceNodeIdSum[edge.sourceNodeId].push(targetNode)
for (const n of sourceNodeIdSum[edge.sourceNodeId]) {
if (n.type != 'bpmn:exclusiveGateway') {
haveMoreChildNode = true
break
}
}
} else {
sourceNodeIdSum[edge.sourceNodeId] = [targetNode]
}
})
console.log('sourceNodeIdSum', sourceNodeIdSum)
if (haveMoreChildNode) {
// 如果都是网关就可以,等优化
return reject({
message: '流程设计-一个节点只能有一个子节点,可以有多个网关'
})
}
// if (data.nodes.length != data.edges.length + 1) {
// return reject({
// message: "流程设计-节点之间必须连线,可以清理多余的节点",//不是很重要
// });
// }
// 检查开始节点和结束节点是否存在
const findStartNode = nodes.filter((item) => item.type == 'bpmn:startEvent')
const findEndNode = nodes.filter((item) => item.type == 'bpmn:endEvent')
if (findStartNode.length != 1 || findEndNode.length != 1) {
return reject({
message: '流程设计-流程必须有且只有一个开始节点和结束节点'
})
}
function handel(arr, pid) {
const newArr = []
arr.forEach((node) => {
// console.log('sourceNodeIdSum', sourceNodeIdSum, node.id)
const newNode = {
id: node.id,
pid: pid,
label: node?.text?.value,
type: node.type,
fieldAuth: node?.properties?.fieldAuth,
gateway: node?.properties?.gateway,
userType: node?.properties?.userType || 0,
userId: node?.properties?.userId || 0,
deptId: node?.properties?.deptId || 0,
postId: node?.properties?.postId || 0
}
if (sourceNodeIdSum[node.id]) {
newNode.children = handel(sourceNodeIdSum[node.id], node.id)
}
newArr.push(newNode)
})
return newArr
}
const TreeNode = handel(findStartNode, 0)
// tree转list
function treeToList(tree) {
const arr = []
tree.forEach((item) => {
arr.push(item)
if (item.children) {
arr.push(...treeToList(item.children))
}
})
return arr
}
console.log('TreeNode', TreeNode)
console.log('treeToList', treeToList(TreeNode))
// 检查连线方向是否正确;
resolve({ formData: data, treeToList: treeToList(TreeNode) })
})
}
}
}
</script>
<style lang="scss">
.diagram {
width: 100%;
height: 100%;
position: relative;
}
.diagram-toolbar {
position: absolute;
top: 10px;
right: 20px;
height: 40px;
padding: 0 10px;
/* width: 310px; */
display: flex;
align-items: center;
/* border-bottom: 1px solid #e5e5e5; */
z-index: 10;
background: #fff;
box-shadow: 0px 0px 4px rgba($color: #000000, $alpha: 0.5);
}
.diagram-main {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
.diagram-sidebar {
position: absolute;
left: 20px;
z-index: 10;
top: 50px;
width: 60px;
background: #fff;
box-shadow: 0px 0px 4px rgba($color: #000000, $alpha: 0.5);
}
.diagram-container {
height: 100%;
.diagram-wrapper {
box-sizing: border-box;
width: 100%;
height: 100%;
.lf-diagram {
// box-shadow: 0px 0px 4px #838284;
width: 100%;
height: 100%;
}
}
}
/* 由于背景图和gird不对齐需要css处理一下 */
.diagram-container :v-deep .lf-background {
left: -9px;
}
}
::-webkit-scrollbar {
width: 9px;
height: 9px;
background: white;
border-left: 1px solid #e8e8e8;
}
::-webkit-scrollbar-thumb {
border-width: 1px;
border-style: solid;
border-color: #fff;
border-radius: 6px;
background: #c9c9c9;
}
::-webkit-scrollbar-thumb:hover {
background: #b5b5b5;
}
</style>

View File

@@ -1,133 +0,0 @@
<template>
<el-drawer
v-model="drawerVisible"
size="600px"
:title="'节点:' + node?.text?.value"
@close="close"
>
<!-- fieldList:{{ fieldList }}
<div>properties:{{ properties }}</div> -->
<!-- 开始节点 -->
<!-- {{ node }} -->
<div v-if="node.type == 'bpmn:startEvent'">
开始节点
<FieldAuth :node="node" :properties="properties" :fieldList="fieldList"></FieldAuth>
</div>
<div v-if="node.type == 'bpmn:userTask'">
<UserTask :node="node" :properties="properties" :fieldList="fieldList"></UserTask>
<FieldAuth :node="node" :properties="properties" :fieldList="fieldList"></FieldAuth>
</div>
<div v-if="node.type == 'bpmn:serviceTask'">
<div>系统任务</div>
<div>抄送</div>
<div>发送邮件</div>
<div>发送短信</div>
<div>发送站内消息</div>
<div>数据入库</div>
</div>
<div v-if="node.type == 'bpmn:exclusiveGateway'">
<Gateway :node="node" :properties="properties" :fieldList="fieldList"></Gateway>
</div>
<div v-if="node.type == 'bpmn:endEvent'">结束</div>
</el-drawer>
</template>
<script>
import UserTask from './PropertyPanel/UserTask.vue'
import FieldAuth from './PropertyPanel/FieldAuth.vue'
import Gateway from './PropertyPanel/Gateway.vue'
export default {
name: 'PropertyPanel',
props: {},
components: {
UserTask,
FieldAuth,
Gateway
},
data() {
return {
drawerVisible: false,
node: {},
properties: {
userType: '',
userId: '', //审批人id
deptId: '', //审批部门id
postId: '', //岗位id
fieldAuth: {}, // 字段权限
gateway: [] //网关条件列表
},
/**
* 表单列表
* [{
* id: 1,
* label: '表单1',
* auth: 1,
* }]
*/
fieldList: []
}
},
methods: {
open(node, fieldList) {
this.node = node
this.properties.userType = node?.properties?.userType || ''
this.properties.userId = node?.properties?.userId || ''
this.properties.deptId = node?.properties?.deptId || ''
this.properties.postId = node?.properties?.postId || ''
this.properties.gateway = node?.properties?.gateway || []
this.properties.fieldAuth = node?.properties?.fieldAuth
? { ...node?.properties?.fieldAuth }
: {}
this.fieldList = fieldList.map((item) => {
let auth = 1
const formId = item?.field?.id
if (node?.properties?.fieldAuth?.[formId]) {
auth = node.properties.fieldAuth[formId]
}
return {
id: formId,
label: item?.field?.options?.label,
auth: auth
}
})
this.drawerVisible = true
},
close() {
const fieldAuth = {}
this.fieldList.forEach((item) => {
fieldAuth[item.id] = item.auth
})
this.$emit('setProperties', this.node, { ...this.properties })
// this.setProperties('fieldAuth', {
// ...fieldAuth
// })
// this.setProperties('userType', this.properties.userType)
// this.setProperties('userId', this.properties.userId)
// this.setProperties('deptId', this.properties.deptId)
// this.setProperties('postId', this.properties.postId)
// this.setProperties('gateway', this.properties.gateway)
},
setProperties(key, val) {
this.$emit('setProperties', this.node, {
[key]: val
})
}
}
}
</script>
<style scoped></style>

View File

@@ -1,11 +1,10 @@
<template>
<div style="padding-bottom: 10px">
<el-card header="条件编辑">
<el-alert title="同一父级的网关只能有一个通过" type="warning" />
<el-alert title="同一父级的网关只能有一个通过" type="warning" :closable="false" />
<!-- 设置优先级 -->
<div style="padding: 40px 0 20px">
<el-select v-model="selectGateway" placeholder="请选择">
<div style="padding: 20px 0 20px" class="flex">
<el-select class="flex-1" v-model="selectGateway" placeholder="请选择">
<el-option
v-for="item in fieldList"
:key="item.id"
@@ -24,7 +23,7 @@
{{ getLabel(row.id) }}
</template>
</el-table-column>
<el-table-column label="权限">
<el-table-column label="判断方式">
<template #default="{ row }">
<el-select v-model="row.condition" placeholder="请选择判断符">
<el-option
@@ -53,27 +52,16 @@
<script setup lang="ts">
import { ref } from 'vue'
import type { PropType } from 'vue'
// import type { PropType } from 'vue'
import { Close } from '@element-plus/icons-vue'
const props = defineProps({
node: {
type: Object,
default: () => ({})
},
fieldList: {
type: Array as PropType<
{
id: string
label: string
}[]
>,
default: () => []
},
properties: {
type: Object,
default: () => ({})
}
})
import type { NodeType, PropertiesType, FieldListType } from './property.type'
const props = defineProps<{
node?: NodeType
fieldList?: FieldListType[]
properties?: PropertiesType
}>()
const conditionList = [
{
value: '==',
@@ -100,7 +88,7 @@ const selectGateway = ref('')
function getLabel(id) {
return props.fieldList.find((item) => {
if (item.id === id) {
return item.label
return true
}
})?.label
}

View File

@@ -14,7 +14,7 @@
</el-form-item>
<el-form-item label="指定部门" v-if="props.properties.userType == 1">
<el-select
<!-- <el-select
v-model="props.properties.deptId"
placeholder="请选择审批部门"
style="width: 100%"
@@ -25,14 +25,18 @@
:label="item.label"
:value="item.value"
/>
</el-select>
</el-select> -->
<el-tree-select
v-model="props.properties.deptId"
:data="deptList"
:check-strictly="true"
default-expand-all
:render-after-expand="false"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="岗位" v-if="[1].includes(props.properties.userType)">
<el-select
v-model="props.properties.postId"
placeholder="请选择岗位"
style="width: 100%"
>
<el-select v-model="props.properties.postId" placeholder="请选择岗位">
<el-option
v-for="item in postList"
:key="item.value"
@@ -63,48 +67,44 @@
</div>
</template>
<script setup>
import { ref } from 'vue'
import { adminLists } from '@/api/perms/admin'
import { deptLists } from '@/api/org/department'
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { adminListAll } from '@/api/perms/admin'
import { deptAll } from '@/api/org/department'
import { postAll } from '@/api/org/post'
const props = defineProps({
node: {
type: Object,
default: () => ({})
},
properties: {
type: Object,
default: () => ({})
},
fieldList: {
type: Array,
default: () => []
}
})
import { arrayToTree } from '@/utils/util'
import type { NodeType, PropertiesType, FieldListType } from './property.type'
const props = defineProps<{
node?: NodeType
fieldList?: FieldListType[]
properties?: PropertiesType
}>()
const adminUserList = ref([])
const deptList = ref([])
const postList = ref([])
function getAdminList() {
adminLists().then((res) => {
adminUserList.value = res.lists.map((item) => {
adminListAll({}).then((res) => {
adminUserList.value = res.map((item) => {
return {
value: item.id,
label: item.nickname
label: item.nickname + ' (' + item.username + ')'
}
})
})
}
function getDeptList() {
deptLists().then((res) => {
deptList.value = res.map((item) => {
deptAll().then((res) => {
const list = res.map((item) => {
return {
value: item.id,
label: item.name
label: item.name,
...item
}
})
deptList.value = arrayToTree(list, '')
})
}
function getPostList() {

View File

@@ -0,0 +1,97 @@
<template>
<el-drawer
v-model="drawerVisible"
size="600px"
:title="'节点:' + node?.text?.value"
@close="close"
>
<div v-if="node.type == 'bpmn:startEvent'">
<FieldAuth :node="node" :properties="properties" :fieldList="fieldList"></FieldAuth>
</div>
<div v-if="node.type == 'bpmn:userTask'">
<UserTask :node="node" :properties="properties" :fieldList="fieldList"></UserTask>
<FieldAuth :node="node" :properties="properties" :fieldList="fieldList"></FieldAuth>
</div>
<div v-if="node.type == 'bpmn:serviceTask'">
<div>都还不支持系统任务</div>
<div>都还不支持抄送</div>
<div>都还不支持发送邮件</div>
<div>都还不支持发送短信</div>
<div>都还不支持发送站内消息</div>
<div>都还不支持数据入库</div>
</div>
<div v-if="node.type == 'bpmn:exclusiveGateway'">
<Gateway :node="node" :properties="properties" :fieldList="fieldList"></Gateway>
</div>
<div v-if="node.type == 'bpmn:endEvent'">结束</div>
</el-drawer>
</template>
<script setup lang="ts">
import { ref, toRaw, reactive } from 'vue'
import UserTask from './UserTask.vue'
import FieldAuth from './FieldAuth.vue'
import Gateway from './Gateway.vue'
import type { NodeType, PropertiesType, FormFieldListType, FieldListType } from './property.type'
defineOptions({
name: 'PropertyPanel'
})
const emit = defineEmits(['setProperties'])
const drawerVisible = ref(false)
const node = ref<NodeType>({})
const properties = reactive<PropertiesType>({
userType: null,
userId: null,
deptId: null,
postId: null,
fieldAuth: {},
gateway: []
})
const fieldList = ref<FieldListType[]>([])
const open = (newNode: NodeType, newFieldList: FormFieldListType[]) => {
if (newNode.type == 'bpmn:endEvent') {
return
}
node.value = newNode
properties.userType = newNode?.properties?.userType || null
properties.userId = newNode?.properties?.userId || null
properties.deptId = newNode?.properties?.deptId || null
properties.postId = newNode?.properties?.postId || null
properties.gateway = newNode?.properties?.gateway || []
properties.fieldAuth = newNode?.properties?.fieldAuth
? { ...newNode?.properties?.fieldAuth }
: {}
fieldList.value = newFieldList.map((item) => {
return {
id: item?.field?.id,
label: item?.field?.options?.label,
auth: newNode?.properties?.fieldAuth?.[item?.field?.id] || 1
}
})
drawerVisible.value = true
}
const close = () => {
const fieldAuth = {}
fieldList.value.forEach((item) => {
fieldAuth[item.id] = item.auth
})
properties.fieldAuth = fieldAuth
emit('setProperties', toRaw(node.value), { ...toRaw(properties) })
drawerVisible.value = false
}
defineExpose({
open
})
</script>
<style scoped></style>

View File

@@ -0,0 +1,52 @@
export type PropertiesType = {
userType?: number
userId?: string | number
deptId?: string | number
postId?: string | number
fieldAuth?: {
[key: string]: number
}
gateway?: {
id: string
value: string
condition: string
}[]
}
export type NodeType = {
id?: string
type?:
| 'bpmn:startEvent'
| 'bpmn:userTask'
| 'bpmn:serviceTask'
| 'bpmn:exclusiveGateway'
| 'bpmn:endEvent'
text?: {
value?: string
x?: number
y?: number
}
properties?: PropertiesType
x?: number
y?: number
}
// Form读取读取德列表结构
export type FormFieldListType = {
name?: string
type?: string
field?: {
id: string
options?: {
name: string
label: string
defaultValue: ''
}
type?: string //'textarea'
}
}
export type FieldListType = {
id?: string
label?: string
auth?: number
}

View File

@@ -0,0 +1,342 @@
<template>
<div class="diagram">
<diagram-toolbar
v-if="lf"
class="diagram-toolbar"
:lf="lf"
:active-edges="activeEdges"
@saveGraph="saveGraph"
@importData="importData"
/>
<div class="diagram-main">
<diagram-sidebar class="diagram-sidebar" @dragInNode="dragInNode" />
<div ref="container" class="diagram-container">
<div class="diagram-wrapper">
<div ref="diagramRef" class="lf-diagram"></div>
</div>
</div>
</div>
<!-- Right-side property panel -->
<PropertyPanel ref="PropertyPanelRef" @setProperties="setProperties" />
</div>
</template>
<script setup lang="ts">
// Importing necessary functions and components
import { ref, onMounted } from 'vue'
import LogicFlow from '@logicflow/core'
import { SelectionSelect, Menu, BpmnElement, MiniMap } from '@logicflow/extension'
// import '@logicflow/core/dist/style/index.css'
// import '@logicflow/extension/lib/style/index.css'
import '@logicflow/core/lib/style/index.css'
import '@logicflow/extension/lib/style/index.css'
import DiagramToolbar from './DiagramToolbar.vue'
import DiagramSidebar from './DiagramSidebar.vue'
import PropertyPanel from './PropertyPanel/index.vue'
import { registerCustomElement } from './node'
defineOptions({
name: 'flowEdit'
})
// Define component props
const props = defineProps({
tabName: {
type: String,
default: ''
},
fieldList: {
type: Array,
default: () => []
},
conf: {
type: Object,
default: () => ({})
}
})
// Define refs for reactive data and component references
const lf = ref(null) // Reference to LogicFlow instance
const activeEdges = ref([]) // Reactive array for active edges
const diagramRef = ref(null) // Reference to the diagram container
const PropertyPanelRef = ref(null) // Reference to the PropertyPanel component
// Lifecycle hook to initialize LogicFlow when the component is mounted
onMounted(() => {
initLogicFlow(props.conf)
})
// Function to initialize LogicFlow
function initLogicFlow(data) {
// 引入框选插件
LogicFlow.use(SelectionSelect)
LogicFlow.use(Menu)
LogicFlow.use(BpmnElement)
LogicFlow.use(MiniMap)
// Creating a new LogicFlow instance
const logicFlowInstance = new LogicFlow({
container: diagramRef.value, // Setting the container where LogicFlow will be rendered
overlapMode: 1,
// allowResize: true,
autoWrap: true,
adjustEdge: true,
adjustEdgeStartAndEnd: true,
metaKeyMultipleSelected: true,
keyboard: {
enabled: true
},
grid: {
size: 10,
type: 'dot'
}
})
// Setting theme for LogicFlow
logicFlowInstance.setTheme({
baseEdge: { strokeWidth: 1 },
baseNode: { strokeWidth: 1 },
nodeText: { overflowMode: 'autoWrap', lineHeight: 1.5 },
edgeText: { overflowMode: 'autoWrap', lineHeight: 1.5 }
})
// Registering custom elements for LogicFlow
registerCustomElement(logicFlowInstance)
// Setting default edge type and rendering initial data
logicFlowInstance.setDefaultEdgeType('pro-polyline')
logicFlowInstance.extension.menu.addMenuConfig({
nodeMenu: [
{
text: '属性配置',
callback(node) {
// alert('分享成功!')
PropertyPanelRef.value.open(node, props.fieldList)
}
}
]
})
logicFlowInstance.render(data)
logicFlowInstance.extension.miniMap.show()
// Assigning the LogicFlow instance to the 'lf' ref
lf.value = logicFlowInstance
// Event listener for node clicks
lf.value.on('node:dbclick', (e) => {
console.log('dbclick on node', e.data, props.fieldList)
PropertyPanelRef.value.open(e.data, props.fieldList)
})
}
// Function to handle dragging nodes into the diagram
function dragInNode(type, text = '') {
lf.value.dnd.startDrag({
type,
text
})
}
// Function to set properties of a node
function setProperties(node, item) {
console.log('setProperties', node, item)
lf.value.setProperties(node.id, item)
}
// function setZIndex(node, type) {
// lf.value.setElementZIndex(node.id, type)
// }
// Function to import data into the LogicFlow instance
function importData(text) {
lf.value.renderRawData(text)
}
// Function to save the graph data
function saveGraph() {
const data = lf.value.getGraphData()
download('export.json', JSON.stringify(data))
}
// Function to download the graph data as a file
function download(filename, text) {
window.sessionStorage.setItem(filename, text)
const element = document.createElement('a')
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text))
element.setAttribute('download', filename)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
}
async function getData() {
/**
* 校验目标
* 1. 必须存在开始节点和结束节点
* 2. 连线方向正确
* 3. 多余的节点(不重要)
* 4. 所有分支必须结束节点
* 5. 检查审批节点设置情况
* 6. 一个节点可以有多个子网关,子网关只能通过一个,不能有多个普通子节点
*
*/
return new Promise<{
formData: any
treeToList: any
}>((resolve, reject) => {
const data = lf.value.getGraphData()
const nodes = data.nodes
const edges = data.edges
let haveMoreChildNode = false
const sourceNodeIdSum = {} // Node ID -> child nodes mapping
edges.forEach((edge) => {
const targetNode = nodes.find((item) => item.id === edge.targetNodeId)
if (sourceNodeIdSum[edge.sourceNodeId]) {
sourceNodeIdSum[edge.sourceNodeId].push(targetNode)
for (const n of sourceNodeIdSum[edge.sourceNodeId]) {
if (n.type !== 'bpmn:exclusiveGateway') {
haveMoreChildNode = true
break
}
}
} else {
sourceNodeIdSum[edge.sourceNodeId] = [targetNode]
}
})
if (haveMoreChildNode) {
return reject({
target: props.tabName,
message: '流程设计-一个节点只能有一个子节点,可以有多个网关'
})
}
// 检查开始节点和结束节点是否存在
const findStartNode = nodes.filter((item) => item.type === 'bpmn:startEvent')
const findEndNode = nodes.filter((item) => item.type === 'bpmn:endEvent')
if (findStartNode.length !== 1 || findEndNode.length !== 1) {
return reject({
target: props.tabName,
message: '流程设计-流程必须有且只有一个开始节点和结束节点'
})
}
const TreeNode = handel(nodes, 0)
function handel(arr, pid) {
const newArr = []
arr.forEach((node) => {
const newNode = {
id: node.id,
pid: pid,
label: node?.text?.value,
type: node.type,
fieldAuth: node?.properties?.fieldAuth,
gateway: node?.properties?.gateway,
userType: node?.properties?.userType || 0,
userId: node?.properties?.userId || 0,
deptId: node?.properties?.deptId || 0,
postId: node?.properties?.postId || 0,
children: null
}
if (sourceNodeIdSum[node.id]) {
newNode.children = handel(sourceNodeIdSum[node.id], node.id)
}
newArr.push(newNode)
})
return newArr
}
function treeToList(tree) {
const arr = []
tree.forEach((item) => {
arr.push(item)
if (item.children) {
arr.push(...treeToList(item.children))
}
})
return arr
}
// 检查连线方向是否正确;
resolve({ formData: data, treeToList: treeToList(TreeNode) })
})
}
defineExpose({
getData
})
</script>
<style lang="scss">
.diagram {
width: 100%;
height: 100%;
position: relative;
}
.diagram-toolbar {
position: absolute;
top: 10px;
right: 20px;
height: 40px;
padding: 0 10px;
/* width: 310px; */
display: flex;
align-items: center;
/* border-bottom: 1px solid #e5e5e5; */
z-index: 10;
background: #fff;
box-shadow: 0px 0px 4px rgba($color: #000000, $alpha: 0.5);
}
.diagram-main {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
.diagram-sidebar {
position: absolute;
left: 20px;
z-index: 10;
top: 50px;
width: 60px;
background: #fff;
box-shadow: 0px 0px 4px rgba($color: #000000, $alpha: 0.5);
}
.diagram-container {
height: 100%;
.diagram-wrapper {
box-sizing: border-box;
width: 100%;
height: 100%;
.lf-diagram {
// box-shadow: 0px 0px 4px #838284;
width: 100%;
height: 100%;
}
}
}
/* 由于背景图和gird不对齐需要css处理一下 */
.diagram-container :v-deep .lf-background {
left: -9px;
}
}
::-webkit-scrollbar {
width: 9px;
height: 9px;
background: white;
border-left: 1px solid #e8e8e8;
}
::-webkit-scrollbar-thumb {
border-width: 1px;
border-style: solid;
border-color: #fff;
border-radius: 6px;
background: #c9c9c9;
}
::-webkit-scrollbar-thumb:hover {
background: #b5b5b5;
}
</style>

View File

@@ -13,8 +13,8 @@
<script>
import LogicFlow from '@logicflow/core'
import { BpmnElement } from '@logicflow/extension'
// import { SelectionSelect, Menu } from "@logicflow/extension";
import '@logicflow/core/dist/style/index.css'
import '@logicflow/core/lib/style/index.css'
import '@logicflow/extension/lib/style/index.css'
import { registerCustomElement } from './node'
@@ -27,36 +27,14 @@ export default {
lf: null,
activeNodes: [],
activeEdges: [],
properties: {},
timer: null,
time: 60000
properties: {}
}
},
watch: {
// appStore: {
// handler() {
// if (this.lf) {
// // this.lf.graphModel.resize();
// // this.lf.fitView();
// // 侧栏有动画,所以要加延时
// setTimeout(() => {
// this.lf.graphModel.resize();
// this.lf.fitView();
// }, 500);
// }
// },
// deep: true,
// },
},
mounted() {
// this.initLogicFlow(exportInfo);
},
beforeUnmount() {
if (this.timer) {
clearInterval(this.timer)
}
},
methods: {
initLogicFlow(data) {
// 引入框选插件

View File

@@ -14,6 +14,7 @@
</div>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue'
// import { ElIcon } from 'element-plus'
import { EL_ICON_PREFIX, LOCAL_ICON_PREFIX } from './index'
import ISvgIcon from './svg-icon.vue'

View File

@@ -77,6 +77,7 @@
</template>
<script lang="ts" setup>
import { ref, withDefaults } from 'vue'
import { computed, nextTick, onMounted, reactive, shallowRef, watch } from 'vue'
import { useEventListener } from '@vueuse/core'
import { ElInput } from 'element-plus'

View File

@@ -7,6 +7,7 @@
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue'
import { addUnit } from '@/utils/util'
import type { CSSProperties } from 'vue'

View File

@@ -17,6 +17,7 @@
</template>
<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
import type { PropType } from 'vue'
import { LinkTypeEnum, type Link } from '.'
import ShopPages from './shop-pages.vue'

View File

@@ -17,6 +17,7 @@
</template>
<script lang="ts" setup>
import { computed, shallowRef, ref, watch } from 'vue'
import { LinkTypeEnum, type Link } from '.'
import LinkContent from './index.vue'
import Popup from '@/components/popup/index.vue'

View File

@@ -18,8 +18,9 @@
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import type { PropType } from 'vue'
import { LinkTypeEnum, type Link } from '.'
import { LinkTypeEnum, type Link } from './index'
defineProps({
modelValue: {

View File

@@ -49,7 +49,11 @@ export default defineComponent({
position: relative;
border-radius: 4px;
overflow: hidden;
@apply bg-br-extra-light border border-br-extra-light;
background-color: var(--el-border-color-extra-light);
border-width: 1px;
border-color: var(--el-border-color-extra-light);
.image,
.video {
display: block;

View File

@@ -11,7 +11,8 @@ import {
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'
import { ElMessage, ElTree, type CheckboxValueType } from 'element-plus'
import { shallowRef, type Ref } from 'vue'
import { shallowRef, ref, reactive } from 'vue'
import type { Ref } from 'vue'
// 左侧分组的钩子函数
export function useCate(type: number) {

View File

@@ -273,6 +273,7 @@
</template>
<script lang="ts" setup>
import { computed, onMounted, toRefs, ref, watch } from 'vue'
import { useCate, useFile } from './hook'
import FileItem from './file.vue'
import Preview from './preview.vue'

View File

@@ -80,6 +80,7 @@
</template>
<script lang="ts" name="material-picker">
import { defineComponent, ref, computed, toRefs, watch, nextTick, provide } from 'vue'
import Draggable from 'vuedraggable'
import Popup from '@/components/popup/index.vue'
import FileItem from './file.vue'

View File

@@ -17,6 +17,7 @@
</template>
<script lang="ts" setup>
import { ref, shallowRef, watch, nextTick } from 'vue'
const props = defineProps({
modelValue: {
type: Boolean,

View File

@@ -4,7 +4,7 @@
<div
ref="textRef"
class="overflow-text truncate"
:style="{ textOverflow: overfloType }"
:style="{ textOverflow: overflowType }"
>
{{ content }}
</div>
@@ -13,6 +13,7 @@
</template>
<script lang="ts" setup>
import { ref, shallowRef } from 'vue'
import { useEventListener } from '@vueuse/core'
import { useTooltipContentProps, type Placement } from 'element-plus'
import type { PropType } from 'vue'
@@ -27,7 +28,7 @@ const props = defineProps({
type: String as PropType<Placement>,
default: 'top'
},
overfloType: {
overflowType: {
type: String as PropType<'ellipsis' | 'unset' | 'clip'>,
default: 'ellipsis'
}

View File

@@ -32,14 +32,6 @@ const emit = defineEmits<{
// (event: 'update:modelValue', value: any): void
}>()
const pager = defineModel<Record<string, any>>({})
// const pager = computed({
// get() {
// return props.modelValue
// },
// set(value) {
// emit('update:modelValue', value)
// }
// })
const sizeChange = () => {
pager.value.page = 1
emit('change')

View File

@@ -53,6 +53,7 @@
<script lang="ts" setup>
import { useEventListener } from '@vueuse/core'
import { ref, watch } from 'vue'
import type { PropType } from 'vue'
const props = defineProps({

View File

@@ -12,6 +12,7 @@
:width="width"
draggable
:close-on-click-modal="clickModalClose"
top="0"
@closed="close"
>
<!-- 弹窗内容 -->
@@ -39,7 +40,7 @@
</template>
<script lang="ts">
import { ref, provide } from 'vue'
import { ref, provide, defineComponent, nextTick } from 'vue'
export default defineComponent({
props: {
title: {
@@ -127,8 +128,14 @@ export default defineComponent({
})
</script>
<style scoped lang="scss">
.dialog-body {
white-space: pre-line;
<style lang="scss">
.dialog {
.dialog-body {
white-space: pre-line;
}
.el-dialog__body {
// max-height: calc(100vh - 200px);
overflow: auto;
}
}
</style>

View File

@@ -40,7 +40,7 @@
</template>
<script lang="ts">
import { computed, defineComponent, ref, shallowRef } from 'vue'
import { computed, defineComponent, ref, toRaw, shallowRef } from 'vue'
import useUserStore from '@/stores/modules/user'
import config from '@/config'
import feedback from '@/utils/feedback'

View File

@@ -149,7 +149,7 @@ const secretKey = ref(''), //后端返回的ase加密秘钥
blockBackImgBase = ref(''), //验证滑块的背景图片
backToken = ref(''), //后端返回的唯一token值
startMoveTime = ref(), //移动开始的时间
endMovetime = ref(), //移动结束的时间
endMoveTime = ref(), //移动结束的时间
tipWords = ref(''),
text = ref(''),
finishText = ref(''),
@@ -257,7 +257,7 @@ function move(e) {
//鼠标松开
function end() {
endMovetime.value = +new Date()
endMoveTime.value = +new Date()
//判断是否重合
if (status.value && isEnd.value == false) {
let moveLeftDistance = parseInt((moveBlockLeft.value || '').replace('px', ''))
@@ -284,7 +284,7 @@ function end() {
}, 1500)
}
passFlag.value = true
tipWords.value = `${((endMovetime.value - startMoveTime.value) / 1000).toFixed(
tipWords.value = `${((endMoveTime.value - startMoveTime.value) / 1000).toFixed(
2
)}s验证成功`
setTimeout(() => {

View File

@@ -5,8 +5,8 @@ import CryptoJS from 'crypto-js'
* */
export function aesEncrypt(word, keyWord = 'XwKsGlMcdPMEhR1B') {
const key = CryptoJS.enc.Utf8.parse(keyWord)
const srcs = CryptoJS.enc.Utf8.parse(word)
const encrypted = CryptoJS.AES.encrypt(srcs, key, {
const src = CryptoJS.enc.Utf8.parse(word)
const encrypted = CryptoJS.AES.encrypt(src, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})

View File

@@ -1,3 +1,4 @@
import request from '@/utils/request'
import { dictDataAll } from '@/api/setting/dict'
import { reactive, toRaw } from 'vue'
@@ -38,6 +39,18 @@ export function useDictOptions<T = any>(options: Options) {
}
}
export type type_dict = {
color?: string
createTime?: string
id?: number
name?: string
remark?: string
sort?: number
status?: number
typeId?: number
updateTime?: string
value?: string
}
export function useDictData<T = any>(dict: string[]) {
const options: Options = {}
for (const type of dict) {
@@ -54,4 +67,24 @@ export function useDictData<T = any>(dict: string[]) {
}
}
// export function useAllList<T = any>(options: Options) {}
export function useListAllData<T = any>(paths: Record<string, string>) {
const options: Options = {}
for (const key in paths) {
options[key] = {
api: () => request.get({ url: paths[key], params: {} }),
transformData: (data: any) => {
console.log('data', data)
return data
}
// params: {
// dictType: path
// }
}
}
const { optionsData } = useDictOptions<T>(options)
return {
listAllData: optionsData
}
}

View File

@@ -1,5 +1,7 @@
import useTabsStore from '@/stores/modules/multipleTabs'
import useSettingStore from '@/stores/modules/setting'
import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
export default function useMultipleTabs() {
const router = useRouter()

View File

@@ -9,6 +9,17 @@ interface Options {
firstLoading?: boolean
}
/**
*
* @param {object} options
* @param {number} options.page 页码
* @param {number} options.size 每页条数
* @param {function} options.fetchFun 分页接口函数
* @param {object} options.params 分页参数
* @param {boolean} options.firstLoading 是否首次加载
*
*
*/
export function usePaging<T>(options: Options) {
const { page = 1, size = 15, fetchFun, params = {}, firstLoading = false } = options
// 记录分页初始参数
@@ -51,7 +62,8 @@ export function usePaging<T>(options: Options) {
Object.keys(paramsInit).forEach((item) => {
params[item] = paramsInit[item]
})
getLists()
resetPage()
}
return {
pager,

View File

@@ -1,3 +1,5 @@
import { useRoute } from 'vue-router'
import { watch } from 'vue'
import type { RouteLocationNormalizedLoaded } from 'vue-router'
export function useWatchRoute(callback: (route: RouteLocationNormalizedLoaded) => void) {

View File

@@ -7,6 +7,8 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { RouterView } from 'vue-router'
import useAppStore from '@/stores/modules/app'
import useTabsStore from '@/stores/modules/multipleTabs'
import useSettingStore from '@/stores/modules/setting'

View File

@@ -15,6 +15,7 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import useAppStore from '@/stores/modules/app'
const appStore = useAppStore()

View File

@@ -6,6 +6,7 @@
</el-breadcrumb>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useWatchRoute } from '@/hooks/useWatchRoute'
import type { RouteLocationMatched, RouteLocationNormalizedLoaded } from 'vue-router'
const breadcrumbs = ref<RouteLocationMatched[]>([])

View File

@@ -5,6 +5,7 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import useAppStore from '@/stores/modules/app'
const appStore = useAppStore()
const isCollapsed = computed(() => appStore.isCollapsed)

View File

@@ -29,6 +29,7 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import useAppStore from '@/stores/modules/app'
import Fold from './fold.vue'
import Refresh from './refresh.vue'
@@ -50,9 +51,17 @@ const settingStore = useSettingStore()
<style lang="scss">
.navbar {
height: var(--navbar-height);
@apply flex px-2 bg-body;
display: flex;
padding-left: 8px;
padding-right: 8px;
background-color: var(--el-bg-color);
.navbar-item {
@apply h-full flex justify-center items-center hover:bg-page;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: var(--el-bg-color-page);
}
}
</style>

View File

@@ -28,6 +28,7 @@
</template>
<script setup lang="ts">
import { useRouter } from 'vue-router'
import useMultipleTabs from '@/hooks/useMultipleTabs'
import { useWatchRoute } from '@/hooks/useWatchRoute'
import useTabsStore, { getRouteParams } from '@/stores/modules/multipleTabs'

View File

@@ -18,6 +18,7 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import useUserStore from '@/stores/modules/user'
import feedback from '@/utils/feedback'
const userStore = useUserStore()

View File

@@ -13,6 +13,8 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { RouterView } from 'vue-router'
import useAppStore from '@/stores/modules/app'
import useTabsStore from '@/stores/modules/multipleTabs'
import useSettingStore from '@/stores/modules/setting'

View File

@@ -83,6 +83,7 @@
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import useSettingStore from '@/stores/modules/setting'
import { useDark, useToggle } from '@vueuse/core'
import theme_light from '@/assets/images/theme_white.png'
@@ -214,7 +215,10 @@ const resetTheme = () => {
<style lang="scss" scoped>
.icon-select {
@apply absolute left-1/2 top-1/2;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
</style>

View File

@@ -3,7 +3,7 @@
<el-drawer
v-model="showMenuDrawer"
direction="ltr"
:size="drawderSize"
:size="drawerSize"
title="主题设置"
:with-header="false"
>
@@ -14,6 +14,7 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import Side from './side.vue'
import useAppStore from '@/stores/modules/app'
import useSettingStore from '@/stores/modules/setting'
@@ -32,7 +33,7 @@ const showMenuDrawer = computed({
}
})
const drawderSize = computed(() => {
const drawerSize = computed(() => {
return `${settingStore.sideWidth + 1}px`
})
</script>

View File

@@ -1,18 +1,18 @@
<template>
<div class="logo">
<image-contain :width="szie" :height="szie" :src="config.webLogo" />
<image-contain :width="size" :height="size" :src="config.webLogo" />
<transition name="title-width">
<div
v-show="showTitle"
class="logo-title overflow-hidden whitespace-nowrap"
:class="{ 'text-white': theme == ThemeEnum.DARK }"
:style="{ left: `${szie + 16}px` }"
:style="{ left: `${size + 16}px` }"
>
<overflow-tooltip
:content="title || config.webName"
:teleported="true"
placement="bottom"
overflo-type="unset"
overflow-type="unset"
>
</overflow-tooltip>
</div>
@@ -21,13 +21,14 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import useAppStore from '@/stores/modules/app'
import { ThemeEnum } from '@/enums/appEnums'
defineOptions({
name: 'SideLogo'
})
defineProps({
szie: { type: Number, default: 34 },
size: { type: Number, default: 34 },
title: { type: String },
theme: { type: String },
showTitle: { type: Boolean, default: true }

View File

@@ -25,6 +25,7 @@
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { getNormalPath, objectToQuery } from '@/utils/util'
import { isExternal } from '@/utils/validate'
import type { RouteRecordRaw } from 'vue-router'

View File

@@ -27,6 +27,8 @@
<script setup lang="ts">
import type { PropType } from 'vue'
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import MenuItem from './menu-item.vue'
import type { RouteRecordRaw } from 'vue-router'
defineOptions({

View File

@@ -14,6 +14,7 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { RouteRecordRaw } from 'vue-router'
import useAppStore from '@/stores/modules/app'
import useSettingStore from '@/stores/modules/setting'

View File

@@ -1,5 +1,6 @@
import { getConfig } from '@/api/app'
import { defineStore } from 'pinia'
import { nextTick } from 'vue'
interface AppSate {
config: Record<string, any>
isMobile: boolean

View File

@@ -1,3 +1,4 @@
import { unref } from 'vue'
import { defineStore } from 'pinia'
import { isExternal } from '@/utils/validate'
import type {

View File

@@ -1,7 +1,7 @@
import { defineStore } from 'pinia'
import defaultSetting from '@/config/setting'
import cache from '@/utils/cache'
import { isObject } from '@vue/shared'
import { isObject } from '@/utils/util'
import { setTheme } from '@/utils/theme'
import { SETTING_KEY } from '@/enums/cacheEnums'
const storageSetting = cache.get(SETTING_KEY)

View File

@@ -1,5 +1,5 @@
.x-loading {
background-color: #17607d;
background-color: #6676fe;
position: fixed;
height: 100%;

View File

@@ -1,4 +1,4 @@
import { isObject } from '@vue/shared'
// import { isObject } from '@vue/shared'
import { cloneDeep } from 'lodash-es'
// import { md5 } from 'js-md5'
import MD5 from 'crypto-js/md5'
@@ -21,14 +21,19 @@ export const addUnit = (value: string | number, unit = 'px') => {
}
/**
* @description 添加单位
* @param {unknown} value
* @description 是否为空
* @param {any} value
* @return {Boolean}
*/
export const isEmpty = (value: unknown) => {
return value == null && typeof value == 'undefined'
export const isEmpty = (value: any) => {
return value === '' || value === null || value === undefined
}
/**
* 判读是否为对象
*/
export const isObject = (val: any): boolean => {
return val !== null && typeof val === 'object'
}
/**
* @description 树转数组,队列实现广度优先遍历
* @param {Array} data 数据
@@ -134,3 +139,15 @@ export const getNonDuplicateID = (length = 8) => {
export const firstToUpperCase = (str = '') => {
return str.toLowerCase().replace(/( |^)[a-z]/g, ($1) => $1.toUpperCase())
}
/**
* @description 清空对象空值属性
*/
export const clearEmpty = (obj: Record<string, any>) => {
for (const key of Object.keys(obj)) {
if (isEmpty(obj[key])) {
delete obj[key]
}
}
return obj
}

View File

@@ -103,6 +103,7 @@
<script lang="ts" setup>
import { computed, onMounted, reactive, shallowRef } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import type { InputInstance, FormInstance } from 'element-plus'
import LayoutFooter from '@/layout/components/footer.vue'
import useAppStore from '@/stores/modules/app'
@@ -113,7 +114,7 @@ import { PageEnum } from '@/enums/pageEnum'
import { useLockFn } from '@/hooks/useLockFn'
import { encryptPassword } from '@/utils/util'
import Verify from '@/components/verify/Verify.vue'
import ImageContain from '@/components/image-contain/index.vue'
// const verifyRef = ref(null)
const verifyRef = shallowRef<InstanceType<typeof Verify>>()
const onShowCaptcha = () => {
@@ -190,7 +191,8 @@ onMounted(() => {
<style lang="scss" scoped>
.login {
background-image: url('./images/login_bg.png');
// background-image: url('./images/login_bg.png');
background-color: #f8f8f8;
background-repeat: no-repeat;
background-size: cover;
height: 100vh;

View File

@@ -26,6 +26,7 @@
</div>
</template>
<script lang="ts" setup>
import { ref, computed, shallowRef, reactive } from 'vue'
import type { FormInstance } from 'element-plus'
import { articleCateEdit, articleCateAdd, articleCateDetail } from '@/api/article'
import Popup from '@/components/popup/index.vue'

View File

@@ -66,6 +66,7 @@
</div>
</template>
<script lang="ts" setup>
import { ref, shallowRef, nextTick } from 'vue'
import { articleCateDelete, articleCateLists, articleCateStatus } from '@/api/article'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'

View File

@@ -112,6 +112,8 @@
</template>
<script lang="ts" setup>
import { reactive, shallowRef } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import type { FormInstance } from 'element-plus'
import feedback from '@/utils/feedback'
import { useDictOptions } from '@/hooks/useDictOptions'

View File

@@ -87,6 +87,7 @@
</div>
</template>
<script lang="ts" setup name="articleLists">
import { reactive, onActivated } from 'vue'
import { articleLists, articleDelete, articleStatus, articleCateAll } from '@/api/article'
import { useDictOptions } from '@/hooks/useDictOptions'
import { usePaging } from '@/hooks/usePaging'

View File

@@ -29,6 +29,7 @@ import {
} from '@/api/article_collect'
import Popup from '@/components/popup/index.vue'
import feedback from '@/utils/feedback'
import { computed, reactive, ref, shallowRef } from 'vue'
import type { PropType } from 'vue'
defineProps({
dictData: {

View File

@@ -61,6 +61,7 @@
</div>
</template>
<script lang="ts" setup>
import { shallowRef, ref, reactive, nextTick } from 'vue'
import { article_collect_delete, article_collect_lists } from '@/api/article_collect'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'

View File

@@ -84,6 +84,8 @@
</template>
<script lang="ts" setup>
import { useRoute } from 'vue-router'
import { shallowRef, reactive } from 'vue'
import type { FormInstance } from 'element-plus'
import { getUserDetail, userEdit } from '@/api/consumer'
import feedback from '@/utils/feedback'

View File

@@ -54,6 +54,7 @@
</div>
</template>
<script lang="ts" setup>
import { reactive, onActivated } from 'vue'
import { usePaging } from '@/hooks/usePaging'
import { getUserList } from '@/api/consumer'

View File

@@ -66,14 +66,14 @@
</el-tab-pane>
<el-tab-pane label="字段管理" name="column">
<el-table :data="formData.column">
<el-table-column label="字段列名" prop="columnName" />
<el-table-column label="字段列名" prop="columnName" min-width="120" />
<el-table-column label="字段描述" prop="columnComment" min-width="120">
<template v-slot="{ row }">
<el-input v-model="row.columnComment"></el-input>
</template>
</el-table-column>
<el-table-column label="sql类型" prop="columnType" min-width="100" />
<el-table-column label="go类型" min-width="100">
<el-table-column label="go类型" min-width="140">
<template v-slot="{ row }">
<el-select v-model="row.goType">
<el-option label="int" value="int" />
@@ -82,7 +82,7 @@
<el-option label="float64" value="float64" />
<el-option label="rune" value="rune" />
<el-option label="bool" value="bool" />
<el-option label="TsTime" value="core.TsTime" />
<el-option label="NullTime" value="core.NullTime" />
</el-select>
</template>
</el-table-column>
@@ -136,7 +136,7 @@
/>
</template>
</el-table-column>
<el-table-column label="查询方式">
<el-table-column label="查询方式" min-width="140">
<template v-slot="{ row }">
<el-select v-model="row.queryType">
<el-option label="=" value="EQ" />
@@ -150,7 +150,7 @@
</el-select>
</template>
</el-table-column>
<el-table-column label="显示类型" min-width="120">
<el-table-column label="显示类型" min-width="140">
<template v-slot="{ row }">
<el-select v-model="row.htmlType">
<el-option label="文本框" value="input" />
@@ -165,19 +165,19 @@
</el-select>
</template>
</el-table-column>
<el-table-column label="字典类型" min-width="120">
<el-table-column label="字典类型" min-width="140">
<template v-slot="{ row }">
<el-select
v-model="row.dictType"
clearable
:disabled="
!(
row.htmlType == 'select' ||
v-if="
(row.htmlType == 'select' ||
row.htmlType == 'radio' ||
row.htmlType == 'checkbox'
)
row.htmlType == 'checkbox') &&
!row.listAllApi
"
placeholder="字典类型"
@change="row.listAllApi = null"
>
<el-option
v-for="(item, index) in optionsData.dictType"
@@ -189,6 +189,31 @@
</el-select>
</template>
</el-table-column>
<el-table-column label="数据来源(字典类型优先)" min-width="280">
<template v-slot="{ row }">
<el-select
v-model="row.listAllApi"
clearable
filterable
v-if="
(row.htmlType == 'select' ||
row.htmlType == 'radio' ||
row.htmlType == 'checkbox') &&
!row.dictType
"
placeholder="字典类型"
@change="row.dictType = null"
>
<el-option
v-for="(item, index) in optionsData.ApiList"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="生成配置" name="config">
@@ -265,11 +290,15 @@
</template>
<script lang="ts" setup>
import { useRoute, useRouter } from 'vue-router'
import { ref, reactive, shallowRef } from 'vue'
import { generateEdit, tableDetail } from '@/api/tools/code'
import { dictTypeAll } from '@/api/setting/dict'
import type { FormInstance } from 'element-plus'
import feedback from '@/utils/feedback'
import { menuLists } from '@/api/perms/menu'
import { getApiList } from '@/api/setting/website'
import { useDictOptions } from '@/hooks/useDictOptions'
import useMultipleTabs from '@/hooks/useMultipleTabs'
enum GenTpl {
@@ -332,6 +361,7 @@ const getDetails = async () => {
const { optionsData } = useDictOptions<{
dictType: any[]
menu: any[]
ApiList: string[]
}>({
dictType: {
api: dictTypeAll
@@ -343,6 +373,14 @@ const { optionsData } = useDictOptions<{
menu.children = data
return menu
}
},
ApiList: {
api: getApiList,
transformData(data: any) {
return data.filter((item: any) => {
return item.endsWith('listAll')
})
}
}
})

View File

@@ -144,6 +144,7 @@
</template>
<script lang="ts" setup>
import { ref, reactive, onActivated } from 'vue'
import {
generateTable,
syncColumn,

View File

@@ -1,7 +1,13 @@
<template>
<div class="code-preview">
<el-dialog v-model="show" width="95%" title="代码预览">
<el-container style="height: 75vh">
<el-dialog
v-model="show"
width="98%"
:title="'代码预览【' + showItem.label + '】'"
top="0px"
draggable
>
<el-container style="max-height: calc(100vh - 200px)">
<el-aside
width="400px"
style="padding: 10px 0; margin-right: 20px; border: 1px solid #dcdfe6"
@@ -15,7 +21,7 @@
</el-aside>
<el-main style="padding: 0; border: 1px solid #dcdfe6">
<div class="flex flex-col h-[100%]">
<div class="flex">
<!-- <div class="flex">
<div class="flex-1 p-4">{{ showItem.label }}</div>
<div>
<el-button @click="handleCopy(showItem.value)" type="primary" link>
@@ -25,19 +31,38 @@
复制
</el-button>
</div>
</div>
</div> -->
<div class="flex-1 overflow-auto">
<highlightjs autodetect :code="showItem.value" language="javascript" />
<div style="height: calc(100vh - 200px)">
<highlightjs
autodetect
:code="showItem.value"
language="javascript"
/>
</div>
</div>
</div>
</el-main>
</el-container>
<template v-slot:footer>
<div>
<!-- {{ showItem.label }} -->
<el-button
icon="el-icon-CopyDocument"
type="primary"
@click="handleCopy(showItem.value)"
>复制</el-button
>
<el-button @click="show = false">关闭</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, computed } from 'vue'
import feedback from '@/utils/feedback'
import useClipboard from 'vue-clipboard3'
@@ -110,3 +135,9 @@ const show = computed<boolean>({
}
})
</script>
<style lang="scss">
.code-preview .el-dialog__body {
// max-height: calc(100vh - 200px);
overflow: auto;
}
</style>

View File

@@ -44,6 +44,7 @@
</template>
<script lang="ts" setup>
import { shallowRef, reactive, watch, ref } from 'vue'
import Popup from '@/components/popup/index.vue'
import Pagination from '@/components/pagination/index.vue'
import { usePaging } from '@/hooks/usePaging'

View File

@@ -25,7 +25,11 @@
<!-- {{ historyList }} -->
<template #footer>
<el-button @click="dialogVisible = false">关闭</el-button>
<el-button v-if="applyDetail.status == 1" type="primary" @click="onSubmit">
<el-button
v-if="applyDetail.status == 1 || applyDetail.status == 4"
type="primary"
@click="onSubmit"
>
确定
</el-button>
</template>
@@ -33,7 +37,7 @@
</template>
<script setup>
import { ref } from 'vue'
import { ref, reactive } from 'vue'
import 'vform3-builds/dist/designer.style.css' //引入VForm3样式
import { flow_history_list_all } from '@/api/flow/flow_history'

View File

@@ -48,13 +48,13 @@
<template #footer>
<el-button @click="dialogVisible = false">关闭</el-button>
<el-button type="primary" @click="submit"> 通过 </el-button>
<el-button type="primary" @click="submit"> 确定 </el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ref, reactive, computed } from 'vue'
import feedback from '@/utils/feedback'
import {
flow_history_next_node,

View File

@@ -38,6 +38,7 @@
import type { FormInstance } from 'element-plus'
import { flow_apply_edit, flow_apply_add, flow_apply_detail } from '@/api/flow/flow_apply'
import { flow_template_lists_all } from '@/api/flow/flow_template'
import type { type_flow_template } from '@/api/flow/flow_template'
import Popup from '@/components/popup/index.vue'
import feedback from '@/utils/feedback'
@@ -143,7 +144,7 @@ const formRules = {
}
]
}
const flow_template = ref([])
const flow_template = ref<type_flow_template[]>([])
const get_flow_template = async () => {
flow_template.value = await flow_template_lists_all()
}

View File

@@ -101,12 +101,14 @@
</div>
</template>
<script lang="ts" setup>
import { shallowRef, reactive } from 'vue'
import {
flow_apply_delete,
flow_apply_lists,
flow_apply_edit,
flow_apply_detail
} from '@/api/flow/flow_apply'
import type { type_flow_apply } from '@/api/flow/flow_apply'
import { useDictData } from '@/hooks/useDictOptions'
import { usePaging } from '@/hooks/usePaging'
@@ -131,7 +133,7 @@ const queryParams = reactive({
status: '3'
})
const { pager, getLists, resetPage, resetParams } = usePaging({
const { pager, getLists, resetPage, resetParams } = usePaging<type_flow_apply>({
fetchFun: flow_apply_lists,
params: queryParams
})
@@ -142,7 +144,7 @@ const { dictData } = useDictData<{
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除?')
await flow_apply_delete({ id })
await flow_apply_delete(id)
feedback.msgSuccess('删除成功')
getLists()
}

View File

@@ -84,10 +84,10 @@
link
@click="OpenViewForm(row)"
>
{{ row.status == 1 ? '编辑' : '预览' }}
{{ row.status == 1 || row.status == 4 ? '编辑' : '预览' }}
</el-button>
<el-button
v-if="row.status == 1 && row.formValue"
v-if="(row.status == 1 || row.status == 4) && row.formValue"
v-perms="['admin:flow:flow_apply:edit']"
type="primary"
link
@@ -136,6 +136,7 @@
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, shallowRef, nextTick } from 'vue'
import {
flow_apply_delete,
flow_apply_lists,
@@ -143,7 +144,10 @@ import {
flow_apply_detail
} from '@/api/flow/flow_apply'
import type { type_flow_apply } from '@/api/flow/flow_apply'
import { useDictData } from '@/hooks/useDictOptions'
import type { type_dict } from '@/hooks/useDictOptions'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'
import EditPopup from './edit.vue'
@@ -174,13 +178,13 @@ const queryParams = reactive({
status: ''
})
const { pager, getLists, resetPage, resetParams } = usePaging({
const { pager, getLists, resetPage, resetParams } = usePaging<type_flow_apply>({
fetchFun: flow_apply_lists,
params: queryParams
})
const { dictData } = useDictData<{
flow_apply_status: any[]
flow_group: any[]
flow_apply_status: type_dict[]
flow_group: type_dict[]
}>(['flow_apply_status', 'flow_group'])
const handleAdd = async () => {
@@ -198,7 +202,7 @@ const handleAdd = async () => {
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除?')
await flow_apply_delete({ id })
await flow_apply_delete(id)
feedback.msgSuccess('删除成功')
getLists()
}

View File

@@ -63,6 +63,8 @@ const props = defineProps({
default: true
}
})
const emit = defineEmits(['close'])
const dialogVisible = ref(false)
// const props = defineProps({
// save: {
@@ -105,6 +107,7 @@ function open(applyId) {
}
function BeforeClose() {
dialogVisible.value = false
emit('close')
}
function submit() {
flow_history_back(formData).then(() => {

View File

@@ -99,7 +99,8 @@ function onSubmit() {
defineExpose({
open,
disableWidgets,
hideWidgets
hideWidgets,
closeFn
})
</script>

View File

@@ -0,0 +1,151 @@
<template>
<el-dialog
v-model="dialogVisible"
:fullscreen="false"
:close-on-click-modal="false"
:close-on-press-escape="false"
:destroy-on-close="true"
:title="title"
top="1px"
>
<el-form
ref="formRef"
:model="formData"
label-position="top"
label-width="110px"
:rules="formRules"
>
<!-- {{ userTask }} -->
<el-form-item v-if="userTask" :label="`${userTask?.label}节点审批人`" prop="templateId">
<el-select
style="width: 100%"
v-if="approverUserList.length"
v-model="formData.applyUserId"
placeholder="请选择审批人"
>
<el-option
v-for="(item, index) in approverUserList"
:key="index"
:label="item.nickname"
:value="item.id"
clearable
/>
</el-select>
</el-form-item>
<el-form-item label="审批意见" prop="passRemark" v-if="props.showRemark">
<el-input
v-model="formData.passRemark"
:rows="2"
type="textarea"
placeholder="请输入审批意见"
/>
</el-form-item>
</el-form>
<!-- <el-steps direction="horizontal" :active="next_nodes.length">
<el-step :title="node.label" v-for="node of next_nodes" :key="node.id" />
</el-steps> -->
<template #footer>
<el-button @click="dialogVisible = false">关闭</el-button>
<el-button type="primary" @click="submit"> 通过 </el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, computed } from 'vue'
import feedback from '@/utils/feedback'
import {
flow_history_next_node,
flow_history_get_approver,
flow_history_pass
} from '@/api/flow/flow_history'
const props = defineProps({
title: {
type: String,
default: ''
},
showRemark: {
type: Boolean,
default: true
}
})
const dialogVisible = ref(false)
// const props = defineProps({
// save: {
// type: Function,
// default: () => {}
// }
// })
class formDataState {
id = ''
passRemark = ''
applyUserId = ''
}
const formData = reactive(new formDataState())
const next_nodes = ref([])
const userTask = computed(() => {
return next_nodes.value.find((item) => item.type == 'bpmn:userTask')
})
const approverUserList = ref([])
const formRules = {
applyUserId: [
{
required: true,
message: '请选择',
trigger: ['blur']
}
]
}
function open(applyId) {
console.log('open')
Object.assign(formData, new formDataState())
formData.id = applyId
dialogVisible.value = true
flow_history_next_node({
applyId: applyId
}).then((res) => {
console.log('res', res)
next_nodes.value = res
})
flow_history_get_approver({ applyId: applyId }).then((user) => {
console.log('user', user)
approverUserList.value = user
if (user && user.length == 1) {
formData.applyUserId = user[0].id
}
})
}
function BeforeClose() {
dialogVisible.value = false
// formData = {}
}
function submit() {
console.log('submit', next_nodes)
if (userTask.value && !formData.applyUserId) {
feedback.msgWarning('请选择审批人')
return
}
flow_history_pass({
applyId: formData.id,
nextNodeAdminId: formData.applyUserId || 0,
passRemark: formData.passRemark
}).then(() => {
BeforeClose()
})
}
defineExpose({
open
})
</script>
<style lang="scss">
// body {
// margin: 0; /* 如果页面出现垂直滚动条则加入此行CSS以消除之 */
// }
</style>

View File

@@ -64,15 +64,15 @@
</div>
</el-card>
<!-- <Approve ref="ApproveRef"></Approve> -->
<ViewForm ref="viewFormRef"></ViewForm>
<!-- <ApplySubmit ref="ApplySubmitRef" title="审批" @close="getLists"></ApplySubmit> -->
</div>
</template>
<script lang="ts" setup>
import { shallowRef, reactive } from 'vue'
import { flow_apply_detail } from '@/api/flow/flow_apply'
import { flow_history_list } from '@/api/flow/flow_history'
import type { type_flow_apply } from '@/api/flow/flow_apply'
import { useDictData } from '@/hooks/useDictOptions'
import { usePaging } from '@/hooks/usePaging'
import useUserStore from '@/stores/modules/user'
@@ -82,7 +82,7 @@ import ViewForm from './components/ViewForm.vue'
const userStore = useUserStore()
defineOptions({
name: 'todo'
name: 'done'
})
const ApproveRef = shallowRef<InstanceType<typeof ApproveRef>>()
const viewFormRef = shallowRef<InstanceType<typeof ViewForm>>()
@@ -95,7 +95,7 @@ const queryParams = reactive({
passStatus: 2
})
const { pager, getLists, resetPage, resetParams } = usePaging({
const { pager, getLists, resetPage, resetParams } = usePaging<type_flow_apply>({
fetchFun: flow_history_list,
params: queryParams
})

View File

@@ -63,19 +63,21 @@
<ViewForm ref="viewFormRef" :save="SaveViewForm" @back="OpenBack"></ViewForm>
<Back ref="backRef"></Back>
<Back ref="backRef" @close="closeBack"></Back>
<ApplySubmit ref="ApplySubmitRef" title="审批" @close="getLists"></ApplySubmit>
</div>
</template>
<script lang="ts" setup>
import { shallowRef, reactive, defineOptions } from 'vue'
import { flow_apply_detail } from '@/api/flow/flow_apply'
import { flow_history_list, flow_history_edit } from '@/api/flow/flow_history'
import type { type_flow_history } from '@/api/flow/flow_history'
import { useDictData } from '@/hooks/useDictOptions'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'
import useUserStore from '@/stores/modules/user'
import ApplySubmit from '@/views/flow/flow_apply/components/apply_submit.vue'
import ApplySubmit from './components/apply_submit.vue'
import ViewForm from './components/ViewForm.vue'
import Back from './components/Back.vue'
const userStore = useUserStore()
@@ -94,7 +96,7 @@ const queryParams = reactive({
passStatus: 1
})
const { pager, getLists, resetPage, resetParams } = usePaging({
const { pager, getLists, resetPage, resetParams } = usePaging<type_flow_history>({
fetchFun: flow_history_list,
params: queryParams
})
@@ -134,7 +136,7 @@ const SaveViewForm = (historyId, form_data) => {
feedback.msgSuccess('保存成功')
await getLists()
const row = pager.lists.find((item) => item.id === historyId)
const row = pager.lists.find((item: any) => item.id === historyId)
OpenApplySubmit(row)
resolve(true)
@@ -155,6 +157,11 @@ const OpenBack = async (row: any) => {
backRef.value?.open(row.applyId)
}
const closeBack = () => {
console.log('closeBack')
viewFormRef.value?.closeFn()
}
getLists()
</script>

View File

@@ -48,6 +48,7 @@ import {
} from '@/api/flow/flow_template'
import Popup from '@/components/popup/index.vue'
import feedback from '@/utils/feedback'
import { computed, ref, reactive, shallowRef } from 'vue'
import type { PropType } from 'vue'
defineProps({
dictData: {
@@ -134,9 +135,7 @@ const setFormData = async (data: Record<string, any>) => {
}
const getDetail = async (row: Record<string, any>) => {
const data = await flow_template_detail({
id: row.id
})
const data = await flow_template_detail(row.id)
setFormData(data)
}

Some files were not shown because too many files have changed in this diff Show More