拆分项目,移除无用应用
Frontend CI/CD / build (web-office) (push) Failing after 10s Details

This commit is contained in:
z9130 2024-10-24 10:28:41 +08:00
parent 26c496f3db
commit d16c0fdba3
482 changed files with 0 additions and 60296 deletions

View File

@ -1,5 +0,0 @@
# 应用标题
VITE_APP_TITLE=热力合同系统
# 应用命名空间用于缓存、store等功能的前缀确保隔离
VITE_APP_NAMESPACE=contract

View File

@ -1,7 +0,0 @@
# public path
VITE_BASE=/
# Basic interface address SPA
VITE_GLOB_API_URL=/api
VITE_VISUALIZER=true

View File

@ -1,16 +0,0 @@
# 端口号
VITE_PORT=5666
VITE_BASE=/
# 接口地址
VITE_GLOB_API_URL=/api
# 是否开启 Nitro Mock服务true 为开启false 为关闭
VITE_NITRO_MOCK=true
# 是否打开 devtoolstrue 为打开false 为关闭
VITE_DEVTOOLS=false
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true

View File

@ -1,19 +0,0 @@
VITE_BASE=/
# 接口地址
VITE_GLOB_API_URL=/api
# 是否开启压缩,可以设置为 none, brotli, gzip
VITE_COMPRESS=none
# 是否开启 PWA
VITE_PWA=false
# vue-router 的模式
VITE_ROUTER_HISTORY=history
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true
# 打包后是否生成dist.zip
VITE_ARCHIVER=true

View File

@ -1,134 +0,0 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useId: typeof import('vue')['useId']
const useModel: typeof import('vue')['useModel']
const useSlots: typeof import('vue')['useSlots']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
import('vue')
}
// for vue template auto import
import { UnwrapRef } from 'vue'
declare module 'vue' {
interface GlobalComponents {}
interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly computed: UnwrapRef<typeof import('vue')['computed']>
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
readonly h: UnwrapRef<typeof import('vue')['h']>
readonly inject: UnwrapRef<typeof import('vue')['inject']>
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']>
readonly provide: UnwrapRef<typeof import('vue')['provide']>
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
readonly ref: UnwrapRef<typeof import('vue')['ref']>
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
readonly unref: UnwrapRef<typeof import('vue')['unref']>
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
readonly useId: UnwrapRef<typeof import('vue')['useId']>
readonly useModel: UnwrapRef<typeof import('vue')['useModel']>
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
readonly watch: UnwrapRef<typeof import('vue')['watch']>
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
}
}

View File

@ -1,63 +0,0 @@
const createEntry = (description = '', data: any = []) => ({
description,
data,
});
const staticDicts = {
cancel_reson: createEntry('变更原因', [
{ label: '未填写原因', value: '0' },
{ label: '用户取消', value: '1' },
{ label: '系统取消', value: '2' },
{ label: '其他原因', value: '3' },
]),
};
export default {
// 配置路径,如果存在,则使用配置路径下的文件
configPath: '',
// 接口配置,仅用于生成 api 接口文件
apis: {
enable: true,
generator: [
{
input: '',
templatePath: 'src/api/template',
output: 'src/api/index.ts',
needTs: true,
outputTs: 'src/api/globals.d.ts',
handleApi: (apiDescriptor) => {
// 返回falsy值表示过滤此api
if (!apiDescriptor.path.startWith('/user')) {
return;
}
apiDescriptor.parameter = apiDescriptor.parameter.filter(
(param) => param.in === 'header' && param.name === 'token',
);
delete apiDescriptor.requestBody.id;
apiDescriptor.url = apiDescriptor.url.replace('/user', '');
return apiDescriptor;
},
},
],
},
// 字典配置,仅用于生成字典枚举文件
dicts: {
enable: true,
generator: [
{
input: '',
templatePath: 'src/api/template',
output: 'src/utils/dict/shared.ts',
handleDict: async (dictDescriptor) => {
// await dictDescriptor.request();
// 请求数据类型表为了生成对应注释
// 返回falsy值表示过滤此api
staticDicts[dictDescriptor.name] = dictDescriptor;
return dictDescriptor;
},
},
],
},
};

View File

@ -1,39 +0,0 @@
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<meta name="description" content="Erp Management System" />
<meta name="keywords" content="erp" />
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
/>
<!-- 由 vite 注入 VITE_APP_TITLE 变量,在 .env 文件内配置 -->
<title><%= VITE_APP_TITLE %></title>
<link rel="icon" href="/favicon.ico" />
<script></script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<script type="text/javascript">
(function () {
var ua = navigator.userAgent.toLocaleLowerCase();
var browserType = '',
browserVersion = '';
if (ua.match(/msie/) != null || ua.match(/trident/) != null) {
browserType = 'IE';
browserVersion =
ua.match(/msie ([\d.]+)/) != null
? ua.match(/msie ([\d.]+)/)[1]
: ua.match(/rv:([\d.]+)/)[1];
if (1 * browserVersion < 12) {
alert('请在ie11版本浏览器上使用系统');
}
}
})();
</script>
</body>
</html>

View File

@ -1,66 +0,0 @@
{
"name": "web-contract",
"version": "1.0.0",
"type": "module",
"scripts": {
"build": "pnpm vite build --mode production",
"build:dev": "pnpm vite build --mode development",
"build:analyze": "pnpm vite build --mode analyze",
"dev": "pnpm vite --mode development",
"dev:prod": "pnpm vite --mode production",
"preview": "vite preview --port 4174",
"typecheck": "vue-tsc --noEmit --skipLibCheck"
},
"imports": {
"#/*": "./src/*"
},
"dependencies": {
"@fast-crud/fast-crud": "^1.21.2",
"@fast-crud/fast-extends": "^1.21.2",
"@fast-crud/ui-antdv4": "^1.21.2",
"@fast-crud/ui-interface": "^1.21.2",
"@vben-core/shadcn-ui": "workspace:*",
"@vben/access": "workspace:*",
"@vben/common-ui": "workspace:*",
"@vben/constants": "workspace:*",
"@vben/hooks": "workspace:*",
"@vben/icons": "workspace:*",
"@vben/layouts": "workspace:*",
"@vben/locales": "workspace:*",
"@vben/plugins": "workspace:*",
"@vben/preferences": "workspace:*",
"@vben/request": "workspace:*",
"@vben/stores": "workspace:*",
"@vben/styles": "workspace:*",
"@vben/types": "workspace:*",
"@vben/utils": "workspace:*",
"@vueuse/core": "^11.0.3",
"alova": "^3.0.14",
"ant-design-vue": "^4.2.3",
"big.js": "^6.2.1",
"common-utils": "workspace:*",
"dayjs": "^1.11.13",
"exceljs": "^4.4.0",
"lodash-es": "^4.17.21",
"pinia": "2.2.2",
"pinia-plugin-persistedstate": "^3.2.1",
"sortablejs": "^1.15.2",
"tyme4ts": "^1.1.2",
"vue": "^3.4.38",
"vue-router": "^4.4.3",
"vxe-pc-ui": "^4.1.12",
"vxe-table": "^4.7.74",
"vxe-table-plugin-antd": "^4.0.8",
"vxe-table-plugin-export-xlsx": "^4.0.2",
"xe-utils": "^3.5.30"
},
"devDependencies": {
"@types/big.js": "^6.2.2",
"@types/lodash-es": "^4.17.12",
"sass": "^1.77.8",
"typescript": "^5.5.4",
"unplugin-auto-import": "^0.18.2",
"unplugin-vue-components": "^0.27.4",
"vite-plugin-lazy-import": "^1.0.7"
}
}

View File

@ -1 +0,0 @@
export { default } from '@vben/tailwind-config/postcss';

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

View File

@ -1,3 +0,0 @@
pnpm i @fast-crud/fast-crud
pnpm i @fast-crud/fast-extends
pnpm i @fast-crud/ui-interface

View File

@ -1,28 +0,0 @@
export interface QueryOptions {
params?: AnyObject;
pathParams?: AnyObject;
config?: AnyObject;
}
export interface BodyOptions {
params?: AnyObject;
data?: AnyObject;
pathParams?: AnyObject;
config?: AnyObject;
}
export interface RequestOptions {
url: string;
data?: QueryOptions;
}
export interface MutationOptions {
url: string;
data?: BodyOptions;
}
declare interface PageVo {
rows: number;
data: any;
message: string;
}

View File

@ -1,958 +0,0 @@
import type { BodyOptions, QueryOptions } from './global.d';
import { http } from './request/index';
export default {
meeting: {
/** 协同办公/会议管理 分页查询 */
get_page: (data?: QueryOptions) => http.get('/app/meeting/page', data),
/** 协同办公/会议管理 删除会议 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/meeting/deletes', data),
/** 协同办公/会议管理 会议保存 */
post_save: (data?: BodyOptions) => http.post('/app/meeting/save', data),
/** 协同办公/会议管理 查看会议台账 */
get_list: (data?: QueryOptions) => http.get('/app/meeting/list', data),
list: {
/** 协同办公/会议管理 会议台账导出 */
get_export: (data?: QueryOptions) =>
http.get('/app/meeting/list/export', data),
},
/** 协同办公/会议管理 门户获取会议数据 */
get_getFundingSource: (data?: QueryOptions) =>
http.get('/app/meeting/getFundingSource', data),
},
tysq: {
zzjg: {
yhjbda: {
YhjbdaController: {
/** 统一授权 未命名接口 */
get_yhjbdaGrid: (data?: QueryOptions) =>
http.get('/app/tysq/zzjg/yhjbda/YhjbdaController/yhjbdaGrid', data),
},
},
},
},
dictType: {
/** 协同办公/字典表 字典类型查询 */
get_list: (data?: QueryOptions) => http.get('/app/dictType/list', data),
/** 协同办公/字典表 字典类型保存 */
post_save: (data?: BodyOptions) => http.post('/app/dictType/save', data),
/** 协同办公/字典表 字典类型删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/dictType/deletes', data),
},
uaa: {
/** 用户中心 用户登陆 */
post_validateAccount: (data?: BodyOptions) =>
http.post('/uc/uaa/validateAccount', data),
},
api: {
core: {
orgemplbc: {
employee: {
/** 用户中心 获取用户信息(分页) */
post_paging: (data?: BodyOptions) =>
http.post('/uc/api/core/orgemplbc/employee/paging', data),
},
organization: {
RL: {
/** 用户中心 根据组织机构id获取员工信息 */
get_employee: (data?: QueryOptions) =>
http.get('/uc/api/core/orgemplbc/organization/RL/employee', data),
},
/** 用户中心 获取组织结构信息 */
post_paging: (data?: BodyOptions) =>
http.post('/uc/api/core/orgemplbc/organization/paging', data),
},
/** 用户中心 根据组织机构id和用户信息查询 */
post_employee: (data?: BodyOptions) =>
http.post('/uc/api/core/orgemplbc/employee', data),
},
},
},
sys: {
user: {
/** 用户中心 根据token获取用户信息 */
post_checkToken: (data?: BodyOptions) =>
http.post('/uc/sys/user/checkToken', data),
functiontree: {
/** 用户中心 获取菜单接口 */
get_XTBGXT: (data?: QueryOptions) =>
http.get('/uc/sys/user/functiontree/HTGL', data),
/** 统一授权 未命名接口 */
get_PLRL: (data?: QueryOptions) =>
http.get('/uc/sys/user/functiontree/PLRL', data),
},
},
},
zbgl: {
/** 协同办公/值班管理 值班查询 */
get_queryZbInfo: (data?: QueryOptions) =>
http.get('/app/zbgl/queryZbInfo', data),
/** 协同办公/值班管理 保存值班信息 */
post_save: (data?: BodyOptions) => http.post('/app/zbgl/save', data),
/** 协同办公/值班管理 删除值班信息 */
get_deletes: (data?: QueryOptions) => http.get('/app/zbgl/deletes', data),
/** 协同办公/值班管理 导入值班人员信息 */
post_importZbry: (data?: BodyOptions) =>
http.post('/app/zbgl/importZbry', data),
/** 协同办公/值班管理 门户值班信息查询 */
get_getDutyInfo: (data?: QueryOptions) =>
http.get('/app/zbgl/getDutyInfo', data),
/** 协同办公/值班管理 导出 */
post_export: (data?: BodyOptions) => http.post('/app/zbgl/export', data),
},
dictData: {
/** 协同办公/字典表 字典数据保存 */
post_save: (data?: BodyOptions) => http.post('/app/dictData/save', data),
/** 合同系统/项目管理 保存 */
get_save: (data?: QueryOptions) => http.get('/app/dictData/save', data),
/** 合同系统/项目名称管理 查询 */
get_page: (data?: QueryOptions) => http.get('/app/dictData/page', data),
/** 协同办公/字典表 字典数据删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/dictData/deletes', data),
/** 合同系统/项目管理 删除 */
get_deletes: (data?: QueryOptions) =>
http.get('/app/dictData/deletes', data),
},
user: {
/** 统一授权 获取用户列表 */
get_page: (data?: QueryOptions) => http.get('/app/user/page', data),
},
dish: {
/** 协同办公/订餐管理/菜谱管理 菜谱查询 */
get_page: (data?: QueryOptions) => http.get('/app/dish/page', data),
/** 协同办公/订餐管理/菜谱管理 菜谱保存 */
post_save: (data?: BodyOptions) => http.post('/app/dish/save', data),
/** 协同办公/订餐管理/食谱管理 菜谱删除 */
post_deletes: (data?: BodyOptions) => http.post('/app/dish/deletes', data),
},
recipe: {
/** 协同办公/订餐管理/食谱管理 食谱查询 */
get_page: (data?: QueryOptions) => http.get('/app/recipe/page', data),
/** 协同办公/订餐管理/食谱管理 食谱保存 */
post_save: (data?: BodyOptions) => http.post('/app/recipe/save', data),
/** 协同办公/订餐管理/食谱管理 食谱导出 */
get_export: (data?: QueryOptions) => http.get('/app/recipe/export', data),
/** 协同办公/订餐管理/食谱管理 批量保存 */
post_saveBatch: (data?: BodyOptions) =>
http.post('/app/recipe/saveBatch', data),
/** 协同办公/订餐管理/食谱管理 食谱编辑 */
post_edit: (data?: BodyOptions) => http.post('/app/recipe/edit', data),
},
ccsq: {
/** 协同办公/出差申请 出差申请查询 */
get_page: (data?: QueryOptions) => http.get('/app/ccsq/page', data),
/** 协同办公/出差申请 申请单保存 */
post_save: (data?: BodyOptions) => http.post('/app/ccsq/save', data),
/** 协同办公/出差申请 申请单删除 */
post_deletes: (data?: BodyOptions) => http.post('/app/ccsq/deletes', data),
/** 协同办公/出差申请 退回 */
post_rollback: (data?: BodyOptions) =>
http.post('/app/ccsq/rollback', data),
/** 协同办公/出差申请 启动流程 */
post_startWorkFlow: (data?: BodyOptions) =>
http.post('/app/ccsq/startWorkFlow', data),
/** 协同办公/出差申请 审核 */
post_submit: (data?: BodyOptions) => http.post('/app/ccsq/submit', data),
/** 协同办公/出差申请 待办 */
get_toDoPage: (data?: QueryOptions) => http.get('/app/ccsq/toDoPage', data),
/** 协同办公/出差申请 已办 */
get_donePage: (data?: QueryOptions) => http.get('/app/ccsq/donePage', data),
/** 协同办公/出差申请 获取可退回节点信息 */
get_getBackNode: (data?: QueryOptions) =>
http.get('/app/ccsq/getBackNode', data),
/** 协同办公/出差申请 查询流程节点 */
get_getFlowNodeUserConfig: (data?: QueryOptions) =>
http.get('/app/ccsq/getFlowNodeUserConfig', data),
/** 协同办公/出差申请 下一审核节点 */
post_getNextNodeUserConfig: (data?: BodyOptions) =>
http.post('/app/ccsq/getNextNodeUserConfig', data),
/** 协同办公/出差申请 查看出差信息 */
get_getBusinessTripInfo: (data?: QueryOptions) =>
http.get('/app/ccsq/getBusinessTripInfo', data),
/** 协同办公/出差申请 查看审核过程 */
get_history: (data?: QueryOptions) => http.get('/app/ccsq/history', data),
},
orderfood: {
/** 协同办公/订餐管理/订餐 订餐加载接口 */
get_getOne: (data?: QueryOptions) =>
http.get('/app/orderfood/getOne', data),
/** 协同办公/订餐管理/订餐 订餐保存 */
post_save: (data?: BodyOptions) => http.post('/app/orderfood/save', data),
/** 协同办公/订餐管理/订餐 取消订餐 */
post_cancel: (data?: BodyOptions) =>
http.post('/app/orderfood/cancel', data),
/** 协同办公/订餐管理/订餐 协助取消他人订餐 */
post_assistCancel: (data?: BodyOptions) =>
http.post('/app/orderfood/assistCancel', data),
},
orderfoods: {
/** 协同办公/订餐管理/汇总 单位订餐汇总 */
get_departmentSummary: (data?: QueryOptions) =>
http.get('/app/orderfoods/departmentSummary', data),
/** 协同办公/订餐管理/汇总 订餐汇总 */
get_infoList: (data?: QueryOptions) =>
http.get('/app/orderfoods/infoList', data),
/** 协同办公/订餐管理/汇总 个人结算汇总 */
get_personalSummary: (data?: QueryOptions) =>
http.get('/app/orderfoods/personalSummary', data),
infoList: {
/** 协同办公/订餐管理/汇总 订餐汇总导出 */
get_export: (data?: QueryOptions) =>
http.get('/app/orderfoods/infoList/export', data),
},
personalSummary: {
/** 协同办公/订餐管理/汇总 个人结算汇总导出 */
get_export: (data?: QueryOptions) =>
http.get('/app/orderfoods/personalSummary/export', data),
},
departmentSummary: {
/** 协同办公/订餐管理/汇总 单位订餐汇总导出 */
get_export: (data?: QueryOptions) =>
http.get('/app/orderfoods/departmentSummary/export', data),
},
/** 协同办公/订餐管理/汇总 结算单 */
get_finalStatement: (data?: QueryOptions) =>
http.get('/app/orderfoods/finalStatement', data),
finalStatement: {
/** 协同办公/订餐管理/汇总 结算表导出 */
get_export: (data?: QueryOptions) =>
http.get('/app/orderfoods/finalStatement/export', data),
},
/** 协同办公/订餐管理/汇总 结算操作 */
post_balance: (data?: BodyOptions) =>
http.post('/app/orderfoods/balance', data),
},
officeSuppliesApply: {
/** 协同办公/办公用品/办公用品申请 申请页面查询 */
get_page: (data?: QueryOptions) =>
http.get('/app/officeSuppliesApply/page', data),
/** 协同办公/办公用品/办公用品申请 申请保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/officeSuppliesApply/save', data),
/** 协同办公/办公用品/办公用品申请 批量审核 */
post_audit: (data?: BodyOptions) =>
http.post('/app/officeSuppliesApply/audit', data),
/** 协同办公/办公用品/办公用品申请 批量申请 */
post_saveBatch: (data?: BodyOptions) =>
http.post('/app/officeSuppliesApply/saveBatch', data),
/** 协同办公/办公用品/办公用品申请 撤销申请 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/officeSuppliesApply/deletes', data),
},
warehousing: {
/** 协同办公/办公用品/入库/出库 入库查询 */
get_page: (data?: QueryOptions) => http.get('/app/warehousing/page', data),
},
inOrOut: {
/** 协同办公/办公用品/入库/出库 入库/保存 */
post_saveBatch: (data?: BodyOptions) =>
http.post('/app/inOrOut/saveBatch', data),
},
supervise: {
/** 协同办公/督查督办/立项发起 立项分页查询 */
get_page: (data?: QueryOptions) => http.get('/app/supervise/page', data),
/** 协同办公/督查督办/立项发起 立项保存 */
post_save: (data?: BodyOptions) => http.post('/app/supervise/save', data),
/** 协同办公/督查督办/立项发起 立项删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/supervise/deletes', data),
/** 协同办公/督查督办/立项发起 立项提交 */
post_audit: (data?: BodyOptions) => http.post('/app/supervise/audit', data),
/** 协同办公/督查督办/执行反馈 执行反馈提交 */
post_auditFankui: (data?: BodyOptions) =>
http.post('/app/supervise/auditFankui', data),
/** 协同办公/督查督办/报表汇总 统计 */
get_huizong: (data?: QueryOptions) =>
http.get('/app/supervise/huizong', data),
/** 协同办公/督查督办/立项发起 更新状态 */
post_updateStatus: (data?: BodyOptions) =>
http.post('/app/supervise/updateStatus', data),
},
feedback: {
/** 协同办公/督查督办/执行反馈 执行反馈待办查询 */
get_page: (data?: QueryOptions) => http.get('/app/feedback/page', data),
/** 协同办公/督查督办/执行反馈 执行反馈保存,实际修改操作,保存反馈时间,反馈内容,进度 */
post_saveUpdate: (data?: BodyOptions) =>
http.post('/app/feedback/saveUpdate', data),
/** 协同办公/督查督办/执行反馈 查询负责部门列表,返回所有的反馈信息 */
get_getDepartment: (data?: QueryOptions) =>
http.get('/app/feedback/getDepartment', data),
/** 协同办公/督查督办/执行反馈 分发立项任务 */
post_save: (data?: BodyOptions) => http.post('/app/feedback/save', data),
/** 协同办公/督查督办/执行反馈 执行反馈已办查询 */
get_pageDone: (data?: QueryOptions) =>
http.get('/app/feedback/pageDone', data),
/** 协同办公/督查督办/立项发起 查询立项对应的反馈 */
get_queryFeedback: (data?: QueryOptions) =>
http.get('/app/feedback/queryFeedback', data),
},
file: {
/** 协同办公/文件上传/下载 多文件上传 */
post_uploads: (data?: BodyOptions) => http.post('/app/file/uploads', data),
},
addressor: {
/** 协同办公/会议管理/发言人 发言人查询 */
get_list: (data?: QueryOptions) => http.get('/app/addressor/list', data),
/** 协同办公/会议管理/发言人 发言人批量保存 */
post_saveBatch: (data?: BodyOptions) =>
http.post('/app/addressor/saveBatch', data),
/** 协同办公/会议管理/发言人 发言人保存 */
post_save: (data?: BodyOptions) => http.post('/app/addressor/save', data),
/** 协同办公/会议管理/发言人 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/addressor/deletes', data),
},
officeSuppliesList: {
/** 协同办公/办公用品/办公用品清单 分页查询 */
get_page: (data?: QueryOptions) =>
http.get('/app/officeSuppliesList/page', data),
/** 协同办公/办公用品/办公用品清单 批量保存 */
post_saveBatch: (data?: BodyOptions) =>
http.post('/app/officeSuppliesList/saveBatch', data),
/** 协同办公/办公用品/办公用品清单 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/officeSuppliesList/deletes', data),
},
officeSuppliesApplySum: {
/** 协同办公/办公用品 采购汇总 */
get_list: (data?: QueryOptions) =>
http.get('/app/officeSuppliesApplySum/list', data),
/** 协同办公/办公用品 结算清单 */
get_finalStatement: (data?: QueryOptions) =>
http.get('/app/officeSuppliesApplySum/finalStatement', data),
/** 协同办公/办公用品 单位结算清单 */
get_unitFinalStatement: (data?: QueryOptions) =>
http.get('/app/officeSuppliesApplySum/unitFinalStatement', data),
finalStatement: {
/** 协同办公/办公用品 结算清单导出 */
get_export: (data?: QueryOptions) =>
http.get('/app/officeSuppliesApplySum/finalStatement/export', data),
},
/** 协同办公/办公用品 结算清单结算操作 */
post_balance: (data?: BodyOptions) =>
http.post('/app/officeSuppliesApplySum/balance', data),
},
autoOrderfoodPeoples: {
/** 协同办公/订餐管理/自动订餐人员管理 分页查询 */
get_page: (data?: QueryOptions) =>
http.get('/app/autoOrderfoodPeoples/page', data),
/** 协同办公/订餐管理/自动订餐人员管理 批量保存 */
post_saveBatch: (data?: BodyOptions) =>
http.post('/app/autoOrderfoodPeoples/saveBatch', data),
/** 协同办公/订餐管理/自动订餐人员管理 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/autoOrderfoodPeoples/deletes', data),
},
usercenter: {
/** 协同办公 获取菜单 */
get_menus: (data?: QueryOptions) => http.get('/app/usercenter/menus', data),
},
workflow: {
/** 协同办公/工作流 待办 */
post_queryMyTodoTask: (data?: BodyOptions) =>
http.post('/app/workflow/queryMyTodoTask', data),
/** 协同办公/工作流 已办 */
post_getHistoricTaskByUserID: (data?: BodyOptions) =>
http.post('/app/workflow/getHistoricTaskByUserID', data),
},
personTask: {
/** 合同系统/签订 待办查询 */
get_page: (data?: QueryOptions) => http.get('/app/personTask/page', data),
/** 合同系统/签订 已办查询 */
get_pagePersonTaskOver: (data?: QueryOptions) =>
http.get('/app/personTask/pagePersonTaskOver', data),
/** 合同系统/履行/履行查询 分页合同履行审批查询 */
get_pagePerformanceAudit: (data?: QueryOptions) =>
http.get('/app/personTask/pagePerformanceAudit', data),
/** 合同系统/履行/履行提示/申请归档 归档保存 */
post_applicationFiling: (data?: BodyOptions) =>
http.post('/app/personTask/applicationFiling', data),
},
sbCtrBasePt: {
/** 合同系统/申报 合同申报数据查询 */
get_QuerySbCtrBase: (data?: QueryOptions) =>
http.get('/app/sbCtrBasePt/QuerySbCtrBase', data),
/** 合同系统/申报 合同申报基本信息加载 */
post_page: (data?: BodyOptions) => http.post('/app/sbCtrBasePt/page', data),
/** 合同系统/申报 合同申报基本信息保存 */
post_save: (data?: BodyOptions) => http.post('/app/sbCtrBasePt/save', data),
/** 合同系统/申报 合同申报基本信息删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/sbCtrBasePt/deletes', data),
/** 合同系统/申报 获取资金渠道 */
get_getFundingSource: (data?: QueryOptions) =>
http.get('/app/sbCtrBasePt/getFundingSource', data),
/** 合同系统/申报 提交 */
post_submit: (data?: BodyOptions) =>
http.post('/app/sbCtrBasePt/submit', data),
/** 合同系统/申报 退回 */
post_rollback: (data?: BodyOptions) =>
http.post('/app/sbCtrBasePt/rollback', data),
/** 合同系统/申报 发起废除 */
post_repeal: (data?: BodyOptions) =>
http.post('/app/sbCtrBasePt/repeal', data),
/** 合同系统/申报 发起流程 */
post_start: (data?: BodyOptions) =>
http.post('/app/sbCtrBasePt/start', data),
},
contractBaseInfo: {
/** 合同系统/立项 合同立项保存 */
post_apply: (data?: BodyOptions) =>
http.post('/app/contractBaseInfo/apply', data),
/** 合同系统/立项 合同立项查询 */
get_page: (data?: QueryOptions) =>
http.get('/app/contractBaseInfo/page', data),
/** 合同系统/立项 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/contractBaseInfo/deletes', data),
/** 合同系统/立项 单条查询 */
get_getOne: (data?: QueryOptions) =>
http.get('/app/contractBaseInfo/getOne', data),
/** 合同系统/立项 提交 */
post_submit: (data?: BodyOptions) =>
http.post('/app/contractBaseInfo/submit', data),
/** 合同系统/立项废除 退回 */
post_rollback: (data?: BodyOptions) =>
http.post('/app/contractBaseInfo/rollback', data),
/** 合同系统/立项废除 提交 */
post_abolishSubmit: (data?: BodyOptions) =>
http.post('/app/contractBaseInfo/abolishSubmit', data),
/** 合同系统/立项 流程启动(非待办提交) */
post_applyFlowStart: (data?: BodyOptions) =>
http.post('/app/contractBaseInfo/applyFlowStart', data),
/** 合同系统/立项废除 流程启动(非待办提交) */
post_abolishFlowStart: (data?: BodyOptions) =>
http.post('/app/contractBaseInfo/abolishFlowStart', data),
},
proProviderInfo: {
/** 合同系统/相对人管理 合同相对人查询 */
get_Query: (data?: QueryOptions) =>
http.get('/app/proProviderInfo/Query', data),
/** 合同系统/相对人管理 获取币种 */
get_getBz: (data?: QueryOptions) =>
http.get('/app/proProviderInfo/getBz', data),
/** 合同系统/相对人管理 保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/proProviderInfo/save', data),
/** 合同系统/相对人管理 删除 */
get_deletes: (data?: QueryOptions) =>
http.get('/app/proProviderInfo/deletes', data),
/** 合同系统/相对人管理 加载 */
post_page: (data?: BodyOptions) =>
http.post('/app/proProviderInfo/page', data),
},
contractModelInfo: {
/** 合同系统/模板管理 保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/contractModelInfo/save', data),
/** 合同系统/模板管理 删除 */
get_deletes: (data?: QueryOptions) =>
http.get('/app/contractModelInfo/deletes', data),
/** 合同系统/模板管理 加载 */
post_page: (data?: BodyOptions) =>
http.post('/app/contractModelInfo/page', data),
},
contractReferType: {
/** 合同系统/合同类型参照 查询 */
get_list: (data?: QueryOptions) =>
http.get('/app/contractReferType/list', data),
/** 合同系统/合同类型参照 保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/contractReferType/save', data),
/** 合同系统/合同类型参照 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/contractReferType/deletes', data),
},
attachment: {
/** 文件上传/下载(新) 附件加载 */
get_list: (data?: QueryOptions) => http.get('/app/attachment/list', data),
/** 文件上传/下载(新) 文件下载 */
get_download: (data?: QueryOptions) =>
http.get('/app/attachment/download/{fileUuid}', data),
/** 文件上传/下载(新) 多文件上传 */
post_uploads: (data?: BodyOptions) =>
http.post('/app/attachment/uploads', data),
},
contractPayment: {
/** 合同系统/履行/履行提示/合同付款 获取合同付款信息 */
get_queryPaymentInfo: (data?: QueryOptions) =>
http.get('/app/contractPayment/queryPaymentInfo', data),
/** 合同系统/归档/合同归档 历史记录 */
get_historyPaymentInfo: (data?: QueryOptions) =>
http.get('/app/contractPayment/historyPaymentInfo', data),
/** 合同系统/履行/履行提示/合同付款 保存付款申请 */
post_save: (data?: BodyOptions) =>
http.post('/app/contractPayment/save', data),
/** 合同系统/履行/履行提示/合同付款 查询流程未配置人员节点 */
get_getFlowNodeUserConfig: (data?: QueryOptions) =>
http.get('/app/contractPayment/getFlowNodeUserConfig', data),
/** 合同系统/履行/履行提示/合同付款 送审 */
post_startWorkFlow: (data?: BodyOptions) =>
http.post('/app/contractPayment/startWorkFlow', data),
/** 合同系统/履行/履行提示/合同付款 审核通过 */
post_submit: (data?: BodyOptions) =>
http.post('/app/contractPayment/submit', data),
/** 合同系统/履行/履行提示/合同付款 退回 */
post_rollback: (data?: BodyOptions) =>
http.post('/app/contractPayment/rollback', data),
/** 合同系统/履行/履行提示/合同付款 待审核 */
get_toDoPage: (data?: QueryOptions) =>
http.get('/app/contractPayment/toDoPage', data),
/** 合同系统/履行/履行提示/合同付款 已审核 */
get_donePage: (data?: QueryOptions) =>
http.get('/app/contractPayment/donePage', data),
},
selectMerchantsBasicInfo: {
/** 合同系统/选商 分页查询 */
get_page: (data?: QueryOptions) =>
http.get('/app/selectMerchantsBasicInfo/page', data),
/** 合同系统/选商 选商信息查询(单条) */
get_getOne: (data?: QueryOptions) =>
http.get('/app/selectMerchantsBasicInfo/getOne', data),
/** 合同系统/选商 选商信息保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/selectMerchantsBasicInfo/save', data),
/** 合同系统/选商 合同选商保存操作(多个对象) */
post_saveMultiEntity: (data?: BodyOptions) =>
http.post('/app/selectMerchantsBasicInfo/saveMultiEntity', data),
/** 合同系统/选商 提交 */
post_submit: (data?: BodyOptions) =>
http.post('/app/selectMerchantsBasicInfo/submit', data),
/** 合同系统/选商 退回 */
post_rollback: (data?: BodyOptions) =>
http.post('/app/selectMerchantsBasicInfo/rollback', data),
/** 合同系统/选商废除 选商废除(弃用) */
post_abolish: (data?: BodyOptions) =>
http.post('/app/selectMerchantsBasicInfo/abolish', data),
/** 合同系统/选商废除 选商废除(开始节点提交,非待办提交) */
post_abolishFlowStart: (data?: BodyOptions) =>
http.post('/app/selectMerchantsBasicInfo/abolishFlowStart', data),
/** 合同系统/选商废除 提交 */
post_abolishSubmit: (data?: BodyOptions) =>
http.post('/app/selectMerchantsBasicInfo/abolishSubmit', data),
/** 合同系统/选商废除 退回 */
post_abolishRollback: (data?: BodyOptions) =>
http.post('/app/selectMerchantsBasicInfo/abolishRollback', data),
/** 合同系统/选商 流程启动(非待办提交) */
post_flowStart: (data?: BodyOptions) =>
http.post('/app/selectMerchantsBasicInfo/flowStart', data),
},
lvxChange: {
/** 合同系统/履行/履行提示/合同变更 保存合同变更申请 */
post_save: (data?: BodyOptions) => http.post('/app/lvxChange/save', data),
/** 合同系统/履行/履行提示/合同变更 获取合同变更信息 */
get_getContractChangeInfo: (data?: QueryOptions) =>
http.get('/app/lvxChange/getContractChangeInfo', data),
/** 合同系统/履行/履行提示/合同变更 查询流程未配置人员节点 */
get_getFlowNodeUserConfig: (data?: QueryOptions) =>
http.get('/app/lvxChange/getFlowNodeUserConfig', data),
/** 合同系统/履行/履行提示/合同变更 流程启动 */
post_startWorkFlow: (data?: BodyOptions) =>
http.post('/app/lvxChange/startWorkFlow', data),
/** 合同系统/履行/履行提示/合同变更 审核通过 */
post_submit: (data?: BodyOptions) =>
http.post('/app/lvxChange/submit', data),
},
contractRelieve: {
/** 合同系统/履行/履行提示/合同解除 获取合同解除信息 */
get_getContractRelieveInfo: (data?: QueryOptions) =>
http.get('/app/contractRelieve/getContractRelieveInfo', data),
/** 合同系统/履行/履行提示/合同解除 保存合同解除信息 */
post_save: (data?: BodyOptions) =>
http.post('/app/contractRelieve/save', data),
},
contractBreach: {
/** 合同系统/履行/履行提示/合同违约情况 保存合同违约信息 */
post_save: (data?: BodyOptions) =>
http.post('/app/contractBreach/save', data),
/** 合同系统/履行/履行提示/合同违约情况 获取合同违约信息 */
get_getContractBreachInfo: (data?: QueryOptions) =>
http.get('/app/contractBreach/getContractBreachInfo', data),
/** 合同系统/履行/履行提示/合同违约情况 查询流程未配置人员节点 */
get_getFlowNodeUserConfig: (data?: QueryOptions) =>
http.get('/app/contractBreach/getFlowNodeUserConfig', data),
/** 合同系统/履行/履行提示/合同违约情况 启动流程 */
post_startWorkFlow: (data?: BodyOptions) =>
http.post('/app/contractBreach/startWorkFlow', data),
/** 合同系统/履行/履行提示/合同违约情况 审核 */
post_submit: (data?: BodyOptions) =>
http.post('/app/contractBreach/submit', data),
/** 合同系统/履行/履行提示/合同违约情况 退回 */
post_rollback: (data?: BodyOptions) =>
http.post('/app/contractBreach/rollback', data),
},
lvxResult: {
/** 合同系统/履行/履行结果 履行结果保存 */
post_save: (data?: BodyOptions) => http.post('/app/lvxResult/save', data),
/** 合同系统/履行/履行结果 分页履行结果查询 */
get_page: (data?: QueryOptions) => http.get('/app/lvxResult/page', data),
/** 合同系统/履行/履行结果 已办 */
get_pageDone: (data?: QueryOptions) =>
http.get('/app/lvxResult/pageDone', data),
},
contractFiling: {
/** 合同系统/履行/履行提示/临时归档 保存临时归档信息 */
post_save: (data?: BodyOptions) =>
http.post('/app/contractFiling/save', data),
/** 合同系统/履行/履行提示/临时归档 分页查询 */
get_pageFillingList: (data?: QueryOptions) =>
http.get('/app/contractFiling/pageFillingList', data),
/** 合同系统/履行/履行提示/临时归档 回档 */
post_update: (data?: BodyOptions) =>
http.post('/app/contractFiling/update', data),
/** 合同系统/履行/履行提示/临时归档 获取临时归档信息 */
get_getLsgd: (data?: QueryOptions) =>
http.get('/app/contractFiling/getLsgd', data),
},
biddingExpert: {
/** 合同系统/选商/选商招标专家 招标专家查询 */
get_list: (data?: QueryOptions) =>
http.get('/app/biddingExpert/list', data),
/** 合同系统/选商/选商招标专家 选商招标专家保存 */
post_saveBatch: (data?: BodyOptions) =>
http.post('/app/biddingExpert/saveBatch', data),
/** 合同系统/选商/选商招标专家 选商招标专家删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/biddingExpert/deletes', data),
},
contractFilingFormal: {
/** 合同系统/归档/合同归档 分页查询归档信息 */
get_queryContractFiling: (data?: QueryOptions) =>
http.get('/app/contractFilingFormal/queryContractFiling', data),
/** 合同系统/归档/合同归档 获取合同招标选商申请信息 */
get_getContractSupplier: (data?: QueryOptions) =>
http.get('/app/contractFilingFormal/getContractSupplier', data),
/** 合同系统/归档/合同归档 保存合同归档 */
post_save: (data?: BodyOptions) =>
http.post('/app/contractFilingFormal/save', data),
/** 合同系统/归档/合同回档 分页查询-已归档 */
get_pageArchivedContract: (data?: QueryOptions) =>
http.get('/app/contractFilingFormal/pageArchivedContract', data),
/** 合同系统/归档/合同回档 回档 */
post_saveFilingBack: (data?: BodyOptions) =>
http.post('/app/contractFilingFormal/saveFilingBack', data),
},
lvxProduct: {
/** 合同系统/履行/履行提示/产品或服务 获取合同产品信息 */
get_getContractProductInfo: (data?: QueryOptions) =>
http.get('/app/lvxProduct/getContractProductInfo', data),
/** 合同系统/履行/履行提示/产品或服务 累计收款金额 */
get_getSumFromProduct: (data?: QueryOptions) =>
http.get('/app/lvxProduct/getSumFromProduct', data),
/** 合同系统/履行/履行提示/产品或服务 历史记录 */
get_getListFromHistoryRecord: (data?: QueryOptions) =>
http.get('/app/lvxProduct/getListFromHistoryRecord', data),
/** 合同系统/履行/履行提示/产品或服务 保存合同产品服务 */
post_save: (data?: BodyOptions) => http.post('/app/lvxProduct/save', data),
},
qdSign: {
/** 合同系统/签订 签订查询 */
get_page: (data?: QueryOptions) => http.get('/app/qdSign/page', data),
/** 合同系统/签订 获取合同签订信息 */
get_getContractSignInfo: (data?: QueryOptions) =>
http.get('/app/qdSign/getContractSignInfo', data),
/** 合同系统/打印 选商打印 */
get_printApprove: (data?: QueryOptions) =>
http.get('/app/qdSign/printApprove', data),
/** 合同系统/签订 打印文本 */
get_textPrint: (data?: QueryOptions) =>
http.get('/app/qdSign/textPrint', data),
/** 合同系统/签订 保存送审 */
post_save: (data?: BodyOptions) => http.post('/app/qdSign/save', data),
/** 合同系统/签订 废除 */
post_abolish: (data?: BodyOptions) =>
http.post('/app/qdSign/abolish', data),
},
flowCenter: {
/** 流程中心 启动流程 */
post_start: (data?: BodyOptions) => http.post('/flowCenter/start', data),
/** 流程中心 审核通过 */
post_agree: (data?: BodyOptions) => http.post('/flowCenter/agree', data),
/** 流程中心 审核退回 */
post_rollback: (data?: BodyOptions) =>
http.post('/flowCenter/rollback', data),
/** 流程中心 获取待办 */
post_getTodoList: (data?: BodyOptions) =>
http.post('/flowCenter/getTodoList', data),
/** 流程中心 获取已办 */
post_doneList: (data?: BodyOptions) =>
http.post('/flowCenter/doneList', data),
/** 流程中心 审核撤回 */
get_revoke: (data?: QueryOptions) => http.get('/flowCenter/revoke', data),
/** 流程中心 审核记录 */
get_history: (data?: QueryOptions) => http.get('/flowCenter/history', data),
/** 流程中心 查看流程图 */
get_getFlowImg: (data?: QueryOptions) =>
http.get('/flowCenter/getFlowImg', data),
/** 流程中心 获取可退回节点 */
get_getReturnNode: (data?: QueryOptions) =>
http.get('/flowCenter/getReturnNode', data),
/** 流程中心 获取流程节点人员配置信息 */
get_getNextNodeUserConfig: (data?: QueryOptions) =>
http.get('/flowCenter/getNextNodeUserConfig', data),
/** 流程中心 获取待办数量 */
get_getTodoListSize: (data?: QueryOptions) =>
http.get('/flowCenter/getTodoListSize', data),
/** 流程中心 获取当前审核节点配置信息 */
get_getNodeConfigInfo: (data?: QueryOptions) =>
http.get('/flowCenter/getNodeConfigInfo', data),
/** 流程中心 获取下一节点配置信息 */
get_getNextNodeConfig: (data?: QueryOptions) =>
http.get('/flowCenter/getNextNodeConfig', data),
/** 流程中心 获取流程节点人员配置信息 */
post_getFlowNodeUserConfig: (data?: BodyOptions) =>
http.post('/flowCenter/getFlowNodeUserConfig', data),
/** 流程中心 获取流程变量配置 */
get_getFlowVariablesConfig: (data?: QueryOptions) =>
http.get('/flowCenter/getFlowVariablesConfig', data),
/** 流程中心 获取流程所有人员配置信息 */
get_getFlowUserConfig: (data?: QueryOptions) =>
http.get('/flowCenter/getFlowUserConfig', data),
},
rl: {
moduleParameter: {
/** 流程中心/流程规划 保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/rl/moduleParameter/save', data),
/** 流程中心/流程规划 查询 */
post_page: (data?: BodyOptions) =>
http.post('/app/rl/moduleParameter/page', data),
/** 流程中心/流程规划 删除 */
get_deletes: (data?: QueryOptions) =>
http.get('/app/rl/moduleParameter/deletes', data),
/** 流程中心/流程规划 获取节点审核人 */
get_getNextNodeUser: (data?: QueryOptions) =>
http.get('/app/rl/moduleParameter/getNextNodeUser', data),
},
workFlow: {
/** 合同系统 流程待办 */
get_queryMyTodoTask: (data?: QueryOptions) =>
http.get('/app/rl/workFlow/queryMyTodoTask', data),
},
},
dutyCount: {
/** 协同办公/订餐管理/值班天数 分页查询 */
get_page: (data?: QueryOptions) => http.get('/app/dutyCount/page', data),
/** 协同办公/订餐管理/值班天数 批量保存 */
post_saveBatch: (data?: BodyOptions) =>
http.post('/app/dutyCount/saveBatch', data),
/** 协同办公/订餐管理/值班天数 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/dutyCount/deletes', data),
},
common: {
/** 公共 获取请求ip */
get_getClientIp: (data?: QueryOptions) =>
http.get('/app/common/getClientIp', data),
/** 公共 获取项目地址 */
get_getProjectAddress: (data?: QueryOptions) =>
http.get('/app/common/getProjectAddress', data),
},
address: {
/** 协同办公/订餐管理/订餐地址 查询(分页) */
get_page: (data?: QueryOptions) => http.get('/app/address/page', data),
/** 协同办公/订餐管理/订餐地址 保存 */
post_save: (data?: BodyOptions) => http.post('/app/address/save', data),
/** 协同办公/订餐管理/订餐地址 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/address/deletes', data),
},
superviseFeedbackRecord: {
/** 协同办公/督查督办/反馈记录 保存反馈记录 */
post_save: (data?: BodyOptions) =>
http.post('/app/superviseFeedbackRecord/save', data),
/** 协同办公/督查督办/反馈记录 查询反馈记录 */
get_page: (data?: QueryOptions) =>
http.get('/app/superviseFeedbackRecord/page', data),
/** 协同办公/督查督办/反馈记录 删除反馈记录 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/superviseFeedbackRecord/deletes', data),
},
lxBasisSale: {
/** 合同系统/签约依据 分页保存/修改 */
post_save: (data?: BodyOptions) => http.post('/app/lxBasisSale/save', data),
/** 合同系统/签约依据 查询 */
get_page: (data?: QueryOptions) => http.get('/app/lxBasisSale/page', data),
/** 合同系统/签约依据 删除测试 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/lxBasisSale/deletes', data),
},
workFlow: {
/** 合同系统 查询下一节点id */
get_getNextNodeUserConfig: (data?: QueryOptions) =>
http.get('/app/workFlow/getNextNodeUserConfig', data),
/** 合同系统 获取可退回节点 */
get_getBackNode: (data?: QueryOptions) =>
http.get('/app/workFlow/getBackNode', data),
/** 合同系统 审核记录 */
get_history: (data?: QueryOptions) =>
http.get('/app/workFlow/history', data),
/** 合同系统 流程已办 */
get_getDoneTaskByUserID: (data?: QueryOptions) =>
http.get('/app/workFlow/getDoneTaskByUserID', data),
/** 合同系统 获取流程图 */
get_getFlowImg: (data?: QueryOptions) =>
http.get('/app/workFlow/getFlowImg', data),
},
biddingResult: {
/** 合同系统/选商/选商结果 分页查询 */
get_page: (data?: QueryOptions) =>
http.get('/app/biddingResult/page', data),
/** 合同系统/选商/选商结果 保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/biddingResult/save', data),
/** 合同系统/选商/选商结果 查询流程审核节点 */
get_getFlowNodeUserConfig: (data?: QueryOptions) =>
http.get('/app/biddingResult/getFlowNodeUserConfig', data),
/** 合同系统/选商/选商结果 启动流程 */
post_startWorkFlow: (data?: BodyOptions) =>
http.post('/app/biddingResult/startWorkFlow', data),
/** 合同系统/选商/选商结果 审核通过 */
post_submit: (data?: BodyOptions) =>
http.post('/app/biddingResult/submit', data),
/** 合同系统/选商/选商结果 退回 */
post_rollback: (data?: BodyOptions) =>
http.post('/app/biddingResult/rollback', data),
/** 合同系统/选商/选商结果 待审核 */
get_toDoPage: (data?: QueryOptions) =>
http.get('/app/biddingResult/toDoPage', data),
/** 合同系统/选商/选商结果 查询合同信息 */
get_getContractInfo: (data?: QueryOptions) =>
http.get('/app/biddingResult/getContractInfo', data),
/** 合同系统/选商/选商结果 查询供应商列表 */
get_getProviderInfo: (data?: QueryOptions) =>
http.get('/app/biddingResult/getProviderInfo', data),
/** 合同系统/选商/选商结果 选商专家列表 */
get_queryBiddingExpert: (data?: QueryOptions) =>
http.get('/app/biddingResult/queryBiddingExpert', data),
},
home: {
/** 合同系统/首页待办/已办 首页待办 */
get_todo: (data?: QueryOptions) => http.get('/app/home/todo', data),
/** 合同系统/首页待办/已办 首页已办 */
get_done: (data?: QueryOptions) => http.get('/app/home/done', data),
},
sqConsignPt: {
/** 合同系统/签约授权 签约授权保存 */
post_saveSignMultiEntity: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/saveSignMultiEntity', data),
/** 合同系统/签约授权 签约授权查询 */
get_SigningaAuthorizationSerch: (data?: QueryOptions) =>
http.get('/app/sqConsignPt/SigningaAuthorizationSerch', data),
/** 合同系统/签约授权 查询单条签约授权数据 */
get_getOne: (data?: QueryOptions) =>
http.get('/app/sqConsignPt/getOne', data),
/** 合同系统/签约授权 签约授权提交(非待办提交) */
post_flowStart: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/flowStart', data),
/** 合同系统/签约授权 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/deletes', data),
/** 合同系统/签约授权 签约授权提交 */
post_submit: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/submit', data),
},
addressorsort: {
/** 协同办公/会议管理/发言人顺序配置 发言人顺序查询 */
get_page: (data?: QueryOptions) =>
http.get('/app/addressorsort/page', data),
/** 协同办公/会议管理/发言人顺序配置 发言人排序保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/addressorsort/save', data),
/** 协同办公/会议管理/发言人顺序配置 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/addressorsort/deletes', data),
},
equInfo: {
/** 设备管理/设备静态库管理/ 设备信息维护 设备信息保存 */
post_save: (data?: BodyOptions) => http.post('/app/equInfo/save', data),
/** 设备管理/设备静态库管理/ 设备信息维护 设备信息(获取/查询) */
get_page: (data?: QueryOptions) => http.get('/app/equInfo/page', data),
/** 设备管理/设备静态库管理/ 设备信息维护 设备信息删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/equInfo/deletes', data),
},
equAllot: {
/** 设备管理/查询管理/设备调拨查询 查询 */
get_page: (data?: QueryOptions) => http.get('/app/equAllot/page', data),
/** 设备管理/设备静态库管理/设备调拨 调拨信息保存 */
post_save: (data?: BodyOptions) => http.post('/app/equAllot/save', data),
/** 设备管理/设备静态库管理/设备调拨 调拨信息删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/equAllot/deletes', data),
},
bidding: {
/** 合同系统/标段信息 标段查询 */
get_list: (data?: QueryOptions) => http.get('/app/bidding/list', data),
/** 合同系统/标段信息 标段信息保存(弃用,在选商中报错) */
post_save: (data?: BodyOptions) => http.post('/app/bidding/save', data),
/** 合同系统/标段信息 标段信息删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/bidding/deletes', data),
/** 合同系统/选商/选商结果 查询标段列表 */
get_getBuddingPtInfoList: (data?: QueryOptions) =>
http.get('/app/bidding/getBuddingPtInfoList', data),
},
equAccident: {
/** 设备管理/设备使用管理/事故处理 事故处理(查询/获取) */
get_page: (data?: QueryOptions) => http.get('/app/equAccident/page', data),
/** 设备管理/设备使用管理/事故处理 保存 */
post_save: (data?: BodyOptions) => http.post('/app/equAccident/save', data),
/** 设备管理/设备使用管理/事故处理 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/equAccident/deletes', data),
/** 设备管理/查询管理/事故处理查询 查询 */
get_query: (data?: QueryOptions) =>
http.get('/app/equAccident/query', data),
},
equStopRepair: {
/** 设备管理/设备使用管理/停炉检修处理 查询 */
get_page: (data?: QueryOptions) =>
http.get('/app/equStopRepair/page', data),
/** 设备管理/设备使用管理/停炉检修处理 保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/equStopRepair/save', data),
/** 设备管理/设备使用管理/停炉检修处理 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/equStopRepair/deletes', data),
/** 设备管理/查询管理/停炉检修处理查询 查询 */
get_query: (data?: QueryOptions) =>
http.get('/app/equStopRepair/query', data),
},
equDanger: {
/** 设备管理/设备使用管理/隐患排查 查询 */
get_page: (data?: QueryOptions) => http.get('/app/equDanger/page', data),
/** 设备管理/设备使用管理/隐患排查 保存 */
post_save: (data?: BodyOptions) => http.post('/app/equDanger/save', data),
/** 设备管理/设备使用管理/隐患排查 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/equDanger/deletes', data),
/** 设备管理/查询管理/隐患排查处理查询 查询 */
get_query: (data?: QueryOptions) => http.get('/app/equDanger/query', data),
},
equDayRepair: {
/** 设备管理/设备使用管理/日常维修 查询 */
get_page: (data?: QueryOptions) => http.get('/app/equDayRepair/page', data),
/** 设备管理/设备使用管理/日常维修 保存 */
post_save: (data?: BodyOptions) =>
http.post('/app/equDayRepair/save', data),
/** 设备管理/设备使用管理/日常维修 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/equDayRepair/deletes', data),
/** 设备管理/查询管理/日常维修查询 查询 */
get_query: (data?: QueryOptions) =>
http.get('/app/equDayRepair/query', data),
},
contractRecommendProvider: {
/** 合同系统/选商/合同推荐供应商信息 推荐供应商查询 */
get_list: (data?: QueryOptions) =>
http.get('/app/contractRecommendProvider/list', data),
/** 合同系统/选商/合同推荐供应商信息 删除 */
post_deletes: (data?: BodyOptions) =>
http.post('/app/contractRecommendProvider/deletes', data),
},
};

View File

@ -1,19 +0,0 @@
/** BaseUrl: 基础路径 */
const BASE_URL: string = '/api'
/** AccessTokenField: header 里传accessToken的键名,一般为 Authorization */
export const ACCESS_TOKEN_FIELD = 'Token'
/**
* baseURL
* proxy_type
*/
export function getBaseURL(): string {
if (import.meta.env.MODE === 'development') {
const proxyType = localStorage.getItem('@@@proxy_type') || '';
// return BASE_URL + "/zzz"
return BASE_URL + proxyType
}
return BASE_URL
}

View File

@ -1,83 +0,0 @@
/**
* RefreshToken
* @description:
*/
import { createAlova } from 'alova'
import { useAccessStore } from '@vben/stores';
import fetchAdapter from 'alova/fetch';
import vueHook from 'alova/vue';
import { getBaseURL, ACCESS_TOKEN_FIELD } from './config';
let lock = false
let promiseResult: any[] = []
const alova = createAlova({
baseURL: getBaseURL(),
cacheFor: null,
statesHook: vueHook,
requestAdapter: fetchAdapter(),
beforeRequest: (method) => {
// ...原请求前拦截器
const accessStore = useAccessStore();
// const userStore = useUserStore()
// console.log('beforeRequest', userStore.accessToken)
// 添加token到请求头
// method.config.headers[ACCESS_TOKEN_FIELD] = `${userStore.accessToken}`
},
responded: async (response, method) => {
let json = await response.json();
return json.data || null
},
})
export function getAccessToken(rToken: string): Promise<any> {
return new Promise(async (resolve, reject) => {
promiseResult.push({
resolve,
reject
})
// const userStore = useUserStore();
if (!lock) {
lock = true
// 为了让refreshToken请求顺利通过需要通过元数据标识authRole为refreshToken。参考官方文档
const method = alova.Post('/system/auth/refreshToken', { token: rToken }, {
meta: {
authRole: 'refreshToken'
}
});
method.send()
.then((data: any) => {
console.log(data)
// 如果 refreshToken 请求成功则将新的token存储到本地
if (data && data.accessToken) {
// userStore.setToken(data.accessToken);
// userStore.setTokenExpiresTime(data.accessExpire)
// userStore.setRefreshToken(data.refreshToken);
while (promiseResult.length) {
// p1.resolve(res.data)
promiseResult.shift().resolve(data)
}
lock = false
return
}
// userStore.resetStore()
while (promiseResult.length) {
// p1.reject(err)
promiseResult.shift().reject("身份认证已失效,请重新登录")
}
})
.catch(err => {
while (promiseResult.length) {
// p1.reject(err)
promiseResult.shift().reject(err)
}
lock = false
})
}
})
}

View File

@ -1,324 +0,0 @@
/**
*
*/
import { preferences } from '@vben/preferences';
import { useAccessStore } from '@vben/stores';
import { createAlova } from 'alova';
import { createServerTokenAuthentication } from 'alova/client';
import fetchAdapter from 'alova/fetch';
import vueHook from 'alova/vue';
import { message } from 'ant-design-vue';
import { merge } from 'lodash-es';
import { useAuthStore } from '#/store';
import { type BodyOptions, type QueryOptions } from '../global.d';
import { ACCESS_TOKEN_FIELD, getBaseURL } from './config';
import { transferResponse } from './transferResponse';
/** 储存过期的token */
const expireTokenCache = [];
/** 服务端 Token 校验 */
const { onAuthRequired, onResponseRefreshToken } =
createServerTokenAuthentication({
refreshTokenOnSuccess: {
/**
* Token
* response和methodboolean表示token是否过期
*/
isExpired: async (response, method) => {
// 文件下载操作
if (method.meta?.responseType === 'blob') {
return false;
}
const responseClone = response.clone();
const data = await responseClone.json();
// 当服务端返回401时表示token过期
const isExpired = ['401'].includes(data.code);
if (isExpired) {
console.log('AccessToken已过期', data.code);
expireTokenCache.push(method.config.headers[ACCESS_TOKEN_FIELD]);
}
return isExpired;
},
/** 当token过期时触发在此函数中触发刷新token */
handler: async (_response, _method) => {
console.warn('Access token or refresh token is invalid or expired. ');
const accessStore = useAccessStore();
const authStore = useAuthStore();
accessStore.setAccessToken(null);
if (
preferences.app.loginExpiredMode === 'modal' &&
accessStore.isAccessChecked
) {
accessStore.setLoginExpired(true);
} else {
await authStore.logout(false);
}
throw new Error('登录已过期,请重新登录');
// const userStore = useUserStore();
// try {
// let rToken = userStore.refreshToken;
// // 如果没有refreshToken则跳转登录页
// if (!rToken) {
// throw new Error('登录已过期,请重新登录');
// }
// await getAccessToken(rToken)
// expireTokenCache = []
// } catch (error: any) {
// window.$message?.error(error.message);
// userStore.resetStore()
// throw error;
// }
},
},
});
export const alovaInstance = createAlova({
/** 动态代理配置 */
baseURL: getBaseURL(),
/** 框架请求适配器 */
statesHook: vueHook,
requestAdapter: fetchAdapter(),
/** 设置缓存状态:不开启 */
cacheFor: null,
// cacheFor: {
// // 统一设置POST的缓存模式
// GET: {
// mode: 'restore',
// expire: 60 * 10 * 1000,
// },
// // POST: {
// // mode: 'restore',
// // expire: 60 * 10 * 1000
// // },
// // // 统一设置HEAD请求的缓存模式
// // HEAD: 60 * 10 * 1000
// },
/** 请求拦截器 */
beforeRequest: onAuthRequired((method) => {
const accessStore = useAccessStore();
if (accessStore.accessToken) {
method.config.headers.Token = accessStore.accessToken;
// 统一授权的这个接口需要以Authorization传参无语 /sys/user/functiontree/XTBGXT
method.config.headers.Authorization = `Bearer ${accessStore.accessToken}`;
}
method.config.headers['Accept-Language'] = preferences.app.locale;
// const userStore = useUserStore()
// // 添加token到请求头
// if (userStore.accessToken) {
// method.config.headers[ACCESS_TOKEN_FIELD] = `Bearer ${userStore.accessToken}`
// method.config.headers["Authorization"] = `Bearer ${userStore.accessToken}`
// }
// method.config.cacheFor = {
// // 设置缓存模式为内存模式
// mode: 'restore',
// // 单位为毫秒
// // 当设置为`Infinity`表示数据永不过期设置为0或负数时表示不缓存
// expire: 60 * 10 * 1000
// }
// method.config.transform = (rawData, headers) => {
// console.log('接口响应', rawData)
// return transferResponse(rawData)
// }
}),
/** 响应拦截器 */
responded: onResponseRefreshToken(async (response, method) => {
if (method.meta?.responseType === 'blob') {
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
const contentDisposition = response.headers.get('content-disposition');
let fileName = 'downloaded-file';
if (contentDisposition) {
const matches = /filename="?([^"]+)"?/.exec(contentDisposition);
if (matches != null && matches[1]) {
fileName = decodeURIComponent(matches[1]);
}
}
a.download = fileName;
// 触发下载
document.body.append(a);
a.click();
// 移除链接
a.remove();
window.URL.revokeObjectURL(url);
return {
blob,
url,
filename: fileName,
};
}
// if (response.status >= 400) {
// throw new Error(response.statusText);
// }
let json = await response.json();
console.log('【接口】', method.url);
console.log('原始响应', JSON.parse(JSON.stringify(json)));
json = transferResponse(json);
console.log('改造响应', JSON.parse(JSON.stringify(json)));
const accessStore = useAccessStore();
if (json.code != 0) {
if (json.code == '401') {
message.error('用户身份过期,请重新登录');
const authStore = useAuthStore();
accessStore.setAccessToken(null);
await authStore.logout();
// const userStore = useUserStore();
// userStore.resetStore();
} else {
message.error(json.msg || '服务器开小差,请稍后再试');
}
// 抛出错误或返回reject状态的Promise实例时此请求将抛出错误
throw new Error((json && json.msg) || '出错了');
}
// 解析的响应数据将传给method实例的transformData钩子函数这些函数将在后续讲解
return json.data;
}),
});
// 请求配置处理中间件
function requestConfigMiddleware(method: string, url: string) {}
class Http {
private appendParamsToUrl(url: string, params: any): string {
let queryString = '';
for (const key in params) {
if (Object.prototype.hasOwnProperty.call(params, key)) {
queryString += `${queryString ? '&' : '?'}${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`;
}
}
return url + queryString;
}
/**
*
* @param customConfig
* @returns
*/
private getConfig(customConfig?: any): any {
// 递归属性拷贝
return merge(
{},
{
meta: {
showLoading: false,
showError: false,
},
},
customConfig,
);
}
private isBodyOptions(
options: BodyOptions | QueryOptions,
): options is BodyOptions {
return (options as BodyOptions).data !== undefined;
}
/**
* swagger路径参数pathParams
* "/api/v1/user/{id}",{ pathParams:{ id :1 },params:{ id:2 } }
* /api/v1/user/1?id=2
*/
private replacePathParams(url: string, pathParams?: any): string {
if (!pathParams) return url;
return url.replaceAll(
/\{(\w+)\}/g,
(_, key) => pathParams[key] || `{${key}}`,
);
}
private request(
method: string,
url: string,
data?: BodyOptions | QueryOptions,
): Promise<any> {
let finalUrl = this.replacePathParams(url, data?.pathParams);
const config = this.getConfig(data?.config);
// 当组件使用allowClear属性时会将数据置为null导致数据查询失败
if (data && data.params) {
Object.keys(data.params).forEach((key) => {
if (data.params[key] === null || data.params[key] === undefined) {
delete data.params[key];
}
});
}
if (data && this.isBodyOptions(data)) {
Object.keys(data.data).forEach((key) => {
if (data.data[key] === null || data.data[key] === undefined) {
delete data.data[key];
}
});
}
let alovaMethod: 'Delete' | 'Get' | 'Post' | 'Put' = 'Get';
if (method === 'get' || method === 'delete') {
if (method === 'get') {
alovaMethod = 'Get';
}
if (method === 'delete') {
alovaMethod = 'Delete';
}
return alovaInstance[alovaMethod](finalUrl, {
...config,
params: data?.params,
});
} else {
// 处理 params 到 url 的逻辑
if (data?.params) {
finalUrl = this.appendParamsToUrl(finalUrl, data.params);
}
if (method === 'post') {
alovaMethod = 'Post';
}
if (method === 'put') {
alovaMethod = 'Put';
}
return alovaInstance[alovaMethod](finalUrl, data?.data, { ...config });
}
}
delete(url: string, data?: QueryOptions) {
return this.request('delete', url, data);
}
get(url: string, data?: QueryOptions) {
return this.request('get', url, data);
}
patch(url: string, data?: BodyOptions) {
return this.request('patch', url, data);
}
post(url: string, data?: BodyOptions) {
return this.request('post', url, data);
}
put(url: string, data?: BodyOptions) {
return this.request('put', url, data);
}
}
export const http = new Http();

View File

@ -1,89 +0,0 @@
const SUCCESS_CODE = 0;
/**
* BFF层
* ,xxx代指需要的数据[xxx]{xxx}{data:{xxx}}{records:xxx}{content:xxx}.........................
* totaltotalElements
*
* @param response
*/
export function transferResponse(response: any) {
// 如果后端直接返回数组,如[xxx]
if (Array.isArray(response)) {
return {
code: SUCCESS_CODE,
data: {
rows: response,
},
msg: 'Ok',
};
}
// 如果后端直接返回数据内容对象,如{xxx},则先进行统一响应包装
if (response.code == undefined) {
response = {
code: SUCCESS_CODE,
data: response,
msg: 'Ok',
};
}
let { code, data = {}, msg, ...rest } = response;
if (!data) {
data = {};
}
if (typeof data === 'string') {
data = {
value: data,
};
}
// eslint-disable-next-line eqeqeq
if (code == 'success') {
code = 0;
}
if (code == 'failure' && msg && msg.includes('token无效')) {
code = 401;
}
if (Array.isArray(data)) {
data = {
rows: data,
};
}
if (!data.total && data.totalElements) {
data.total = data.totalElements;
}
if (data.records && Array.isArray(data.records)) {
data.rows = data.records;
delete data.records;
}
if (data.content && Array.isArray(data.content)) {
data.rows = data.content;
delete data.content;
}
if (data.content && Array.isArray(data.records)) {
data.rows = data.records;
delete data.records;
}
if (response.code == 200 && response.flag === false) {
code = 500;
} else if (response.code == '200') {
code = 0;
}
return {
code,
data: {
...data,
...rest,
},
msg,
};
}

View File

@ -1,77 +0,0 @@
import { http } from '../request/index';
import { useAccessStore } from '@vben/stores';
export namespace AuthApi {
/** 登录接口参数 */
export interface LoginParams {
password: string;
username: string;
}
/** 登录接口返回值 */
export interface LoginResult {
accessToken: string;
desc: string;
realName: string;
userId: string;
username: string;
}
export interface RefreshTokenResult {
data: string;
status: number;
}
}
/**
*
*/
export async function loginApi(data: AuthApi.LoginParams) {
return http.post('/uc/uaa/validateAccount', {
data,
config: {
transform(rawData) {
if (rawData.access_token) {
rawData.accessToken = rawData.access_token;
rawData.realName = rawData.display_name;
return rawData;
}
return rawData;
},
},
});
}
/**
* accessToken
*/
export async function refreshTokenApi() {
return http.post('/auth/refresh');
}
/**
* 退
*/
export async function logoutApi() {
return http.post('/uc/uaa/logout');
}
/**
*
*/
export async function getAccessCodesApi() {
return http.post('/auth/codes');
}
/**
*
*/
export async function getUserInfoApi() {
const accessStore = useAccessStore();
return http.post('/uc/sys/user/checkToken', {
data: {
token: accessStore.accessToken,
},
});
}

View File

@ -1,8 +0,0 @@
import { http } from '../request/index';
/**
*
*/
export async function getAllMenusApi() {
return http.get('/menu/all');
}

View File

@ -1,115 +0,0 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { useAntdDesignTokens } from '@vben/hooks';
import { preferences, usePreferences } from '@vben/preferences';
import { App, ConfigProvider, theme } from 'ant-design-vue';
import { antdLocale } from '#/locales';
import { useDictStore } from './store/dict';
defineOptions({ name: 'App' });
const { isDark } = usePreferences();
const { tokens } = useAntdDesignTokens();
const tokenTheme = computed(() => {
const algorithm = isDark.value
? [theme.darkAlgorithm]
: [theme.defaultAlgorithm];
// antd
if (preferences.app.compact) {
algorithm.push(theme.compactAlgorithm);
}
return {
algorithm,
token: tokens,
};
});
const dictStore = useDictStore();
if (dictStore.initDict) {
dictStore.setDictMap();
}
</script>
<template>
<ConfigProvider :locale="antdLocale" :theme="tokenTheme">
<App>
<RouterView />
</App>
</ConfigProvider>
</template>
<style>
.vxebasic-table-container {
flex: auto;
min-height: 300px;
}
.ant-btn {
display: flex;
align-items: center;
}
.ant-modal-confirm-btns {
display: flex;
justify-content: flex-end;
}
.ant-btn__warning {
@apply bg-warning text-warning-foreground hover:bg-warning/90 shadow;
}
.ant-checkbox-disabled .ant-checkbox-inner {
background: #fafafa;
color: #333;
}
.ant-input-number-disabled {
background: #fafafa;
color: #333;
}
.ant-input-affix-wrapper-disabled,
.ant-input-affix-wrapper[disabled] {
background: #fafafa;
color: #333;
}
.ant-radio-wrapper-disabled {
background: #fafafa;
color: #333;
}
.ant-radio-wrapper .ant-radio-disabled .ant-radio-inner {
background-color: rgba(50, 54, 57, 0.04);
border-color: hsl(240 5.9% 90%);
}
.ant-picker.ant-picker-disabled {
background: #fafafa;
color: #333;
}
.ant-select-disabled.ant-select:not(.ant-select-customize-input)
.ant-select-selector {
background: #fafafa;
color: #333;
}
.ant-picker .ant-picker-input > input-disabled,
.ant-picker .ant-picker-input > input[disabled] {
background: #fafafa;
color: #333 !important;
}
.ant-input-disabled,
.ant-input[disabled] {
background: #fafafa;
color: #333;
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -1,41 +0,0 @@
import { createApp } from 'vue';
import { registerAccessDirective } from '@vben/access';
import { initStores } from '@vben/stores';
import '@vben/styles';
import '@vben/styles/antd';
import { VbenButton } from '@vben-core/shadcn-ui';
import { setupI18n } from '#/locales';
import App from './app.vue';
import { registerFastCrud } from './plugins/fastCrud';
import { registerVxeTable } from './plugins/vxeTable';
import { router } from './router';
async function bootstrap(namespace: string) {
const app = createApp(App);
// 国际化 i18n 配置
await setupI18n(app);
// 配置 pinia-tore
await initStores(app, { namespace });
// 安装权限指令
registerAccessDirective(app);
// 配置路由及路由守卫
app.use(router);
// 引入 fast-crud 相关组件
registerFastCrud(app);
registerVxeTable(app);
app.component('vben-button', VbenButton);
app.mount('#app');
}
export { bootstrap };

View File

@ -1,97 +0,0 @@
import { dict } from '@fast-crud/fast-crud';
import Apis from '#/api';
export const unitComponentProps = {
name: 'fs-dict-tree',
vModel: 'value',
allowClear: true,
class: 'min-w-[180px]',
showCheckedStrategy: 'SHOW_CHILD',
showSearch: true,
'tree-node-filter-prop': 'label',
dict: dict({
isTree: true,
async getData(_context) {
const data: any = await Apis.api.core.orgemplbc.organization.post_paging({
params: {
page: 1,
size: 1000,
},
data: {
subFilter: [
{
symbol: 'like',
singleValue: '0001%',
key: 'ORG_ID',
logic: 'AND',
},
],
},
});
data.rows.forEach((item: any) => {
item.label = item.ORG_NAME;
item.value = item.ORG_ID;
});
const treeData = transTree(data.rows);
return treeData;
},
}),
};
export async function getUnitData(_params?: any) {
const data: any = await Apis.api.core.orgemplbc.organization.post_paging({
params: {
page: 1,
size: 1000,
},
data: {
subFilter: [
{
symbol: 'like',
singleValue: '0001%',
key: 'ORG_ID',
logic: 'AND',
},
],
},
});
data.rows.forEach((item: any) => {
item.label = item.ORG_NAME;
item.value = item.ORG_ID;
});
const treeData = transTree(data.rows);
return treeData;
}
// 转换树行数据的方法
function transTree(list) {
// 最终生成的树行结构
const _treeData: any[] = [];
// 对传入进来的 数据进行遍历,查找对应的子级
list.forEach((item) => {
// 给每一项添加子节点
// item.children = []
item.key = item.ORG_ID;
item.label = item.ORG_NAME;
// 如果 pid 为空,说明是最顶级,直接放到 _treeData 中即可
if (item.ORG_LEVEL === 1) {
item.selectable = false;
_treeData.push(item);
}
// 根据前面的分析pid 代表的是父级的 id从而可以进行筛选子级
// filter 方法会把满足条件到的每一项,组成一个数组进行返回
const children = list.filter((data) => data.PARENT_ID === item.ORG_ID);
// 如果没有子节点,直接 return 不做任何处理
if (children.length === 0) return;
// 将返回的子级进行赋值给父级(item)的 children 属性
item.children = children;
});
// 将最终生成的数据返回出去
return _treeData;
}

View File

@ -1,110 +0,0 @@
<template>
<template v-if="props.selectable">
<div
v-for="(dict, index) in dicts"
:key="index"
@click="handleClick(dict)"
:class="{ 'cursor-pointer': selectable }"
>
<a-tag :color="getTagColor(dict)" :round="!multiple">
{{ dict[labelField] }}
</a-tag>
</div>
</template>
<div v-else-if="Array.isArray(value)" class="flex flex-row flex-wrap">
<template v-for="(dict, index) in dicts" :key="index">
<div v-if="selectedValues.includes(dict.value)" class="mb-1">
<a-tag>
{{ dict[labelField] }}
</a-tag>
</div>
</template>
</div>
<template v-else>
<a-tag :color="dict?.colorType || ''">
{{ (dict && dict[labelField]) || value }}
</a-tag>
</template>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { Tag, Space } from 'ant-design-vue';
import { getDictOpts, getDictObj } from '#/utils/dict';
import type { DictDataType } from '#/utils/dict';
const props = withDefaults(
defineProps<{
type?: string;
options: DictDataType[];
value?: string | number | boolean | Array<string | number | boolean>;
icon?: string;
multiple?: boolean;
selectable?: boolean;
labelField?: string;
valueField?: string;
}>(),
{
type: '',
options: () => [],
multiple: false,
selectable: false,
labelField: 'label',
valueField: 'value',
value: '',
icon: '',
},
);
const emit = defineEmits(['update:value', 'tag-click']);
const dictData = ref<DictDataType | null>(null);
const selectedValues = ref<Array<string | number>>(
Array.isArray(props.value) ? props.value : [],
);
const dicts = computed(() => {
return props.type ? getDictOpts(props.type) : props.options;
});
const dict = computed(() => {
for (const item of props.options) {
if (item[props.valueField] == props.value) {
return item;
}
}
return {};
});
const handleClick = (dict: DictDataType) => {
emit('tag-click', dict);
if (props.selectable) {
if (props.multiple) {
const index = selectedValues.value.indexOf(dict.value);
if (index === -1) {
selectedValues.value.push(dict.value);
} else {
selectedValues.value.splice(index, 1);
}
emit('update:value', selectedValues.value);
} else {
emit('update:value', dict.value);
}
}
};
const getTagColor = (dict: DictDataType) => {
return (props.multiple && selectedValues.value.includes(dict.value)) ||
(!props.multiple && props.value == dict.value)
? 'blue'
: '';
};
onMounted(() => {});
</script>
<style scoped>
.cursor-pointer {
cursor: pointer;
}
</style>

View File

@ -1 +0,0 @@
export { default as DictTag } from './dict-tag.vue';

View File

@ -1,13 +0,0 @@
import type { VxeGridPropTypes } from 'vxe-table';
import dayjs from 'dayjs';
import { useRender } from '#/hooks/useRender';
export const PrimaryKey = 'guid';
export function getColumns(_params: any = {}): VxeGridPropTypes.Columns {
return [
];
}

View File

@ -1,61 +0,0 @@
<script lang="ts" setup>
import { nextTick, ref, watch } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { logger } from 'common-utils';
withDefaults(
defineProps<{
loading?: boolean;
}>(),
{
loading: false,
},
);
const emit = defineEmits<{
(e: 'confirm', data: any): void;
(e: 'update:loading', data: any): void;
}>();
const isConfirmLoading = ref(false);
const data = ref({
title: '',
schema: {},
});
const formRef = ref();
const formBinding = ref();
const [Modal, modalApi] = useVbenModal({
async onOpenChange(isOpen: boolean) {
if (isOpen) {
data.value = modalApi.getData<Record<string, any>>() || {};
formBinding.value = data.value.schema || {};
nextTick(() => {});
}
isConfirmLoading.value = false;
},
async onConfirm() {
isConfirmLoading.value = true;
try {
await formRef.value?.submit();
emit('confirm', formRef.value.form);
} catch (error) {
logger.error('', error);
} finally {
isConfirmLoading.value = false;
}
},
});
</script>
<template>
<Modal :confirm-loading="loading" :loading="loading" :title="data.title">
<fs-form v-if="formBinding.columns" ref="formRef" v-bind="formBinding" />
</Modal>
</template>

View File

@ -1,28 +0,0 @@
import type { RouteMeta as IRouteMeta } from '@vben-core/typings';
import 'vue-router';
declare module 'vue-router' {
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
interface RouteMeta extends IRouteMeta {}
}
export interface VbenAdminProAppConfigRaw {
VITE_GLOB_API_URL: string;
}
export interface ApplicationConfig {
apiURL: string;
}
declare global {
interface Window {
_VBEN_ADMIN_PRO_APP_CONF_: VbenAdminProAppConfigRaw;
}
}
export interface PageVo {
code: number;
data: any;
message: string;
}

View File

@ -1,149 +0,0 @@
import { h } from 'vue';
import dayjs from 'dayjs';
import { Button, Tag } from 'ant-design-vue';
import { isArray, isString } from 'lodash-es';
import { DictTag } from '#/components/dict-tag';
// import { Icon } from '@/components/Icon';
import { Tooltip } from 'ant-design-vue'
import { getDictOpts } from '#/utils/dict';
export const useRender = {
/**
*
* @param text
* @returns image标签
*/
// renderImg: (text: string) => {
// if (text) {
// if (isArray(text)) return h(TableImg, { imgList: text });
// else if (isString(text)) return h(TableImg, { imgList: [text] });
// }
// return '';
// },
/**
*
* @param url
* @param text
* @returns link
*/
renderLink: (url: string, text?: string) => {
if (url) return h(Button, { type: 'link', href: url, target: '_blank' }, () => text || '');
return '';
},
/**
* text与val
* @param text 1
* @param val 2
* @returns 1 + 2
*/
renderText: (text: string, val: string) => {
if (text) return `${text} ${val}`;
else return '';
},
/**
*
* @param text
* @param val
*/
renderMultiLineText: (text: string, params?: any) => {
if (text) {
params = params || {}
let classArr: string[] = params.class || [];
if (params?.maxLine && params?.maxLine > 0) {
classArr.push('line-clamp-' + params?.maxLine)
}
return h(
Tooltip,
{ trigger: 'hover' },
{
trigger: () => h('span', { class: classArr.join(' ') }, text),
default: () => text
}
)
}
return '';
},
/**
*
* @param text
* @param color
* @returns
*/
renderTag: (text: string | number, color?: string) => {
if (color) return h(Tag, { color }, () => text);
else return h(Tag, {}, () => text);
},
/**
*
* @param texts
* @returns
*/
renderTags: (texts: string[]) => {
if (texts) {
return h('div', null, [
texts.map((text) => {
return h(Tag, null, () => text);
}),
]);
}
return '';
},
/**
*
* @param text
* @param format
* @returns
*/
renderDate: (text: string, format?: string) => {
if (!text) return '';
if (!format) return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
else return dayjs(text).format(format);
},
/**
*
* @param text
* @param dictType
* @returns
*/
renderDict: (text: string, dictType: string, params?: any) => {
if (!dictType && !params.options) {
console.warn('请传入字典类型')
return '';
}
let dict: any[] = [];
if (dictType) {
dict = getDictOpts(dictType)
}
if (params && params.options) {
dict = params.options;
}
return h(DictTag, { options: dict, value: text, ...params });
}
// /**
// * 渲染图标icon
// * @param text icon
// * @returns icon
// */
// renderIcon: (text: string) => {
// if (text) return h(Icon, { icon: text });
// },
/**
* 使JsonPreview组件 便JSON
* @param json json字符串/obj
* @returns json返回JsonPreview
*/
// renderJsonPreview: (json: any) => {
// if (!json) return '';
// if (typeof json === 'object') return h(JsonPreview, { data: json });
// if (typeof json === 'string') {
// try {
// const data = JSON.parse(json);
// return h(JsonPreview, { data });
// } catch (e) {
// return json;
// }
// }
// },
};

View File

@ -1,76 +0,0 @@
import { ref } from 'vue';
import { merge } from 'lodash-es';
import { type VxeGridInstance, type VxeGridProps } from 'vxe-table';
export function useVxeTable(props: { ref: string }) {
const xGridRef = ref<VxeGridInstance<any>>();
return {
xGridRef,
gridProps: (props: VxeGridProps) => {
// 设置默认属性
const defaultProps: VxeGridProps = {
// 保持原始值的状态,被某些功能所依赖,比如编辑状态、还原数据等(开启后影响性能,具体取决于数据量)
keepSource: false,
height: 'auto',
border: true,
editConfig: {
mode: 'row',
},
rowConfig: {
isCurrent: true,
},
// 斑马条纹
stripe: false,
pagerConfig: {
enabled: true,
size: 'mini',
pageSize: 50,
autoHidden: false,
},
// 列设置
columnConfig: {
// 取消列选中效果
isCurrent: false,
isHover: false,
// 取消列宽拖动功能
resizable: false,
},
toolbarConfig: {
enabled: true,
export: false,
// print: true,
zoom: true,
custom: true,
refresh: true,
slots: {
buttons: 'toolbar_buttons',
},
},
headerAlign: 'left',
align: 'left',
};
// 如果mergedProps.proxyConfig是空对象则删除该字段不然 vxetable 可能会误判断
if (props.proxyConfig && JSON.stringify(props.proxyConfig) != '{}') {
defaultProps.proxyConfig = {
props: {
list: 'rows',
result: 'rows',
total: 'total',
},
};
}
return merge({}, defaultProps, props);
},
triggerProxy: (code: string) => {
const $grid = xGridRef.value;
if ($grid) {
$grid.commitProxy(code);
}
},
};
}

View File

@ -1,121 +0,0 @@
<script setup lang="ts">
import { usePreferences } from '@vben/preferences';
import AuthenticationFormView from './form.vue';
import SloganIcon from './icons/slogan.vue';
interface Props {
appName?: string;
logo?: string;
pageTitle?: string;
pageDescription?: string;
sloganImage?: string;
copyright?: boolean;
}
withDefaults(defineProps<Props>(), {
appName: '',
copyright: true,
logo: '',
pageDescription: '',
pageTitle: '',
sloganImage: '',
});
const { authPanelCenter, authPanelLeft, authPanelRight, isDark } =
usePreferences();
</script>
<template>
<div
:class="[isDark]"
class="flex min-h-full flex-1 select-none overflow-x-hidden"
>
<!-- <template v-if="toolbar">
<slot name="toolbar">
<Toolbar :toolbar-list="toolbarList" />
</slot>
</template> -->
<!-- 左侧认证面板 -->
<AuthenticationFormView
v-if="authPanelLeft"
class="min-h-full w-2/5 flex-1"
transition-name="slide-left"
/>
<!-- 头部 Logo 和应用名称 -->
<div class="absolute left-0 top-0 z-10 flex flex-1">
<div
class="text-foreground lg:text-foreground ml-4 mt-4 flex flex-1 items-center sm:left-6 sm:top-6"
>
<img :alt="appName" :src="logo" class="mr-2" width="42" />
<p class="text-xl font-medium">
{{ appName }}
</p>
</div>
</div>
<!-- 系统介绍 -->
<div v-if="!authPanelCenter" class="relative hidden w-0 flex-1 lg:block">
<div
class="bg-background-deep absolute inset-0 h-full w-full dark:bg-[#070709]"
>
<div class="login-background absolute left-0 top-0 size-full"></div>
<div class="flex-col-center -enter-x mr-20 h-full">
<template v-if="sloganImage">
<img
:alt="appName"
:src="sloganImage"
class="animate-float h-64 w-2/5"
/>
</template>
<SloganIcon v-else :alt="appName" class="animate-float h-70 w-1/2" />
<div class="text-1xl text-foreground mt-6 font-sans lg:text-2xl">
{{ pageTitle }}
</div>
<div class="dark:text-muted-foreground mt-2">
{{ pageDescription }}
</div>
</div>
</div>
</div>
<!-- 中心认证面板 -->
<!-- <div v-if="authPanelCenter" class="flex-center relative w-full">
<div class="login-background absolute left-0 top-0 size-full"></div>
<AuthenticationFormView
class="md:bg-background shadow-primary/5 shadow-float w-full rounded-3xl pb-20 md:w-2/3 lg:w-1/2 xl:w-[36%]"
/>
</div> -->
<!-- 右侧认证面板 -->
<AuthenticationFormView
v-if="authPanelRight"
class="min-h-full w-[34%] flex-1"
/>
</div>
</template>
<style scoped>
.login-background {
background: linear-gradient(
154deg,
#07070915 30%,
hsl(var(--primary) / 30%) 48%,
#07070915 64%
);
filter: blur(100px);
}
.dark {
.login-background {
background: linear-gradient(
154deg,
#07070915 30%,
hsl(var(--primary) / 20%) 48%,
#07070915 64%
);
filter: blur(100px);
}
}
</style>

View File

@ -1,33 +0,0 @@
<script setup lang="ts">
defineOptions({
name: 'AuthenticationFormView',
});
</script>
<template>
<div
class="flex-col-center dark:bg-background-deep bg-background relative px-6 py-10 lg:flex-initial lg:px-8"
>
<slot></slot>
<!-- Router View with Transition and KeepAlive -->
<RouterView v-slot="{ Component, route }">
<Transition appear mode="out-in" name="slide-right">
<KeepAlive :include="['Login']">
<component
:is="Component"
:key="route.fullPath"
class="enter-x mt-6 w-full sm:mx-auto md:max-w-md"
/>
</KeepAlive>
</Transition>
</RouterView>
<!-- Footer Copyright -->
<div
class="text-muted-foreground absolute bottom-3 flex text-center text-xs"
>
<slot name="copyright"> </slot>
</div>
</div>
</template>

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
export { default as AuthPageLayout } from './authentication.vue';

View File

@ -1,201 +0,0 @@
<script lang="ts" setup>
import type { NotificationItem } from './notification';
import { computed, onMounted, ref } from 'vue';
import { storeToRefs, useAccessStore, useUserStore } from '@vben/stores';
// import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
import { useRouter } from 'vue-router';
import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
import { PhUserCircle } from '@vben/icons';
import { BasicLayout, LockScreen, UserDropdown } from '@vben/layouts';
import { preferences } from '@vben/preferences';
import Apis from '#/api';
import { useAuthStore } from '#/store';
import { DICT_TYPE, getDictObj } from '#/utils/dict';
import { Notification } from './notification';
const router = useRouter();
const notifications = ref<NotificationItem[]>([
// {
// avatar: "https://avatar.vercel.sh/vercel.svg?text=VB",
// date: "3",
// isRead: true,
// message: "",
// title: " 14 ",
// },
// {
// avatar: "https://avatar.vercel.sh/1",
// date: "",
// isRead: false,
// message: "",
// title: " ",
// },
// {
// avatar: "https://avatar.vercel.sh/1",
// date: "2024-01-01",
// isRead: false,
// message: "",
// title: " ",
// },
// {
// avatar: "https://avatar.vercel.sh/satori",
// date: "1",
// isRead: false,
// message: "",
// title: "",
// },
]);
const userStore = useUserStore();
const authStore = useAuthStore();
const accessStore = useAccessStore();
const showDot = computed(() =>
notifications.value.some((item) => !item.isRead),
);
const menus = computed(() => [
{
handler: () => {
router.push('/user/center');
},
icon: PhUserCircle,
text: '个人中心',
},
// {
// handler: () => {
// openWindow(VBEN_GITHUB_URL, {
// target: '_blank',
// });
// },
// icon: MdiGithub,
// text: 'GitHub',
// },
// {
// handler: () => {
// openWindow(`${VBEN_GITHUB_URL}/issues`, {
// target: '_blank',
// });
// },
// icon: CircleHelp,
// text: $t('widgets.qa'),
// },
]);
const { loginLoading } = storeToRefs(authStore);
const avatar = computed(() => {
return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;
});
async function handleLogout() {
await authStore.logout(false);
}
function handleNoticeClear() {
notifications.value = [];
}
function handleMakeAll() {
notifications.value.forEach((item) => (item.isRead = true));
}
function handleViewAll() {
router.push('/user/todo');
}
const isDev = import.meta.env.MODE === 'development';
const value = ref(localStorage.getItem('@@@proxy_type') || ''); // /zp
function handleMenuClick(e) {
if (e.key === 'pro') {
localStorage.setItem('@@@proxy_type', '');
} else {
localStorage.setItem('@@@proxy_type', `/${e.key}`);
}
location.reload();
}
onMounted(async () => {
// const data = await Apis.home.get_todo({
// params: { pageNum: 1, pageSize: 20 },
// });
// notifications.value = data.rows.map((item) => {
// let module =
// getDictObj(DICT_TYPE.contract_todo_type, item.module)?.label || '';
// module = module.slice(-4);
// let moduleTextArr = [...module];
// moduleTextArr =
// moduleTextArr.length <= 3 ? moduleTextArr : moduleTextArr.slice(-4);
// return {
// moduleTextArr,
// avatar: '',
// date: item.createTime,
// isRead: true,
// message: item.contractName,
// title: item.taskName,
// };
// });
// console.log(notifications);
// resetAllStores();
});
</script>
<template>
<BasicLayout @clear-preferences-and-logout="handleLogout">
<template #user-dropdown>
<UserDropdown
:avatar
:description="userStore.userInfo?.belongOrgName"
:menus
:tag-text="userStore.userInfo?.gwmc"
:text="userStore.userInfo?.displayName"
@logout="handleLogout"
/>
</template>
<template #notification>
<a-dropdown v-if="isDev">
<template #overlay>
<a-menu selectable @click="handleMenuClick">
<a-menu-item key="pro"> 正式 </a-menu-item>
<a-menu-item key="czg"> czg </a-menu-item>
<a-menu-item key="zp"> zp </a-menu-item>
<a-menu-item key="zzz"> zzz </a-menu-item>
<a-menu-item key="xmh"> xmh </a-menu-item>
</a-menu>
</template>
<a-button> {{ value ? `代理${value}` : '代理切换' }} </a-button>
</a-dropdown>
<!-- <Notification
:dot="showDot"
:notifications="notifications"
@clear="handleNoticeClear"
@make-all="handleMakeAll"
@view-all="handleViewAll"
/> -->
</template>
<template #extra>
<AuthenticationLoginExpiredModal
v-model:open="accessStore.loginExpired"
:avatar
:loading="loginLoading"
password-placeholder=""
username-placeholder=""
@submit="authStore.authLogin"
/>
</template>
<template #lock-screen>
<LockScreen
:avatar
:text="userStore.userInfo?.displayName"
@to-login="handleLogout"
/>
</template>
</BasicLayout>
</template>

View File

@ -1,8 +0,0 @@
const BasicLayout = () => import('./basic.vue');
const IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);
const AuthPageLayout = () =>
import('#/layouts/authentication').then((m) => m.AuthPageLayout);
export { AuthPageLayout, BasicLayout, IFrameView };

View File

@ -1,3 +0,0 @@
export { default as Notification } from './notification.vue';
export type * from './types';

View File

@ -1,187 +0,0 @@
<script lang="ts" setup>
import type { NotificationItem } from './types';
import { Bell, MailCheck } from '@vben/icons';
import { $t } from '@vben/locales';
import {
VbenButton,
VbenIconButton,
VbenPopover,
VbenScrollbar,
} from '@vben-core/shadcn-ui';
import { useToggle } from '@vueuse/core';
interface Props {
/**
* 显示圆点
*/
dot?: boolean;
/**
* 消息列表
*/
notifications?: NotificationItem[];
}
defineOptions({ name: 'NotificationPopup' });
withDefaults(defineProps<Props>(), {
dot: false,
notifications: () => [],
});
const emit = defineEmits<{
clear: [];
makeAll: [];
read: [NotificationItem];
viewAll: [];
}>();
const [open, toggle] = useToggle();
function close() {
open.value = false;
}
function handleViewAll() {
emit('viewAll');
close();
}
function handleMakeAll() {
emit('makeAll');
}
function handleClear() {
emit('clear');
}
function handleClick(item: NotificationItem) {
emit('read', item);
}
</script>
<template>
<VbenPopover
v-model:open="open"
content-class="relative right-2 w-[360px] p-0"
>
<template #trigger>
<div class="flex-center mr-2 h-full" @click.stop="toggle()">
<VbenIconButton class="bell-button text-foreground relative">
<span
v-if="dot"
class="bg-primary absolute right-0.5 top-0.5 h-2 w-2 rounded"
></span>
<Bell class="size-4" />
</VbenIconButton>
</div>
</template>
<div class="relative">
<div class="flex items-center justify-between p-4 py-3">
<div class="text-foreground">{{ $t('widgets.notifications') }}</div>
<VbenIconButton
:tooltip="$t('widgets.markAllAsRead')"
@click="handleMakeAll"
>
<MailCheck class="size-4" />
</VbenIconButton>
</div>
<VbenScrollbar v-if="notifications.length > 0">
<ul class="!flex max-h-[360px] w-full flex-col">
<template v-for="item in notifications" :key="item.title">
<li
class="hover:bg-accent border-border relative flex w-full cursor-pointer items-start gap-5 border-t px-3 py-3"
@click="handleClick(item)"
>
<span
v-if="!item.isRead"
class="bg-primary absolute right-2 top-2 h-2 w-2 rounded"
></span>
<span
class="relative flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-blue-500 text-sm font-bold text-white"
>
<div
class="flex flex-wrap justify-center text-center leading-none"
>
<span
v-for="(char, index) in item.moduleTextArr"
:key="index"
class="w-1/2 p-0.5"
>
{{ char }}
</span>
</div>
</span>
<div class="flex flex-col gap-1 leading-none">
<p class="font-semibold">{{ item.title }}</p>
<p class="text-muted-foreground my-1 line-clamp-2 text-xs">
{{ item.message }}
</p>
<p class="text-muted-foreground line-clamp-2 text-xs">
{{ item.date }}
</p>
</div>
</li>
</template>
</ul>
</VbenScrollbar>
<template v-else>
<div class="flex-center text-muted-foreground min-h-[150px] w-full">
{{ $t('common.noData') }}
</div>
</template>
<div
class="border-border flex items-center justify-between border-t px-4 py-3"
>
<!-- <VbenButton size="sm" variant="ghost" @click="handleClear">
{{ $t('widgets.clearNotifications') }}
</VbenButton> -->
<div></div>
<VbenButton size="sm" @click="handleViewAll">
{{ $t('widgets.viewAll') }}
</VbenButton>
</div>
</div>
</VbenPopover>
</template>
<style scoped>
:deep(.bell-button) {
&:hover {
svg {
animation: bell-ring 1s both;
}
}
}
@keyframes bell-ring {
0%,
100% {
transform-origin: top;
}
15% {
transform: rotateZ(10deg);
}
30% {
transform: rotateZ(-10deg);
}
45% {
transform: rotateZ(5deg);
}
60% {
transform: rotateZ(-5deg);
}
75% {
transform: rotateZ(2deg);
}
}
</style>

View File

@ -1,9 +0,0 @@
interface NotificationItem {
avatar: string;
date: string;
isRead?: boolean;
message: string;
title: string;
}
export type { NotificationItem };

View File

@ -1,3 +0,0 @@
# locale
每个app使用的国际化可能不同这里用于扩展国际化的功能例如扩展 dayjs、antd组件库的多语言切换以及app本身的国际化文件。

View File

@ -1,94 +0,0 @@
import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
import type { Locale } from 'ant-design-vue/es/locale';
import type { App } from 'vue';
import { ref } from 'vue';
import { $t, setupI18n as coreSetup, loadLocalesMap } from '@vben/locales';
import { preferences } from '@vben/preferences';
import antdEnLocale from 'ant-design-vue/es/locale/en_US';
import antdDefaultLocale from 'ant-design-vue/es/locale/zh_CN';
import dayjs from 'dayjs';
const antdLocale = ref<Locale>(antdDefaultLocale);
const modules = import.meta.glob('./langs/*.json');
const localesMap = loadLocalesMap(modules);
/**
*
*
* @param lang
*/
async function loadMessages(lang: SupportedLanguagesType) {
const [appLocaleMessages] = await Promise.all([
localesMap[lang]?.(),
loadThirdPartyMessage(lang),
]);
return appLocaleMessages?.default;
}
/**
*
* @param lang
*/
async function loadThirdPartyMessage(lang: SupportedLanguagesType) {
await Promise.all([loadAntdLocale(lang), loadDayjsLocale(lang)]);
}
/**
* dayjs的语言包
* @param lang
*/
async function loadDayjsLocale(lang: SupportedLanguagesType) {
let locale;
switch (lang) {
case 'zh-CN': {
locale = await import('dayjs/locale/zh-cn');
break;
}
case 'en-US': {
locale = await import('dayjs/locale/en');
break;
}
// 默认使用英语
default: {
locale = await import('dayjs/locale/en');
}
}
if (locale) {
dayjs.locale(locale);
} else {
console.error(`Failed to load dayjs locale for ${lang}`);
}
}
/**
* antd的语言包
* @param lang
*/
async function loadAntdLocale(lang: SupportedLanguagesType) {
switch (lang) {
case 'zh-CN': {
antdLocale.value = antdDefaultLocale;
break;
}
case 'en-US': {
antdLocale.value = antdEnLocale;
break;
}
}
}
async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
await coreSetup(app, {
defaultLocale: preferences.app.locale,
loadMessages,
missingWarn: !import.meta.env.PROD,
...options,
});
}
export { $t, antdLocale, setupI18n };

View File

@ -1,8 +0,0 @@
{
"page": {
"demos": {
"title": "Demos",
"antd": "Ant Design Vue"
}
}
}

View File

@ -1,8 +0,0 @@
{
"page": {
"demos": {
"title": "演示",
"antd": "Ant Design Vue"
}
}
}

View File

@ -1,31 +0,0 @@
import { initPreferences } from '@vben/preferences';
import { unmountGlobalLoading } from '@vben/utils';
import { overridesPreferences } from './preferences';
/**
*
*/
async function initApplication() {
// name用于指定项目唯一标识
// 用于区分不同项目的偏好设置以及存储数据的key前缀以及其他一些需要隔离的数据
const env = import.meta.env.PROD ? 'prod' : 'dev';
const appVersion = import.meta.env.VITE_APP_VERSION;
const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`;
// app偏好设置初始化
await initPreferences({
namespace,
overrides: overridesPreferences,
});
// 启动应用并挂载
// vue应用主要逻辑及视图
const { bootstrap } = await import('./bootstrap');
await bootstrap(namespace);
// 移除并销毁loading
unmountGlobalLoading();
}
initApplication();

View File

@ -1,14 +0,0 @@
import type { App } from 'vue';
import FastCrud from '@fast-crud/fast-crud';
import ui from '@fast-crud/ui-antdv4';
import Antdv from 'ant-design-vue';
import '@fast-crud/fast-crud/dist/style.css';
import '@fast-crud/ui-antdv4/dist/style.css';
export function registerFastCrud(app: App) {
app.use(Antdv);
app.use(ui);
app.use(FastCrud, {
});
}

View File

@ -1,202 +0,0 @@
import type { App } from 'vue';
import VXETable from 'vxe-table'
import {
VxeTable,
VxeColumn,
VxeColgroup,
VxeGrid,
VxeToolbar
} from 'vxe-table'
import VxeUI from 'vxe-pc-ui'
import {
VxeAlert,
VxeAnchor,
VxeAnchorLink,
VxeBreadcrumb,
VxeBreadcrumbItem,
VxeButton,
VxeButtonGroup,
VxeCalendar,
VxeCard,
VxeCarousel,
VxeCheckbox,
VxeCheckboxGroup,
VxeCol,
VxeCollapse,
VxeCollapsePane,
VxeDatePicker,
VxeDrawer,
VxeForm,
VxeFormDesign,
VxeFormGather,
VxeFormItem,
VxeFormView,
VxeIcon,
VxeIconPicker,
VxeImage,
VxeImageGroup,
VxeImagePreview,
VxeInput,
VxeLayoutAside,
VxeLayoutBody,
VxeLayoutContainer,
VxeLayoutFooter,
VxeLayoutHeader,
VxeLink,
VxeListDesign,
VxeListView,
VxeList,
VxeLoading,
VxeMenu,
VxeModal,
VxeNumberInput,
VxeOptgroup,
VxeOption,
VxePager,
VxePasswordInput,
VxePrintPageBreak,
VxePrint,
VxePulldown,
VxeRadio,
VxeRadioButton,
VxeRadioGroup,
VxeRow,
VxeSelect,
VxeSwitch,
VxeTabPane,
VxeTabs,
VxeTag,
VxeText,
VxeTextarea,
VxeTip,
VxeTooltip,
VxeTree,
VxeTreeSelect,
VxeUpload
} from 'vxe-pc-ui'
import VXETablePluginExportXLSX from 'vxe-table-plugin-export-xlsx'
import ExcelJS from 'exceljs'
import VXETablePluginAntd from 'vxe-table-plugin-antd'
// 导入主题变量,也可以重写主题变量
import 'vxe-pc-ui/lib/style.css'
import 'vxe-table/lib/style.css'
import 'vxe-table/styles/cssvar.scss'
import 'vxe-pc-ui/styles/cssvar.scss'
// VxeUI.setTheme('dark')
VxeUI.component(VxeAlert)
VxeUI.component(VxeAnchor)
VxeUI.component(VxeAnchorLink)
VxeUI.component(VxeBreadcrumb)
VxeUI.component(VxeBreadcrumbItem)
VxeUI.component(VxeButton)
VxeUI.component(VxeButtonGroup)
VxeUI.component(VxeCalendar)
VxeUI.component(VxeCard)
VxeUI.component(VxeCarousel)
VxeUI.component(VxeCheckbox)
VxeUI.component(VxeCheckboxGroup)
VxeUI.component(VxeCol)
VxeUI.component(VxeCollapse)
VxeUI.component(VxeCollapsePane)
VxeUI.component(VxeDatePicker)
VxeUI.component(VxeDrawer)
VxeUI.component(VxeForm)
VxeUI.component(VxeFormDesign)
VxeUI.component(VxeFormGather)
VxeUI.component(VxeFormItem)
VxeUI.component(VxeFormView)
VxeUI.component(VxeIcon)
VxeUI.component(VxeIconPicker)
VxeUI.component(VxeImage)
VxeUI.component(VxeImageGroup)
VxeUI.component(VxeImagePreview)
VxeUI.component(VxeInput)
VxeUI.component(VxeLayoutAside)
VxeUI.component(VxeLayoutBody)
VxeUI.component(VxeLayoutContainer)
VxeUI.component(VxeLayoutFooter)
VxeUI.component(VxeLayoutHeader)
VxeUI.component(VxeLink)
VxeUI.component(VxeListDesign)
VxeUI.component(VxeListView)
VxeUI.component(VxeList)
VxeUI.component(VxeLoading)
VxeUI.component(VxeMenu)
VxeUI.component(VxeModal)
VxeUI.component(VxeNumberInput)
VxeUI.component(VxeOptgroup)
VxeUI.component(VxeOption)
VxeUI.component(VxePager)
VxeUI.component(VxePasswordInput)
VxeUI.component(VxePrintPageBreak)
VxeUI.component(VxePrint)
VxeUI.component(VxePulldown)
VxeUI.component(VxeRadio)
VxeUI.component(VxeRadioButton)
VxeUI.component(VxeRadioGroup)
VxeUI.component(VxeRow)
VxeUI.component(VxeSelect)
VxeUI.component(VxeSwitch)
VxeUI.component(VxeTabPane)
VxeUI.component(VxeTabs)
VxeUI.component(VxeTag)
VxeUI.component(VxeText)
VxeUI.component(VxeTextarea)
VxeUI.component(VxeTip)
VxeUI.component(VxeTooltip)
VxeUI.component(VxeTree)
VxeUI.component(VxeTreeSelect)
VxeUI.component(VxeUpload)
VxeUI.component(VxeTable)
VxeUI.component(VxeColumn)
VxeUI.component(VxeColgroup)
VxeUI.component(VxeGrid)
VxeUI.component(VxeToolbar)
VXETable.use(VXETablePluginAntd)
VXETable.use(VXETablePluginExportXLSX, {
ExcelJS
})
VXETable.setConfig({
// zIndex: 9999,
grid: {
size: 'mini',
proxyConfig: {
props: {
result: 'data.rows',
total: 'data.total',
},
},
toolbarConfig: {
enabled: true,
},
},
pager: {
background: true,
pageSize: 50,
pageSizes: [50, 100, 300, 500, 1000],
layouts: ['PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'Sizes', 'FullJump', 'Total'],
},
})
export function registerVxeTable(app: App) {
app.use(VxeUI)
app.use(VxeTable)
app.use(VxeColumn)
app.use(VxeColgroup)
app.use(VxeGrid)
app.use(VxeToolbar)
}

View File

@ -1,13 +0,0 @@
import { defineOverridesPreferences } from '@vben/preferences';
/**
* @description
* 使
*/
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
name: import.meta.env.VITE_APP_TITLE,
authPageLayout: 'panel-right',
},
});

View File

@ -1,42 +0,0 @@
import type {
ComponentRecordType,
GenerateMenuAndRoutesOptions,
} from '@vben/types';
import { generateAccessible } from '@vben/access';
import { preferences } from '@vben/preferences';
import { message } from 'ant-design-vue';
import { getAllMenusApi } from '#/api/system/menu';
import { BasicLayout, IFrameView } from '#/layouts';
import { $t } from '#/locales';
const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');
async function generateAccess(options: GenerateMenuAndRoutesOptions) {
const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');
const layoutMap: ComponentRecordType = {
BasicLayout,
IFrameView,
};
return await generateAccessible(preferences.app.accessMode, {
...options,
fetchMenuListAsync: async () => {
message.loading({
content: `${$t('common.loadingMenu')}...`,
duration: 1.5,
});
return await getAllMenusApi();
},
// 可以指定没有权限跳转403页面
forbiddenComponent,
// 如果 route.meta.menuVisibleWithForbidden = true
layoutMap,
pageMap,
});
}
export { generateAccess };

View File

@ -1,262 +0,0 @@
import type { Router } from 'vue-router';
import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
import { preferences } from '@vben/preferences';
import { useAccessStore, useUserStore } from '@vben/stores';
import { startProgress, stopProgress } from '@vben/utils';
import { useTitle } from '@vueuse/core';
import Apis from '#/api';
import { $t } from '#/locales';
import { coreRouteNames, dynamicRoutes } from '#/router/routes';
import { useAuthStore } from '#/store';
import { generateAccess } from './access';
/**
*
* @param router
*/
function setupCommonGuard(router: Router) {
// 记录已经加载的页面
const loadedPaths = new Set<string>();
router.beforeEach(async (to) => {
to.meta.loaded = loadedPaths.has(to.path);
// 页面加载进度条
if (!to.meta.loaded && preferences.transition.progress) {
startProgress();
}
return true;
});
router.afterEach((to) => {
// 记录页面是否加载,如果已经加载,后续的页面切换动画等效果不在重复执行
if (preferences.tabbar.enable) {
loadedPaths.add(to.path);
}
// 关闭页面加载进度条
if (preferences.transition.progress) {
stopProgress();
}
// 动态修改标题
if (preferences.app.dynamicTitle) {
const { title } = to.meta;
// useTitle(`${$t(title)} - ${preferences.app.name}`);
useTitle(`${$t(title)} - ${preferences.app.name}`);
}
});
}
/**
*
* permission.path = "/xx/edit" route.path = "/xx/edit/:id?" id可以为任意值meetingId roleId等
*/
function matchPaths(routePath, permissionPath) {
const routeParts = routePath.path.split('/');
const permissionParts = permissionPath.path.split('/');
if (routePath.name === permissionPath.id) {
return true;
}
if (permissionParts.length > routeParts.length) {
return false;
}
return routeParts.every((part, index) => {
return part === permissionParts[index] || part.startsWith(':');
});
}
// 过滤路由,只保留第三个数据源配置的路由
function filterRoutesByPermissions(routes, permissions, staticRouteKeys) {
const filteredRoutes = [];
for (const route of routes) {
// console.log('[ route ] >', route)
// console.log('[ permission.path ] >', permissions)
const permission = permissions.find((permission) =>
matchPaths(route, permission),
);
const isStaticRoute = staticRouteKeys.includes(route.name);
if (permission || isStaticRoute) {
const newRoute = { ...route };
if (permission) {
newRoute.meta = {
...newRoute.meta,
title: permission.name,
};
if (permission.order) {
newRoute.meta.order = permission.order;
}
}
if (route.children) {
newRoute.children = filterRoutesByPermissions(
route.children,
permissions,
staticRouteKeys,
);
}
filteredRoutes.push(newRoute);
// console.log(JSON.parse(JSON.stringify(filteredRoutes)));
}
}
return filteredRoutes;
}
/**
* 访
* @param router
*/
function setupAccessGuard(router: Router) {
router.beforeEach(async (to, from) => {
const accessStore = useAccessStore();
const userStore = useUserStore();
const authStore = useAuthStore();
// 基本路由,这些路由不需要进入权限拦截
if (coreRouteNames.includes(to.name as string)) {
if (to.path === LOGIN_PATH && accessStore.accessToken) {
return decodeURIComponent(
(to.query?.redirect as string) || DEFAULT_HOME_PATH,
);
}
return true;
}
// accessToken 检查
if (!accessStore.accessToken) {
// 明确声明忽略权限访问权限,则可以访问
if (to.meta.ignoreAccess) {
return true;
}
// 没有访问权限,跳转登录页面
if (to.fullPath !== LOGIN_PATH) {
return {
path: LOGIN_PATH,
// 如不需要,直接删除 query
query: { redirect: encodeURIComponent(to.fullPath) },
// 携带当前跳转的页面,登录后重新跳转该页面
replace: true,
};
}
return to;
}
// 是否已经生成过动态路由
if (accessStore.isAccessChecked) {
return true;
}
// 生成路由表
// 当前登录用户拥有的角色标识列表
const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());
const userRoles = userInfo.roles ?? [];
// debugger
// 二开从统一授权获取菜单key值遍历本地所有菜单进行添加
const staticRouteKeys = [
'Dashboard',
'home',
'User',
'UserCenter',
'UserTodo',
'IFrame',
'MeetingStandingBook',
'MeetingStart',
'DutyStandingBook',
'ContractInfo',
];
const r = await Apis.sys.user.functiontree.get_XTBGXT();
let originRouters = r.rows[0].children;
// 提取数据的函数
const extractData = (input: any[]) => {
const result: any[] = [];
function traverse(node: any) {
if (node.id && node.name) {
result.push({
id: node.id,
path: node.remark,
name: node.name,
order: node.showOrder || 0,
});
}
if (node.children && node.children.length > 0) {
for (const child of node.children) {
traverse(child);
}
}
}
for (const node of input) {
traverse(node);
}
return result;
};
// console.log('originRouters', originRouters)
originRouters = extractData(originRouters);
// console.log('originRouters', originRouters)
let finalRoutes = filterRoutesByPermissions(
dynamicRoutes,
originRouters,
staticRouteKeys,
);
console.log(originRouters);
// console.log('finalRoutes', finalRoutes)
// console.log('dynamicRoutes', dynamicRoutes)
// console.log('userInfo', userInfo)
if (userInfo.accountId == 'Admin.itl' || userInfo._isSkip) {
finalRoutes = dynamicRoutes;
}
// console.log(userInfo)
// 生成菜单和路由
const { accessibleMenus, accessibleRoutes } = await generateAccess({
roles: userRoles,
router,
// 则会在菜单中显示但是访问会被重定向到403
routes: finalRoutes,
});
// 保存菜单信息和路由信息
accessStore.setAccessMenus(accessibleMenus);
accessStore.setAccessRoutes(accessibleRoutes);
accessStore.setIsAccessChecked(true);
const redirectPath = (from.query.redirect ?? to.fullPath) as string;
return {
...router.resolve(decodeURIComponent(redirectPath)),
replace: true,
};
});
}
/**
*
* @param router
*/
function createRouterGuard(router: Router) {
/** 通用 */
setupCommonGuard(router);
/** 权限访问 */
setupAccessGuard(router);
}
export { createRouterGuard };

View File

@ -1,32 +0,0 @@
import {
createRouter,
createWebHashHistory,
createWebHistory,
} from 'vue-router';
import { resetStaticRoutes } from '@vben/utils';
import { createRouterGuard } from './guard';
import { routes } from './routes';
/**
* @zh_CN vue-router实例
*/
const router = createRouter({
history:
import.meta.env.VITE_ROUTER_HISTORY === 'hash'
? createWebHashHistory(import.meta.env.VITE_BASE)
: createWebHistory(import.meta.env.VITE_BASE),
// 应该添加到路由的初始路由列表。
routes,
scrollBehavior: () => ({ left: 0, top: 0 }),
// 是否应该禁止尾部斜杠。
// strict: true,
});
const resetRoutes = () => resetStaticRoutes(router, routes);
// 创建路由守卫
createRouterGuard(router);
export { resetRoutes, router };

View File

@ -1,114 +0,0 @@
import type { RouteRecordRaw } from 'vue-router';
import { DEFAULT_HOME_PATH } from '@vben/constants';
import { AuthPageLayout, BasicLayout, IFrameView } from '#/layouts';
import { $t } from '#/locales';
import Login from '#/views/_core/authentication/login.vue';
/** 全局404页面 */
const fallbackNotFoundRoute: RouteRecordRaw = {
component: () => import('#/views/_core/fallback/not-found.vue'),
meta: {
hideInBreadcrumb: true,
hideInMenu: true,
hideInTab: true,
title: '404',
},
name: 'FallbackNotFound',
path: '/:path(.*)*',
};
/** 基本路由,这些路由是必须存在的 */
const coreRoutes: RouteRecordRaw[] = [
{
meta: {
title: 'Root',
},
name: 'Root',
path: '/',
redirect: DEFAULT_HOME_PATH,
},
{
component: AuthPageLayout,
props: {
toolbar: false,
},
meta: {
title: 'Authentication',
},
name: 'Authentication',
path: '/auth',
children: [
{
name: 'Login',
path: 'login',
component: Login,
meta: {
title: $t('page.core.login'),
},
},
{
name: 'CodeLogin',
path: 'code-login',
component: () => import('#/views/_core/authentication/code-login.vue'),
meta: {
title: $t('page.core.codeLogin'),
},
},
{
name: 'QrCodeLogin',
path: 'qrcode-login',
component: () =>
import('#/views/_core/authentication/qrcode-login.vue'),
meta: {
title: $t('page.core.qrcodeLogin'),
},
},
{
name: 'ForgetPassword',
path: 'forget-password',
component: () =>
import('#/views/_core/authentication/forget-password.vue'),
meta: {
title: $t('page.core.forgetPassword'),
},
},
{
name: 'Register',
path: 'register',
component: () => import('#/views/_core/authentication/register.vue'),
meta: {
title: $t('page.core.register'),
},
},
],
},
{
component: IFrameView,
meta: {
icon: 'lucide:layout-dashboard',
order: 210,
title: 'iframe',
hideInMenu: true,
hideInTab: true,
},
name: 'IFrame',
path: '/iframe',
children: [
{
name: 'ContractInfo',
path: '/iframe/contract/info',
component: () => import('#/views/contract/iframe-info/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '合同明细信息',
},
},
],
},
];
export { coreRoutes, fallbackNotFoundRoute };

View File

@ -1,31 +0,0 @@
import type { RouteRecordRaw } from 'vue-router';
import { mergeRouteModules, traverseTreeValues } from '@vben/utils';
import { coreRoutes, fallbackNotFoundRoute } from './core';
const dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {
eager: true,
});
// 有需要可以自行打开注释,并创建文件夹
// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });
/** 动态路由 */
const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
/** 外部路由列表访问这些页面可以不需要Layout可能用于内嵌在别的系统 */
// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);
const externalRoutes: RouteRecordRaw[] = [];
/** 路由列表,由基本路由+静态路由组成 */
const routes: RouteRecordRaw[] = [
...coreRoutes,
...externalRoutes,
fallbackNotFoundRoute,
];
/** 基本路由列表,这些路由不需要进入权限拦截 */
const coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);
export { coreRouteNames, dynamicRoutes, routes };

View File

@ -1,537 +0,0 @@
import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '#/layouts';
const routes: RouteRecordRaw[] = [
{
component: BasicLayout,
meta: {
icon: 'lucide:layout-dashboard',
title: '合同配置',
},
name: 'HTGLHTPZ',
path: '/contract/config',
children: [
{
name: 'ContractConfigIndex',
path: '/contract/config',
component: () => import('#/views/contract/config/index.vue'),
meta: {
hideInMenu: true,
icon: 'lucide:area-chart',
title: '合同配置',
},
},
],
},
{
name: 'HTGLHTLX',
path: '/contract/approval',
component: BasicLayout,
meta: {
icon: 'lucide:area-chart',
title: '合同立项',
},
children: [
{
name: 'ContractApprovalEdit',
path: '/contract/approval/edit/:id?',
beforeEnter: (e) => {
console.log('e', e);
if (e.params.id && e.params.id === ':id') {
e.params.id = '';
e.fullPath = '/contract/approval/edit';
}
},
component: () => import('#/views/contract/approval/edit/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '立项申报',
activePath: '/contract/approval/edit/:id?',
},
},
{
name: 'ContractApprovalList',
path: '/contract/approval/list',
component: () => import('#/views/contract/approval/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '立项编制',
},
},
{
name: 'ContractApprovalTodo',
path: '/contract/approval/todo',
component: () => import('#/views/contract/approval/todo/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '立项提示',
},
},
{
name: 'ContractApprovalSigningBasis',
path: '/contract/approval/signing-basis',
component: () =>
import('#/views/contract/approval/signing-basis/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '签约依据维护',
},
},
],
},
{
name: 'HTGLHTXS',
path: '/contract/business',
component: BasicLayout,
meta: {
icon: 'lucide:area-chart',
title: '合同选商',
},
children: [
{
name: 'ContractBusinessEdit',
path: '/contract/business/edit/:id?',
component: () => import('#/views/contract/business/edit/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '选商填报',
activePath: '/contract/business/todo',
},
},
{
name: 'ContractBusinessResult',
path: '/contract/business/result/:id?',
component: () => import('#/views/contract/business/result/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '选商结果填报',
activePath: '/contract/business/todo',
},
},
{
name: 'ContractBusinessList',
path: '/contract/business/list',
component: () => import('#/views/contract/business/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '选商编制',
},
},
{
name: 'ContractBusinessResultList',
path: '/contract/business/result-list',
component: () =>
import('#/views/contract/business/result-list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '选商结果编制',
},
},
{
name: 'ContractBusinessTodo',
path: '/contract/business/todo',
component: () => import('#/views/contract/business/todo/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '选商提示',
},
},
],
},
{
name: 'HTGLHTSB',
path: '/contract/declaration',
component: BasicLayout,
meta: {
icon: 'lucide:area-chart',
title: '合同申报',
},
children: [
{
name: 'ContractDeclarationEdit',
path: '/contract/declaration/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
e.params.id = '';
e.fullPath = '/contract/declaration/edit';
}
},
component: () => import('#/views/contract/declaration/edit/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '申报填报',
activePath: '/contract/declaration/todo',
},
},
{
name: 'ContractDeclarationList',
path: '/contract/declaration/list',
component: () => import('#/views/contract/declaration/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '申报编制',
},
},
{
name: 'ContractDeclarationTodo',
path: '/contract/declaration/todo',
component: () => import('#/views/contract/declaration/todo/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '申报提示',
},
},
{
name: 'ContractDeclarationPrint',
path: '/contract/declaration/print',
component: () => import('#/views/contract/declaration/print/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '合同打印',
},
},
],
},
// {
// name: 'ContractAudit',
// path: '/contract/audit',
// component: BasicLayout,
// meta: {
// icon: 'lucide:area-chart',
// title: '合同审批',
// },
// children: [
// {
// name: 'ContractAuditTodo',
// path: '/contract/audit/todo',
// component: () => import('#/views/contract/audit/todo/index.vue'),
// meta: {
// icon: 'lucide:area-chart',
// title: '审批提示',
// },
// },
// {
// name: 'ContractAuditList',
// path: '/contract/audit/list',
// component: () => import('#/views/contract/audit/list/index.vue'),
// meta: {
// icon: 'lucide:area-chart',
// title: '审批查询',
// },
// },
// ],
// },
{
name: 'HTGLHTQD',
path: '/contract/sign',
component: BasicLayout,
meta: {
icon: 'lucide:area-chart',
title: '合同签订',
},
children: [
{
name: 'ContractSignEdit',
path: '/contract/sign/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
e.params.id = '';
e.fullPath = '/contract/sign/edit';
}
},
component: () => import('#/views/contract/sign/edit/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '签订填报',
activePath: '/contract/sign/todo',
},
},
{
name: 'ContractSignList',
path: '/contract/sign/list',
component: () => import('#/views/contract/sign/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '签订编制',
},
},
{
name: 'ContractSignTodo',
path: '/contract/sign/todo',
component: () => import('#/views/contract/sign/todo/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '签订提示',
},
},
],
},
{
name: 'HTGLHTLVX',
path: '/contract/perform',
component: BasicLayout,
meta: {
icon: 'lucide:area-chart',
title: '合同履行',
},
children: [
{
name: 'ContractPerformEdit',
path: '/contract/perform/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
e.params.id = '';
e.fullPath = '/contract/perform/edit';
}
},
component: () => import('#/views/contract/perform/edit/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '履行填报',
activePath: '/contract/perform/todo',
},
},
{
name: 'ContractPerformList',
path: '/contract/perform/list',
component: () => import('#/views/contract/perform/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '履行编制',
},
},
{
name: 'ContractPerformTodo',
path: '/contract/perform/todo',
component: () => import('#/views/contract/perform/todo/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '履行提示',
},
},
{
name: 'ContractPerformResult',
path: '/contract/perform/result',
component: () => import('#/views/contract/perform/result/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '履行结果填报',
},
},
{
name: 'ContractPerformResultList',
path: '/contract/perform/resultList',
component: () =>
import('#/views/contract/perform/result-list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '履行结果编制',
},
},
{
name: 'ContractPerformTemporaryArchive',
path: '/contract/perform/temporary-archive',
component: () =>
import('#/views/contract/perform/temporary-archive/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '临时归档',
},
},
],
},
{
name: 'HTGLHTGD',
path: '/contract/archive',
component: BasicLayout,
meta: {
icon: 'lucide:area-chart',
title: '合同归档',
},
children: [
{
name: 'ContractArchiveTodoArchive',
path: '/contract/archive/todo/archive',
component: () =>
import('#/views/contract/archive/todo/archive/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '合同归档',
},
},
{
name: 'ContractArchiveTodoRetracement',
path: '/contract/archive/todo/retracement',
component: () =>
import('#/views/contract/archive/todo/retracement/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '合同回档',
},
},
{
name: 'ContractArchiveList',
path: '/contract/archive/list',
component: () => import('#/views/contract/archive/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '归档查询',
},
},
],
},
{
name: 'HTGLHTQYSQ',
path: '/contract/sign-authorization',
component: BasicLayout,
meta: {
icon: 'lucide:area-chart',
title: '签约授权管理',
},
children: [
{
name: 'ContractSignAuthorizationEdit',
path: '/contract/sign-authorization/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
e.params.id = '';
e.fullPath = '/contract/sign-authorization/edit';
}
},
component: () =>
import('#/views/contract/sign-authorization/edit/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '签约授权申报',
activePath: '/contract/sign-authorization/edit/:id?',
},
},
{
name: 'ContractSignAuthorizationList',
path: '/contract/sign-authorization/list',
component: () =>
import('#/views/contract/sign-authorization/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '签约授权查询',
},
},
],
},
{
name: 'HTGLHTXDR',
path: '/contract/company',
component: BasicLayout,
meta: {
icon: 'lucide:area-chart',
title: '合同相对人',
},
children: [
{
name: 'ContractCompanyEdit',
path: '/contract/company/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
e.params.id = '';
e.fullPath = '/contract/company/edit';
}
},
component: () => import('#/views/contract/company/edit/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '相对人录入维护',
activePath: '/contract/company/edit/:id?',
},
},
{
name: 'ContractCompanyList',
path: '/contract/company/list',
component: () => import('#/views/contract/company/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '相对人查询',
},
},
],
},
// {
// name: 'ContractStatistic',
// path: '/contract/statistic',
// meta: {
// icon: 'lucide:area-chart',
// title: '统计分析',
// },
// children: [
// {
// name: 'ContractStatisticAnalysis',
// path: '/contract/statistic/analysis',
// beforeEnter: (e) => {
// if (e.params.id && e.params.id === ':id') {
// e.params.id = ''
// e.fullPath = '/contract/company/edit'
// }
// },
// component: () => import('#/views/contract/company/edit/index.vue'),
// meta: {
// icon: 'lucide:area-chart',
// title: '统计分析',
// },
// },
// {
// name: 'ContractStatisticAbrogateList',
// path: '/contract/statistic/abrogate-list',
// component: () => import('#/views/contract/company/list/index.vue'),
// meta: {
// icon: 'lucide:area-chart',
// title: '废除查询',
// },
// },
// ],
// },
// {
// name: 'ContractPrint',
// path: '/contract/statistic',
// meta: {
// icon: 'lucide:area-chart',
// title: '统计分析',
// },
// children: [
// {
// name: 'ContractPrintBusiness',
// path: '/contract/print/business',
// component: () => import('#/views/contract/company/edit/index.vue'),
// meta: {
// icon: 'lucide:area-chart',
// title: '统计分析',
// },
// },
// {
// name: 'ContractPrintAbrogateList',
// path: '/contract/print/abrogate-list',
// component: () => import('#/views/contract/company/list/index.vue'),
// meta: {
// icon: 'lucide:area-chart',
// title: '废除查询',
// },
// },
// ],
// },
];
export default routes;

View File

@ -1,49 +0,0 @@
import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '#/layouts';
const routes: RouteRecordRaw[] = [
{
component: BasicLayout,
meta: {
icon: 'lucide:layout-dashboard',
order: -1,
title: '首页',
},
name: 'Dashboard',
path: '/home',
children: [
{
name: 'home',
path: '/home',
component: () => import('#/views/dashboard/home/index.vue'),
meta: {
affixTab: true,
hideInMenu: true,
icon: 'lucide:area-chart',
title: '首页',
},
},
// {
// name: 'Analytics',
// path: '/analytics',
// component: () => import('#/views/dashboard/analytics/index.vue'),
// meta: {
// affixTab: true,
// icon: 'lucide:area-chart',
// title: $t('page.dashboard.analytics'),
// },
// },
// {
// name: 'Workspace',
// path: '/workspace',
// component: () => import('#/views/dashboard/workspace/index.vue'),
// meta: {
// title: $t('page.dashboard.workspace'),
// },
// },
],
},
];
export default routes;

View File

@ -1,29 +0,0 @@
import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '#/layouts';
const routes: RouteRecordRaw[] = [
{
component: BasicLayout,
meta: {
icon: 'lucide:layout-dashboard',
order: 10,
title: '系统管理',
},
name: 'System',
path: '/system',
children: [
{
name: 'Dict',
path: '/system/dict',
component: () => import('#/views/system/dict/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '字典管理',
},
},
],
},
];
export default routes;

View File

@ -1,51 +0,0 @@
import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '#/layouts';
const routes: RouteRecordRaw[] = [
{
component: BasicLayout,
meta: {
hideInMenu: true,
icon: 'lucide:layout-dashboard',
order: -1,
title: '用户中心',
},
name: 'User',
path: '/user',
children: [
{
name: 'UserTodo',
path: '/user/todo',
component: () => import('#/views/user-center/todo/index.vue'),
meta: {
hideInMenu: true,
icon: 'lucide:area-chart',
title: '消息通知',
},
},
{
name: 'UserCenter',
path: '/user/center',
component: () => import('#/views/user-center/center/index.vue'),
meta: {
hideInMenu: true,
icon: 'lucide:area-chart',
title: '个人中心',
},
},
{
name: 'About',
path: '/about',
component: () => import('#/views/_core/about/index.vue'),
meta: {
hideInMenu: true,
icon: 'lucide:area-chart',
title: '关于',
},
},
],
},
];
export default routes;

View File

@ -1,130 +0,0 @@
import type { LoginAndRegisterParams } from '@vben/common-ui';
import type { UserInfo } from '@vben/types';
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
import { notification } from 'ant-design-vue';
import { defineStore } from 'pinia';
import { getUserInfoApi, loginApi } from '#/api/system/auth';
import { $t } from '#/locales';
export const useAuthStore = defineStore('auth', () => {
const accessStore = useAccessStore();
const userStore = useUserStore();
const router = useRouter();
const loginLoading = ref(false);
let loginInfo = localStorage.getItem('loginInfo') || '{}';
/**
*
* Asynchronously handle the login process
* @param params
*/
async function authLogin(
params: LoginAndRegisterParams,
onSuccess?: () => Promise<void> | void,
) {
// 异步处理用户登录操作并获取 accessToken
let userInfo: null | UserInfo = null;
try {
loginLoading.value = true;
if (params.username == 'Admin.itl' || params._isSkip) {
} else {
params.username = `${params.username}.RL`;
}
const loginRes = await loginApi({
...params,
appId: 'HTGL',
appName: '合同管理系统',
appSecret: 'r1og4wiyrrvr4qvw2aafhgvy',
});
console.log(loginRes);
if (params._isSkip) {
loginRes._isSkip = params._isSkip;
}
loginInfo = JSON.stringify(loginRes);
localStorage.setItem('loginInfo', loginInfo);
const { accessToken } = loginRes;
// 如果成功获取到 accessToken
if (accessToken) {
accessStore.setAccessToken(accessToken);
// 获取用户信息并存储到 accessStore 中
const [fetchUserInfoResult] = await Promise.all([fetchUserInfo()]);
userInfo = fetchUserInfoResult;
if (params._isSkip) {
userInfo._isSkip = params._isSkip;
}
userStore.setUserInfo(userInfo);
if (accessStore.loginExpired) {
accessStore.setLoginExpired(false);
} else {
onSuccess
? await onSuccess?.()
: await router.push(userInfo.homePath || DEFAULT_HOME_PATH);
}
if (userInfo?.realName) {
notification.success({
description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,
duration: 3,
message: $t('authentication.loginSuccess'),
});
}
}
} finally {
loginLoading.value = false;
}
return {
userInfo,
};
}
async function logout(redirect: boolean = true) {
// await logoutApi();
resetAllStores();
accessStore.setLoginExpired(false);
// 回登陆页带上当前路由地址
await router.replace({
path: LOGIN_PATH,
query: redirect
? {
redirect: encodeURIComponent(router.currentRoute.value.fullPath),
}
: {},
});
}
async function fetchUserInfo() {
let userInfo: null | UserInfo = null;
userInfo = await getUserInfoApi();
userInfo = { ...JSON.parse(loginInfo), ...userInfo };
userStore.setUserInfo(userInfo);
return userInfo;
}
function $reset() {
localStorage.removeItem('loginInfo');
loginLoading.value = false;
}
return {
$reset,
authLogin,
fetchUserInfo,
loginLoading,
logout,
};
});

View File

@ -1,202 +0,0 @@
import { computed, ref } from 'vue';
import { defineStore } from 'pinia';
// import { getDictDataList } from '@/api/system/dict';
import Apis from '#/api';
import dataModule from '#/utils/dict/static.data';
const DICT_STORAGE_KEY = 'DICT_KEY';
interface DictDataVO {
dictType: string;
label: string;
value: null | number | string;
colorType: string;
cssClass: string;
}
export const useDictStore = defineStore('app-dict', () => {
/** 是否初始化字典,是的话每次应用自动加载,后续走缓存,否的话每次请求 */
const initDict = ref(true);
/** 字典合集仅initDict为true时生效 */
const dictMap = ref<Record<string, DictDataVO[]>>({});
/** 是否已设置字典合集仅initDict为true时生效 */
const isSetDict = ref(false);
/** 每次新查询字典时的查询缓存,单位:秒 主要用于循环获取数据显示label的场景建议不低于10s */
const expireAfterSeconds = ref(30);
/** 获取所有字典数据 */
const getDictMap = computed(() => dictMap.value);
/** 判断是否已设置字典表 */
const getIsSetDict = computed(() => isSetDict.value);
/**
*
*
* @returns
*/
const setDictMap = async (): Promise<boolean> => {
try {
// 模拟网络请求
// await new Promise((resolve) => setTimeout(resolve, 2000));
const data = await Apis.dictData.get_page({
params: { pageNum: 1, pageSize: 10_000 },
});
const dictDataMap: Record<string, DictDataVO[]> = {};
// 处理静态字典数据
Object.keys(dataModule).forEach((dictType) => {
const dictEntries = dataModule[dictType];
dictEntries.data.forEach((dictData) => {
dictData.type = dictType;
if (!dictDataMap[dictType]) {
dictDataMap[dictType] = [];
}
dictDataMap[dictType].push({
value: dictData.value,
label: dictData.name,
colorType: dictData.colorType,
cssClass: dictData.cssClass,
...dictData,
} as DictDataVO);
});
});
// 处理动态字典数据
data?.rows.forEach((dictData: any) => {
if (!dictDataMap[dictData.type]) dictDataMap[dictData.type] = [];
dictDataMap[dictData.type].push({
value: dictData.value,
label: dictData.name,
colorType: dictData.colorType,
cssClass: dictData.cssClass,
...dictData,
} as DictDataVO);
});
console.log('[ dictDataMap ] >', dictDataMap);
dictMap.value = dictDataMap;
isSetDict.value = true;
return true;
} catch (error) {
console.error('字典数据获取失败:', error);
return false;
}
};
/** 获取字典数据 输入字典数组,输出包含对应类型的字典对象 */
const getDictData = async (
dictTypeArr: string[],
): Promise<Record<string, DictDataVO[]>> => {
const newDictMap: Record<string, DictDataVO[]> = {};
return await new Promise((resolve) => {
if (
initDict.value &&
isSetDict.value &&
Object.keys(dictMap.value).length > 0
) {
dictTypeArr.forEach((dictType) => {
newDictMap[dictType] = dictMap.value[dictType] || [];
});
resolve(newDictMap);
}
// if (!isSetDict.value) {
// console.warn('字典数据尚未加载,正在等待...');
// const checkInterval = setInterval(() => {
// console.warn('字典数据加载中...');
// if (isSetDict.value) {
// console.warn('字典数据完成.');
// clearInterval(checkInterval);
// dictTypeArr.forEach((dictType) => {
// newDictMap[dictType] = dictMap.value[dictType] || [];
// });
// resolve(newDictMap);
// }
// }, 45);
// }
// try {
// return {};
// } catch (error) {
// console.error('getDictMap 函数报错:', error);
// return {};
// }
resolve(newDictMap);
});
};
/**
* 30使
*
* @returns Array
*/
const getDictInfo = async (dictType: string): Promise<DictDataVO[]> => {
const StorageKey = `${DICT_STORAGE_KEY}:${dictType}`;
try {
localStorage.setItem(StorageKey, JSON.stringify(dictMap.value));
const dictDataMap = (await getDictData([dictType])) || {};
setTimeout(() => {
localStorage.removeItem(StorageKey);
}, expireAfterSeconds.value * 1000);
return JSON.parse(JSON.stringify(dictDataMap[dictType])) || [];
} catch (error) {
console.error('getDictInfo函数报错', error);
return [];
}
};
/**
* 30使
*
* @returns DictDataVO
*/
const getDictDataInfo = async (
dictType: string,
value: string,
): Promise<DictDataVO> => {
const dictDataMap = (await getDictInfo(dictType)) || [];
return (
dictDataMap.find((item) => item.value === value) || ({} as DictDataVO)
);
};
/**
* 30使
*
* @returns DictDataVO
*/
const getDictDataLabel = async (
dictType: string,
value: string,
): Promise<string> => {
const dictDataMap = (await getDictInfo(dictType)) || [];
const info =
dictDataMap.find((item) => item.value === value) || ({} as DictDataVO);
return info.label;
};
function $reset() {
// loginLoading.value = false;
}
return {
initDict,
dictMap,
isSetDict,
expireAfterSeconds,
getDictMap,
getIsSetDict,
setDictMap,
getDictData,
getDictInfo,
getDictDataInfo,
getDictDataLabel,
$reset,
};
});

View File

@ -1,2 +0,0 @@
export * from './auth';
export * from './dict'

View File

@ -1,226 +0,0 @@
/** 数据字典工具类 */
import { computed } from 'vue';
import Apis from '#/api';
import { useDictStore } from '#/store/dict';
import dataModule from '#/utils/dict/static.data';
export * from './shared';
const dictStore = useDictStore();
const dictData = computed(() => {
return dictStore.dictMap;
});
/**
* dictType
*
* @param dictType
* @returns {any | Array}
*/
export interface DictDataType {
dictType?: string;
label: string;
value: boolean | null | number | string;
key?: any;
colorType?: string;
cssClass?: string;
isDefault?: boolean;
}
export interface DictDataOptions {
label?: any;
value?: null | number | string;
}
export function getDictDatas(dictType: string) {
return dictData.value[dictType] || [];
}
export function getDictOpts(dictType: string) {
/**
* Tag getDictOptions来处理
*
* bugfix: dictOption.push({ ...dict, value: parseInt(dict.value + '') })
*/
return getDictDatas(dictType);
}
export async function getDictDatasAsync(
dictTypeParams: { type: string; valueType?: string }[],
) {
const dictDataMap: Record<string, DictDataType[]> = {};
const foundTypes = new Set<string>();
// 处理静态字典数据
for (const dictType of Object.keys(dataModule)) {
const dictParam = dictTypeParams.find((d) => d.type === dictType);
if (dictParam) {
const dictEntries = dataModule[dictType];
if (dictEntries && dictEntries.data && dictEntries.data.length > 0) {
dictEntries.data.forEach((dictData) => {
dictData.type = dictType;
if (!dictDataMap[dictType]) {
dictDataMap[dictType] = [];
}
dictDataMap[dictType].push({
...dictData,
value: dictData.value,
label: dictData.label,
colorType: dictData.colorType,
cssClass: dictData.cssClass,
} as DictDataType);
});
foundTypes.add(dictType);
}
// 如果所有类型都已找到,提前返回
if (foundTypes.size === dictTypeParams.length) {
return dictDataMap;
}
}
}
// 并行获取远程字典数据
const promises = dictTypeParams.map(async ({ type, valueType }) => {
if (!foundTypes.has(type)) {
try {
const data = await Apis.dictData.get_page({
params: { type },
});
dictDataMap[type] = (data.rows || []).map((dictData: any) => ({
value: convertValue(dictData.value, valueType),
label: dictData.name,
colorType: dictData.colorType,
cssClass: dictData.cssClass,
}));
} catch (error) {
console.error(`Failed to fetch data for type ${type}:`, error);
}
}
});
await Promise.all(promises);
return dictDataMap;
}
export function getDictOptions(
dictType: string,
valueType?: 'boolean' | 'number' | 'string',
): any[] {
const dictOption: DictDataType[] = [];
valueType ||= 'string';
const dictOptions: DictDataType[] = dictData.value[dictType] || [];
if (dictOptions && dictOptions.length > 0) {
dictOptions.forEach((dict: DictDataType) => {
dictOption.push({
...dict,
key: dict.value,
value: convertValue(dict.value, valueType),
});
});
}
return dictOption;
}
function convertValue(value, type) {
switch (type) {
case 'boolean': {
return value === 'true';
}
case 'number': {
return Number.parseInt(value, 10);
}
case 'string': {
return String(value);
}
default: {
return value;
}
}
}
export async function getDictOptionsAsync(
dictType: string,
valueType: 'boolean' | 'number' | 'string' = 'string',
): Promise<DictDataType[]> {
try {
const response = await getDictDatasAsync([
{ type: dictType, valueType: valueType },
]);
const dictOptions: DictDataType[] = response[dictType] || [];
return dictOptions.map((dict: DictDataType) => ({
...dict,
key: dict.value,
value: convertValue(dict.value, valueType),
}));
} catch (error) {
console.error('Error fetching dictionary data:', error);
return [];
}
}
/** 获取指定 value 的字典数据 */
export function getDictObj(dictType: string, value: any): DictDataType | null {
const dictOptions: DictDataType[] = getDictDatas(dictType);
if (dictOptions) {
if (value) {
return (
dictOptions.find(
(dict: DictDataType) => dict.value === value.toString(),
) || null
);
}
return null;
} else {
return null;
}
}
/** 获取指定 value 的字典数据 */
export function getDictObjByOptions(
options: DictDataType[],
value: any,
): DictDataType | null {
if (options) {
if (value) {
const result = options.find((dict: DictDataType) => dict.value === value);
return result || null;
}
return null;
} else {
return null;
}
}
/** 获取指定 value 的字典数据 */
export async function getDictObjAsync(
dictType: string,
value: any,
): Promise<DictDataType | null> {
const dictOptions = await getDictOptionsAsync(dictType);
if (dictOptions) {
if (value) {
return (
dictOptions.find(
(dict: DictDataType) => dict.value === value.toString(),
) || null
);
}
return null;
} else {
return null;
}
}
/** 获取字典默认数据 */
export function getDictDefaultObj(dictType: string): DictDataType | null {
const dictOptions: DictDataType[] = getDictDatas(dictType);
return dictOptions
? dictOptions.find((dict: DictDataType) => dict.isDefault == '1') ||
dictOptions[0]
: null;
}

View File

@ -1,61 +0,0 @@
export enum DICT_TYPE {
/** 系统通用状态 */
sys_normal_disable = 'sys_normal_disable',
/** 合同管理-资金流向 */
contract_fund_flow = 'contract_fund_flow',
/** 合同管理-资金渠道 */
contract_funding_source = 'contract_funding_source',
/** 合同管理-组织形式 */
contract_organization_form = 'contract_organization_form',
/** 合同管理-币种单位 */
contract_currency_unit = 'contract_currency_unit',
/** 合同管理-合同模块 */
contract_module = 'contract_module',
/** 合同管理-选商方式 */
contract_selection_method = 'contract_selection_method',
/** 合同管理-合同审批 */
contract_approval = 'contract_approval',
/** 合同管理-履行状态 */
contract_performance_status = 'contract_performance_status',
/** 合同管理-授权类型 */
contract_authorization_type = 'contract_authorization_type',
/** 合同管理-项目类型 */
contract_project_type = 'contract_project_type',
/** 合同管理-商务计价方式 */
contract_price_style = 'contract_price_style',
/** 综合管理-项目管理 */
comprehensive_project = 'comprehensive_project',
/** 综合管理-项目名称管理 */
comprehensive_project_name = 'comprehensive_project_name',
comprehensive_config = 'comprehensive_config',
/** 合同管理-签约依据类型 */
contract_basis_type = 'contract_basis_type',
/** 合同管理-合同相对人性质 */
counterparty_nature = 'counterparty_nature',
/** 变更原因 */
cancel_reson = 'cancel_reson',
/** 划分标段 */
section_type = 'section_type',
/** 标段数 */
section_num = 'section_num',
/** 常用是否 */
common_whether = 'common_whether',
/** 履行期限 */
deadline_for_performance = 'deadline_for_performance',
/** 纠纷解决方式 */
dispute_settlement_methods = 'dispute_settlement_methods',
/** 付款性质 */
payment_nature = 'payment_nature',
/** 合同立项节点流程 */
contract_approval_flow_node = 'contract_approval_flow_node',
/** 合同选商节点流程 */
contract_business_flow_node = 'contract_business_flow_node',
/** 合同立项节点流程 */
contract_abolish_flow_node = 'contract_abolish_flow_node',
/** 合同授权类型 */
contract_authorization_type2 = 'contract_authorization_type2',
/** 合同授权期限 */
contract_authorization_period = 'contract_authorization_period',
/** 合同待办类型 */
contract_todo_type = 'contract_todo_type'
}

View File

@ -1,123 +0,0 @@
const createEntry = (annotation = '', data = []) => ({
annotation,
data,
});
export default {
sys_normal_disable: createEntry('系统通用状态'),
contract_fund_flow: createEntry('合同管理-资金流向'),
contract_funding_source: createEntry('合同管理-资金渠道'),
contract_organization_form: createEntry('合同管理-组织形式'),
contract_currency_unit: createEntry('合同管理-币种单位'),
contract_module: createEntry('合同管理-合同模块'),
contract_selection_method: createEntry('合同管理-选商方式'),
contract_approval: createEntry('合同管理-合同审批'),
contract_performance_status: createEntry('合同管理-履行状态'),
contract_authorization_type: createEntry('合同管理-授权类型'),
contract_project_type: createEntry('合同管理-项目类型'),
contract_price_style: createEntry('合同管理-商务计价方式'),
comprehensive_project: createEntry('综合管理-项目管理'),
comprehensive_project_name: createEntry('综合管理-项目名称管理'),
comprehensive_config: createEntry(),
contract_basis_type: createEntry('合同管理-签约依据类型'),
counterparty_nature: createEntry('合同管理-合同相对人性质'),
cancel_reson: createEntry('变更原因', [
{ label: '未填写原因', value: '0' },
{ label: '用户取消', value: '1' },
{ label: '系统取消', value: '2' },
{ label: '其他原因', value: '3' },
]),
section_type: createEntry('划分标段', [
{ label: '是', value: '1' },
{ label: '否', value: '0' },
]),
section_num: createEntry('标段数', [
{ label: '1', value: '1' },
{ label: '2', value: '2' },
{ label: '3', value: '3' },
{ label: '4', value: '4' },
{ label: '5', value: '5' },
{ label: '6', value: '6' },
{ label: '7', value: '7' },
{ label: '8', value: '8' },
]),
common_whether: createEntry('常用是否', [
{ label: '是', value: '1' },
{ label: '否', value: '0' },
]),
deadline_for_performance: createEntry('履行期限', [
{ label: '确定', value: '1' },
{ label: '不确定', value: '0' },
]),
dispute_settlement_methods: createEntry('纠纷解决方式', [
{ label: '诉讼', value: '1' },
{ label: '仲裁', value: '2' },
{ label: '其它', value: '3' },
]),
payment_nature: createEntry('付款性质', [
{ label: '结算款', value: '1' },
{ label: '其它', value: '3' },
]),
contract_approval_flow_node: createEntry('合同立项节点流程', [
{ label: '开始节点', value: 'paStart' },
{ label: '立项编制', value: 'paEdit' },
{ label: '立项审批中', value: 'paApproval' },
{ label: '选商编制', value: 'smEdit' },
{ label: '选商审批中', value: 'smApproval' },
{ label: '选商结果编制', value: 'smrEdit' },
{ label: '结束', value: 'end' },
]),
contract_business_flow_node: createEntry('合同选商节点流程', [
{ label: '开始节点', value: 'smStart' },
{ label: '待编制', value: 'smEdit' },
{ label: '待部门自审', value: 'smDepartmentAudit' },
{ label: '待计划规划部审查', value: 'smPlanningDepartment' },
{ label: '待财务资产部审查', value: 'smFinancialDepartment' },
{ label: '待合规审查(企管法规部)', value: 'smRegulationDepartment' },
{ label: '待主管领导审批', value: 'smManager' },
{ label: '待公司领导审核', value: 'smLeaders' },
{ label: '选商结果填报', value: 'smrEdit' },
{ label: '结束', value: 'end' },
]),
contract_abolish_flow_node: createEntry('合同立项节点流程', [
{ label: '待提交', value: 'edit' },
{ label: '待部门审核', value: 'departmentAudit' },
{ label: '已结束', value: 'end' },
{ label: '废除', value: 'abolishEdit' },
]),
// 授权类型
contract_authorization_type2: createEntry('合同授权类型', [
{ label: '长期授权', value: '0' },
{ label: '单项授权', value: '1' },
]),
// 授权期限
contract_authorization_period: createEntry('合同授权期限', [
{ label: '确定', value: '0' },
{ label: '不确定', value: '1' },
]),
// 合同待办类型
contract_todo_type: createEntry('合同待办类型', [
{ label: '合同立项', value: 'contractSetup' },
{ label: '合同选商', value: 'selectMerchant' },
{ label: '合同申报', value: 'contractDeclare' },
{ label: '合同签订', value: 'contractSign' },
{ label: '合同履行', value: 'contractPerform' },
{ label: '合同归档', value: 'contractFile' },
]),
};

View File

@ -1,101 +0,0 @@
import { message, type UploadProps } from "ant-design-vue";
import Apis from '#/api';
export class FileUploader {
fileList = [] as UploadProps['fileList'];
uploading = false;
constructor(params: any) {
}
select = async (fileUuids: string) => {
return new Promise<void>(async (resolve, reject) => {
Apis.attachment.get_list({
params: { uuid: fileUuids }
}).then((data) => {
let files = [] as UploadProps['fileList'];
for (const element of data.rows) {
files?.push({
uid: element.fileUuid,
name: element.fileName,
status: 'done',
url: element.fileUrl,
})
}
resolve(files)
}).catch(e => {
reject()
})
})
}
remove: UploadProps['onRemove'] = file => {
if (this.fileList) {
const index = this.fileList.indexOf(file);
const newFileList = this.fileList.slice();
newFileList.splice(index, 1);
this.fileList = newFileList;
}
};
upload = async (files?: UploadProps['fileList'], data?: any) => {
return new Promise<void>(async (resolve, reject) => {
if (this.fileList) {
const formData = new FormData();
if (data && Object.keys(data).length) {
Object.keys(data).forEach((key) => {
formData.append(key, data[key]);
});
}
let file = files ? files : this.fileList;
let alreadyUploaded = [] as string[];
file.forEach((file: UploadProps['fileList'][number]) => {
if (file.originFileObj) {
formData.append('files', file.originFileObj as any);
} else {
alreadyUploaded.push(file.uid)
}
});
this.uploading = true;
// You can use any AJAX library you like
try {
this.fileList = [];
this.uploading = false;
let files = []
for (const element of alreadyUploaded) {
files.push({
fileUuid: element,
})
}
const filesCount = formData.getAll('files').length;
if (filesCount > 0) {
let data = await Apis.attachment.post_uploads({
data: formData,
})
files = files.concat(data.rows)
message.success('上传成功.');
}
resolve(files || [])
} catch (error) {
this.uploading = false;
reject()
message.error('上传失败.');
} finally {
this.uploading = false;
}
}
reject()
});
};
}

View File

@ -1,220 +0,0 @@
import { h, unref } from 'vue';
import type { App, Component, Plugin } from 'vue';
import { cloneDeep, isObject } from 'lodash-es';
/** 递归组装菜单格式 */
export function generatorMenu(routerMap: Array<any>) {
return filterRouter(routerMap).map(item => {
const isRoot = isRootRouter(item);
const info = isRoot ? item.children[0] : item;
const currentMenu = {
...info,
...info.meta,
label: info.meta?.title,
key: info.name,
icon: isRoot ? item.meta?.icon : info.meta?.icon
};
// 是否有子菜单,并递归处理
if (info.children && info.children.length > 0) {
// Recursion
currentMenu.children = generatorMenu(info.children);
}
return currentMenu;
});
}
/** 混合菜单 */
export function generatorMenuMix(routerMap: Array<any>, routerName: string, location: string) {
const cloneRouterMap = cloneDeep(routerMap);
const newRouter = filterRouter(cloneRouterMap);
if (location === 'header') {
const firstRouter: any[] = [];
newRouter.forEach(item => {
const isRoot = isRootRouter(item);
const info = isRoot ? item.children[0] : item;
info.children = undefined;
const currentMenu = {
...info,
...info.meta,
label: info.meta?.title,
key: info.name
};
firstRouter.push(currentMenu);
});
return firstRouter;
}
return getChildrenRouter(newRouter.filter(item => item.name === routerName));
}
/** 递归组装子菜单 */
export function getChildrenRouter(routerMap: Array<any>) {
return filterRouter(routerMap).map(item => {
const isRoot = isRootRouter(item);
const info = isRoot ? item.children[0] : item;
const currentMenu = {
...info,
...info.meta,
label: info.meta?.title,
key: info.name
};
// 是否有子菜单,并递归处理
if (info.children && info.children.length > 0) {
// Recursion
currentMenu.children = getChildrenRouter(info.children);
}
return currentMenu;
});
}
/** 判断根路由 Router */
export function isRootRouter(item) {
return item.meta?.alwaysShow != true && item?.children?.filter(item => !item?.meta?.hidden)?.length === 1;
}
export const withInstall = <T extends Component>(component: T, alias?: string) => {
const comp = component as any;
comp.install = (app: App) => {
app.component(comp.name || comp.displayName, component);
if (alias) {
app.config.globalProperties[alias] = component;
}
};
return component as T & Plugin;
};
/** 找到对应的节点 */
let result = null;
export function getTreeItem(data: any[], key?: string | number): any {
data.map(item => {
if (item.key === key) {
result = item;
} else if (item.children && item.children.length) {
getTreeItem(item.children, key);
}
});
return result;
}
/** 找到所有节点 */
const treeAll: any[] = [];
export function getTreeAll(data: any[]): any[] {
data.map(item => {
treeAll.push(item.key);
if (item.children && item.children.length) {
getTreeAll(item.children);
}
});
return treeAll;
}
// dynamic use hook props
export function getDynamicProps<T extends {}, U>(props: T): Partial<U> {
const ret: Recordable = {};
Object.keys(props).map(key => {
ret[key] = unref((props as Recordable)[key]);
});
return ret as Partial<U>;
}
export function deepMerge<T = any>(src: any = {}, target: any = {}): T {
let key: string;
for (key in target) {
src[key] = isObject(src[key]) ? deepMerge(src[key], target[key]) : (src[key] = target[key]);
}
return src;
}
/**
* Sums the passed percentage to the R, G or B of a HEX color
*
* @param {string} color The color to change
* @param {number} amount The amount to change the color by
* @returns {string} The processed part of the color
*/
function addLight(color: string, amount: number) {
const cc = Number.parseInt(color, 16) + amount;
const c = cc > 255 ? 255 : cc;
return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`;
}
/**
* Lightens a 6 char HEX color according to the passed percentage
*
* @param {string} color The color to change
* @param {number} amount The amount to change the color by
* @returns {string} The processed color represented as HEX
*/
export function lighten(color: string, amount: number) {
color = color.includes('#') ? color.substring(1, color.length) : color;
amount = Math.trunc((255 * amount) / 100);
return `#${addLight(color.substring(0, 2), amount)}${addLight(
color.substring(2, 4),
amount
)}${addLight(color.substring(4, 6), amount)}`;
}
/** 判断是否 url */
export function isUrl(url: string) {
return /^(http|https):\/\//g.test(url);
}
/**
*
*
* @param {Array} arrayData
* @param {Object} treeProps { id:"_id", parent_id:"parent_id",
* children:"children",need_field:["_id","name"],deleteParentId:true }
* @returns {Array} treeData
*/
export function arrayToTree(originalArrayData, treeProps) {
const arrayData = cloneDeep(originalArrayData);
let { id = '_id', parent_id = 'parent_id', children = 'children', deleteParentId = false, need_field } = treeProps;
const result = [];
const temp = {};
for (let i = 0; i < arrayData.length; i++) {
temp[arrayData[i][id]] = arrayData[i]; // 以id作为索引存储元素可以无需遍历直接定位元素
}
for (let j = 0; j < arrayData.length; j++) {
const currentElement = arrayData[j];
const newCurrentElement = {};
if (need_field) {
need_field = uniqueArr(need_field.concat([id, parent_id, children]));
for (const keyName in currentElement) {
if (!need_field.includes(keyName)) {
delete currentElement[keyName];
}
}
}
const tempCurrentElementParent = temp[currentElement[parent_id]]; // 临时变量里面的当前元素的父元素
if (tempCurrentElementParent) {
// 如果存在父元素
if (!tempCurrentElementParent[children]) {
// 如果父元素没有chindren键
tempCurrentElementParent[children] = []; // 设上父元素的children键
}
if (deleteParentId) {
delete currentElement[parent_id];
}
tempCurrentElementParent[children].push(currentElement); // 给父元素加上当前元素作为子元素
} else {
// 不存在父元素,意味着当前元素是一级元素
result.push(currentElement);
}
}
return result;
}
// 最简单数组去重法
export function uniqueArr(array) {
const n = []; // 一个新的临时数组
// 遍历当前数组
for (let i = 0; i < array.length; i++) {
// 如果当前数组的第i已经保存进了临时数组那么跳过
// 否则把当前项push到临时数组里面
if (!n.includes(array[i])) n.push(array[i]);
}
return n;
}

View File

@ -1,44 +0,0 @@
export const logger = {
log(level: string, message: any, error?: any) {
const timestamp = new Date().toISOString();
const stack = error ? error.stack : '';
const formattedMessage = `[${timestamp}] [${level}] ${message} ${stack}`;
switch (level) {
case 'DEBUG': {
console.debug(formattedMessage);
break;
}
case 'ERROR':
case 'FATAL': {
console.error(formattedMessage);
break;
}
case 'INFO': {
console.info(formattedMessage);
break;
}
case 'WARN': {
console.warn(formattedMessage);
break;
}
default: {
console.log(formattedMessage);
}
}
},
debug(message: any) {
this.log('DEBUG', message);
},
info(message: any) {
this.log('INFO', message);
},
warn(message: any) {
this.log('WARN', message);
},
error(message: any, error: any) {
this.log('ERROR', message, error);
},
fatal(message: any, error: any) {
this.log('FATAL', message, error);
},
};

View File

@ -1,68 +0,0 @@
import dayjs from 'dayjs';
/**
*
* @param dateStr YYYY-MM 2024-06,
*/
export function getMonthStartAndEnd(dateStr?: string) {
if (!dateStr) {
dateStr = dayjs().format('YYYY-MM');
}
// 验证输入格式是否正确
const regex = /^\d{4}-\d{2}$/;
if (!regex.test(dateStr)) {
throw new Error('日期字符串格式不正确,应为 YYYY-MM');
}
// 使用 split 方法分割字符串
const [year, month] = dateStr.split('-').map(Number);
// 获取指定月份的第一天
const firstDayOfMonth = dayjs(new Date(year, month - 1, 1))
.startOf('month')
.format('YYYY-MM-DD');
// 获取指定月份的最后一天
const lastDayOfMonth = dayjs(new Date(year, month - 1, 1))
.endOf('month')
.format('YYYY-MM-DD');
return [firstDayOfMonth, lastDayOfMonth];
}
export function shortcuts(params?: any) {
return {
: () => {
const now = dayjs().valueOf();
return [
dayjs(now).startOf('month').valueOf(),
dayjs(now).endOf('month').valueOf(),
] as const;
},
: () => {
const now = dayjs().valueOf();
return [dayjs(now).subtract(7, 'day').valueOf(), now] as const;
},
: () => {
const now = dayjs().valueOf();
return [dayjs(now).subtract(1, 'month').valueOf(), now] as const;
},
: () => {
const now = dayjs().valueOf();
return [dayjs(now).subtract(3, 'month').valueOf(), now] as const;
},
: () => {
const now = dayjs().valueOf();
return [dayjs(now).subtract(6, 'month').valueOf(), now] as const;
},
: () => {
const now = dayjs().valueOf();
return [dayjs(now).subtract(1, 'year').valueOf(), now] as const;
},
: () => {
const now = dayjs().valueOf();
return [dayjs(now).startOf('year').valueOf(), now] as const;
},
};
}

View File

@ -1,3 +0,0 @@
# \_core
此目录包含应用程序正常运行所需的基本视图。这些视图是应用程序布局中使用的视图。

View File

@ -1,9 +0,0 @@
<script lang="ts" setup>
import { About } from '@vben/common-ui';
defineOptions({ name: 'About' });
</script>
<template>
<About />
</template>

View File

@ -1,30 +0,0 @@
<script lang="ts" setup>
import type { LoginCodeParams } from '@vben/common-ui';
import { ref } from 'vue';
import { AuthenticationCodeLogin } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
defineOptions({ name: 'CodeLogin' });
const loading = ref(false);
/**
* 异步处理登录操作
* Asynchronously handle the login process
* @param values 登录表单数据
*/
async function handleLogin(values: LoginCodeParams) {
// eslint-disable-next-line no-console
console.log(values);
}
</script>
<template>
<AuthenticationCodeLogin
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleLogin"
/>
</template>

View File

@ -1,23 +0,0 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { AuthenticationForgetPassword } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
defineOptions({ name: 'ForgetPassword' });
const loading = ref(false);
function handleSubmit(value: string) {
// eslint-disable-next-line no-console
console.log('reset email:', value);
}
</script>
<template>
<AuthenticationForgetPassword
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleSubmit"
/>
</template>

View File

@ -1,101 +0,0 @@
<script lang="ts" setup>
import type { VbenFormSchema } from '@vben/common-ui';
import type { BasicOption } from '@vben/types';
import { computed } from 'vue';
import { AuthenticationLogin, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { useAuthStore } from '#/store';
defineOptions({ name: 'Login' });
const authStore = useAuthStore();
const MOCK_USER_OPTIONS: BasicOption[] = [
{
label: '超级管理员',
value: 'vben',
},
{
label: '管理员',
value: 'admin',
},
{
label: '用户',
value: 'jack',
},
];
const formSchema = computed((): VbenFormSchema[] => {
return [
{
component: 'VbenInput',
componentProps: {
class: 'w-full',
placeholder: $t('authentication.usernameTip'),
},
dependencies: {
trigger(values, form) {
if (values.selectAccount) {
const findUser = MOCK_USER_OPTIONS.find(
(item) => item.value === values.selectAccount,
);
if (findUser) {
form.setValues({
password: '123456',
username: findUser.value,
});
}
}
},
triggerFields: ['selectAccount'],
},
fieldName: 'username',
label: $t('authentication.username'),
rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
},
{
component: 'VbenInputPassword',
componentProps: {
placeholder: $t('authentication.password'),
},
fieldName: 'password',
label: $t('authentication.password'),
rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
},
];
});
const isDev = import.meta.env.MODE === 'development';
function mockLogin(username: string, password: string, isSkip: boolean = true) {
authStore.authLogin({
username,
password,
_isSkip: isSkip,
});
}
</script>
<template>
<div class="w-[90%]">
<AuthenticationLogin
:form-schema="formSchema"
:loading="authStore.loginLoading"
@submit="authStore.authLogin"
/>
</div>
<div v-if="isDev">
<p class="text-center">快速登录</p>
<a-space>
<a-button @click="mockLogin('Admin.itl', 'ABC123')">超级管理员</a-button>
<a-button @click="mockLogin('zhangxs.itl', 'Rlgs!6243910')">zxs</a-button>
<a-button @click="mockLogin('zengp.itl', 'Rlgs!6243910')">zp</a-button>
<a-button @click="mockLogin('rlqym', 'Rlgs!6243910', false)">
rlqym
</a-button>
</a-space>
</div>
</template>

View File

@ -1,10 +0,0 @@
<script lang="ts" setup>
import { AuthenticationQrCodeLogin } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
defineOptions({ name: 'QrCodeLogin' });
</script>
<template>
<AuthenticationQrCodeLogin :login-path="LOGIN_PATH" />
</template>

View File

@ -1,25 +0,0 @@
<script lang="ts" setup>
import type { LoginAndRegisterParams } from '@vben/common-ui';
import { ref } from 'vue';
import { AuthenticationRegister } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
defineOptions({ name: 'Register' });
const loading = ref(false);
function handleSubmit(value: LoginAndRegisterParams) {
// eslint-disable-next-line no-console
console.log('register submit:', value);
}
</script>
<template>
<AuthenticationRegister
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleSubmit"
/>
</template>

View File

@ -1,7 +0,0 @@
<script lang="ts" setup>
import { Fallback } from '@vben/common-ui';
</script>
<template>
<Fallback status="coming-soon" />
</template>

View File

@ -1,9 +0,0 @@
<script lang="ts" setup>
import { Fallback } from '@vben/common-ui';
defineOptions({ name: 'Fallback403Demo' });
</script>
<template>
<Fallback status="403" />
</template>

View File

@ -1,9 +0,0 @@
<script lang="ts" setup>
import { Fallback } from '@vben/common-ui';
defineOptions({ name: 'Fallback500Demo' });
</script>
<template>
<Fallback status="500" />
</template>

View File

@ -1,9 +0,0 @@
<script lang="ts" setup>
import { Fallback } from '@vben/common-ui';
defineOptions({ name: 'Fallback404Demo' });
</script>
<template>
<Fallback status="404" />
</template>

View File

@ -1,9 +0,0 @@
<script lang="ts" setup>
import { Fallback } from '@vben/common-ui';
defineOptions({ name: 'FallbackOfflineDemo' });
</script>
<template>
<Fallback status="offline" />
</template>

View File

@ -1,186 +0,0 @@
import { dict } from '@fast-crud/fast-crud';
import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict';
import { filterContractTypes } from '#/views/contract/utils';
export function getFormSchema(params: any = {}) {
const { contractTypeData, readOnly = false } = params;
return {
contractName: {
title: '合同名称',
key: 'contractName',
col: { span: 24 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
disabled: readOnly,
},
rules: [{ required: true, message: '请输入合同名称' }],
},
ctrType: {
title: '合同类别',
key: 'ctrType',
col: { span: 12 },
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[200px]',
prototype: true,
dict: dict({
async getData(_context) {
return filterContractTypes(contractTypeData, '-1');
},
}),
disabled: readOnly,
},
valueChange: {
immediate: true, // 是否立即执行一次
handle({ form, value, getComponentRef }) {
form.ctrTwoType = undefined;
console.log(getComponentRef('ctrTwoType'));
getComponentRef('ctrTwoType').reloadDict(); // 执行city的select组件的reloadDict()方法触发“city”重新加载字典
},
},
rules: [{ required: true, message: '请选择合同类别' }],
},
ctrTwoType: {
title: '二级类别',
key: 'ctrTwoType',
col: { span: 12 },
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[200px]',
prototype: true,
dict: dict({
async getData({ form = {} }) {
console.log(form);
return filterContractTypes(contractTypeData, form.ctrType);
},
}),
disabled: readOnly,
},
rules: [{ required: true, message: '请选择二级类别' }],
},
frameProtocol: {
title: '框架协议',
key: 'frameProtocol',
col: { span: 8 },
component: {
name: 'fs-dict-radio',
vModel: 'value',
dict: dict({
data: getDictOptions(DICT_TYPE.common_whether),
}),
disabled: readOnly,
},
rules: [{ required: true, message: '请选择框架协议' }],
},
frameProtocolCtr: {
title: '框架协议下的合同',
key: 'frameProtocolCtr',
col: { span: 12 },
labelCol: { style: { width: '200px' } },
component: {
name: 'fs-dict-radio',
vModel: 'value',
dict: dict({
data: getDictOptions(DICT_TYPE.common_whether),
}),
disabled: readOnly,
},
rules: [{ required: true, message: '请选择框架协议下的合同' }],
},
fundAllocation: {
title: '资金流向',
key: 'fundAllocation',
col: { span: 12 },
component: {
name: 'fs-dict-select',
vModel: 'value',
allowClear: false,
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_fund_flow),
}),
disabled: readOnly,
},
valueChange: {
immediate: true, // 是否立即执行一次
handle({ form }) {
form.fundAllocationName = getDictObj(
DICT_TYPE.contract_fund_flow,
form.fundAllocation,
)?.label;
},
},
rules: [{ required: true, message: '请选择资金流向' }],
},
fundDitch: {
title: '资金渠道',
key: 'fundDitch',
col: { span: 12 },
component: {
name: 'fs-dict-select',
vModel: 'value',
allowClear: false,
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_funding_source),
}),
disabled: readOnly,
},
rules: [{ required: true, message: '请选择资金渠道' }],
},
budgetSum: {
title: '预算金额',
key: 'budgetSum',
col: { span: 8 },
colon: false,
component: {
name: 'a-input-number',
vModel: 'value',
class: 'w-full',
min: 0,
disabled: readOnly,
},
},
priceType: {
title: '',
key: 'priceType',
col: { span: 6 },
labelCol: { style: { width: '12px' } },
colon: false,
component: {
name: 'fs-dict-select',
vModel: 'value',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_currency_unit),
}),
disabled: readOnly,
},
},
organiza: {
title: '组织形式',
key: 'organiza',
col: { span: 24 },
component: {
name: 'fs-dict-radio',
vModel: 'value',
allowClear: false,
class: 'min-w-[180px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contract_organization_form, 'number'),
}),
disabled: readOnly,
},
rules: [{ required: true, message: '请选择组织形式' }],
},
fileList: {
title: '相关附件',
key: 'fileList',
},
};
}

View File

@ -1,829 +0,0 @@
<script setup lang="ts">
import { computed, nextTick, onMounted, reactive, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
import { MdiAdd, MdiUpload } from '@vben/icons';
import { useUserStore } from '@vben/stores';
import { message, Modal, type UploadChangeParam } from 'ant-design-vue';
import { logger } from 'common-utils';
import Apis from '#/api';
import temporaryFormModal from '#/components/temporary-form-modal/temporary-form-modal.vue';
import { useVxeTable } from '#/hooks/vxeTable';
import { DICT_TYPE, getDictObj } from '#/utils/dict';
import { FileUploader } from '#/utils/file';
import AuditNodeTable from '#/views/contract/components/audit-node-table/audit-node-table.vue';
import chooseUserModal from '#/views/system/user/choose-user-modal.vue';
import chooseSigningBasisModal from '../signing-basis/choose-signing-basis-modal.vue';
import { getColumns } from '../signing-basis/columns';
import { getFormSchema } from './curd';
const { xGridRef, gridProps } = useVxeTable({ ref: 'xGridRef' });
const [ChooseUserModal, chooseUserModalApi] = useVbenModal({
connectedComponent: chooseUserModal,
});
const [ChooseSigningBasisModal, chooseSigningBasisModalApi] = useVbenModal({
connectedComponent: chooseSigningBasisModal,
});
const [TemporaryFormModal, temporaryFormModalApi] = useVbenModal({
connectedComponent: temporaryFormModal,
});
const userStore = useUserStore();
const userInfo = computed(() => userStore.userInfo);
const fileUploader = new FileUploader({});
const router = useRouter();
const route = useRoute();
const id = ref(route.params.id);
const taskId = route.query.taskId;
const auditId = ref();
const pageRef = ref();
const currData = ref<any>({});
const formRef = ref();
const isLoading = ref(false);
const contractTypeData = ref<any[]>([]);
const formBinding = ref({
col: { span: 24 },
initialForm: {
contractName: '',
frameProtocol: '0',
frameProtocolCtr: '0',
priceType: 'CNY',
},
labelCol: { style: { width: '120px' } },
columns: {},
});
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
height: '200px',
columns: getColumns(),
data: [],
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
},
}),
);
const collapses = ['1', '2', '3'];
const collapseActiveKey = ref(collapses);
function areArraysEqualUnordered(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
const sortedArr1 = [...arr1].sort();
const sortedArr2 = [...arr2].sort();
return JSON.stringify(sortedArr1) === JSON.stringify(sortedArr2);
}
const isFold = computed(() => {
return !areArraysEqualUnordered(collapses, collapseActiveKey.value);
});
function handleFold() {
collapseActiveKey.value = isFold.value ? collapses : [];
}
function handleBack() {
Modal.confirm({
title: '提示',
content: `是否确认返回上一页面?`,
onOk: async () => {
back();
},
});
}
/**
* 页面返回并关闭tab
*/
function back() {
router.replace('/contract/approval/todo');
}
function handleOpenSignBasisChooseModal() {
//
const tableFullData = xGridRef.value?.getTableData().fullData;
if (tableFullData && tableFullData.length > 0) {
chooseSigningBasisModalApi.setData({
title: '选择签约依据',
guids: tableFullData.map((item) => item.guid) || [],
});
} else {
chooseSigningBasisModalApi.setData({
title: '选择签约依据',
guids: [],
});
}
chooseSigningBasisModalApi.open();
}
const handleChange = (info: UploadChangeParam) => {
formRef.value.setFormData({
fileList: info.fileList.length > 0 ? info.fileList : [],
});
};
function removeRow(row) {
const $grid = xGridRef.value;
if ($grid) {
$grid.remove(row);
message.success('移除成功');
}
}
const userModalOpenType = ref<'abolish' | 'audit'>('audit');
const currAuditType = ref<'abolish' | 'audit'>('audit');
const userListByAbolish = ref([]);
async function handleAbolish(type: 'confirm' | 'openModal') {
userModalOpenType.value = 'abolish';
if (type === 'openModal') {
Modal.confirm({
title: '提示',
content: '是否确认作废该合同?确认后该合同无法再次使用',
okType: 'danger',
onOk: async () => {
chooseUserModalApi.setData({
title: '选择立项废除审批人',
userIds: [],
});
chooseUserModalApi.open();
},
});
}
if (type === 'confirm') {
const hideLoading = message.loading('提交中...', 0);
try {
await Apis.contractBaseInfo.post_abolishFlowStart({
data: {
guid: currData.value.guid,
assigneeList: userListByAbolish.value.map((item) => item.ACCOUNT_ID),
},
});
} catch (error) {
logger.error('立项废除提交失败', error);
} finally {
hideLoading();
}
}
}
async function handleAbolishAudit(
type: 'access' | 'accessConfirm' | 'reject' | 'rejectConfirm',
data?: any,
) {
console.log(type);
if (type === 'access') {
Modal.confirm({
title: '提示',
content: '是否确认立项废除审核通过?',
onOk: () => {
temporaryFormModalApi.setData({
title: '备注信息',
schema: {
columns: {
comment: {
title: '',
key: 'comment',
col: { span: 24 },
colon: false,
component: {
name: 'a-textarea',
vModel: 'value',
autoSize: { minRows: 4, maxRows: 6 },
placeholder: '请输入',
},
rules: [{ required: true, message: '请输入退回原因' }],
},
},
},
});
temporaryFormModalApi.open();
},
});
}
if (type === 'accessConfirm') {
try {
await Apis.contractBaseInfo.post_abolishSubmit({
params: {
guid: id.value,
},
data: {
// appId: id.value,
taskId,
nodeId: '',
comment: '通过',
},
});
message.success('审核通过');
back();
} catch (error) {
logger.error('审核通过失败', error);
message.error('审核通过失败,请稍候再试');
}
}
if (type === 'reject') {
Modal.confirm({
title: '提示',
content: '是否确认拒绝废除该立项?',
onOk: () => {
temporaryFormModalApi.setData({
title: '退回原因',
schema: {
columns: {
comment: {
title: '',
key: 'comment',
col: { span: 24 },
colon: false,
component: {
name: 'a-textarea',
vModel: 'value',
autoSize: { minRows: 4, maxRows: 6 },
placeholder: '请输入',
},
rules: [{ required: true, message: '请输入退回原因' }],
},
},
},
});
temporaryFormModalApi.open();
},
});
}
if (type === 'rejectConfirm') {
const comment = data.comment;
try {
await Apis.contractBaseInfo.post_rollback({
params: {
guid: id.value,
},
data: {
appId: id.value,
taskId,
nodeId: '',
comment,
},
});
temporaryFormModalApi.close();
message.success('退回成功');
back();
} catch (error) {
logger.error('合同立项退回失败', error);
message.error('退回失败,请稍候再试');
}
}
}
function handleDelete() {
Modal.confirm({
title: '提示',
content: '是否确认删除该条记录?',
okType: 'danger',
onOk: async () => {
await Apis.contractBaseInfo.post_deletes({
params: { ids: currData.value.guid },
});
message.success('删除成功');
back();
},
});
}
function loadDataByContractTypeData() {}
function handleChooseConfirm(rows) {
const $grid = xGridRef.value;
//
if ($grid) {
$grid.remove();
$grid.insert(rows);
} else {
console.error('xGridRef不存在');
}
}
async function handleChooseUserConfirm(e) {
chooseUserModalApi.close();
isLoading.value = true;
if (userModalOpenType.value === 'abolish') {
userListByAbolish.value = e;
handleAbolish('confirm');
return;
}
try {
await Apis.contractBaseInfo.post_applyFlowStart({
data: {
guid: id.value,
assigneeList: e.map((item) => item.ACCOUNT_ID),
},
});
message.success('提交成功');
back();
} catch (error) {
logger.error('合同立项提交失败', error);
message.error('提交失败,请稍候再试');
} finally {
isLoading.value = false;
}
}
async function handleSave() {
try {
await formRef.value.submit();
} catch {
message.error('请完成必填项的填写');
return;
}
try {
isLoading.value = true;
let newForm: any = {};
//
const tableFullData = xGridRef.value?.getTableData().fullData;
if (tableFullData && tableFullData.length > 0) {
newForm.basisId = tableFullData[0].basisId;
} else {
message.error('请选择签约依据');
return;
}
//
const fileList = formRef.value.form.fileList;
let files: any = [];
if (fileList && fileList.length > 0) {
files = await fileUploader.upload(fileList, { source: 'ht' });
}
if (files) {
newForm.fileUuid = (files.map((item) => item.fileUuid) || []).join(',');
}
newForm = Object.assign({}, formRef.value.form, newForm);
delete newForm.fileList;
// name
for (const item of contractTypeData.value) {
if (item.contrLevelId === newForm.ctrType) {
newForm.ctrTypeName = item.contrLevelName;
}
if (item.contrLevelId === newForm.ctrTwoType) {
newForm.ctrTwoTypeName = item.contrLevelName;
}
}
newForm.fundDitchName = getDictObj(
DICT_TYPE.contract_funding_source,
newForm.fundDitch,
)?.label;
newForm.priceTypeName = getDictObj(
DICT_TYPE.contract_currency_unit,
newForm.priceType,
)?.label;
newForm.contractMoney = newForm.budgetSum;
newForm.currentContStepId = 0;
console.log(newForm);
// let result = await Apis.contractBaseInfo.post_apply({ data: newForm });
let result: any = {};
result = await Apis.contractBaseInfo.post_apply({ data: newForm });
id.value = result.value;
auditId.value = result.value;
message.success('保存成功');
Modal.confirm({
title: '提示',
content: '保存成功!是否进行提交?',
onOk: () => {
handleSubmit();
},
onCancel: () => {
// back();
},
});
} catch (error) {
message.error('提交失败,请稍候再试');
logger.error('立项结果报错失败', error);
} finally {
isLoading.value = false;
}
}
async function handleSubmit() {
// flowinstanceid ,退
if (currData.value.flowInstanceId) {
auditType.value = 'access';
handleAudit('confirm');
return;
}
userModalOpenType.value = 'audit';
// isLoading.value = true
chooseUserModalApi.setData({
title: '选择审批人',
userIds: [],
});
chooseUserModalApi.open();
}
let auditType = ref('');
const isTemporaryFormModalLoading = ref(false);
async function handleAudit(
type: 'confirm' | 'openAccessModal' | 'openRejectModal',
data?: any,
) {
console.log(type);
if (type === 'openAccessModal') {
auditType.value = 'access';
temporaryFormModalApi.setData({
title: '审核通过备注',
schema: {
columns: {
comment: {
title: '',
key: 'comment',
col: { span: 24 },
colon: false,
component: {
name: 'a-textarea',
vModel: 'value',
autoSize: { minRows: 4, maxRows: 6 },
placeholder: '请输入',
},
},
},
},
});
temporaryFormModalApi.open();
}
if (type === 'confirm' && auditType.value === 'access') {
isTemporaryFormModalLoading.value = true;
const comment = data.comment;
try {
await Apis.contractBaseInfo.post_submit({
params: {
guid: id.value,
},
data: {
appId: id.value,
taskId,
nodeId: '',
comment: comment || '',
},
});
message.success('审核通过');
temporaryFormModalApi.close();
back();
} catch (error) {
logger.error('审核通过失败', error);
message.error('审核通过失败,请稍候再试');
} finally {
isTemporaryFormModalLoading.value = false;
}
}
if (type === 'openRejectModal') {
auditType.value = 'reject';
temporaryFormModalApi.setData({
title: '审核退回原因',
schema: {
columns: {
comment: {
title: '',
key: 'comment',
col: { span: 24 },
colon: false,
component: {
name: 'a-textarea',
vModel: 'value',
autoSize: { minRows: 4, maxRows: 6 },
placeholder: '请输入',
},
rules: [{ required: true, message: '请输入退回原因' }],
},
},
},
});
temporaryFormModalApi.open();
}
if (type === 'confirm' && auditType.value === 'reject') {
isTemporaryFormModalLoading.value = true;
const comment = data.comment;
try {
await Apis.contractBaseInfo.post_rollback({
params: {
guid: id.value,
},
data: {
appId: id.value,
taskId,
nodeId: '',
comment,
},
});
temporaryFormModalApi.close();
message.success('退回成功');
back();
} catch (error) {
logger.error('合同立项退回失败', error);
message.error('退回失败,请稍候再试');
} finally {
isTemporaryFormModalLoading.value = false;
}
}
}
onMounted(async () => {
isLoading.value = true;
try {
const contractReferTypeData: any = await Apis.contractReferType.get_list({
params: {},
});
contractTypeData.value = contractReferTypeData.rows || [];
if (id.value) {
const data: any = await Apis.contractBaseInfo.get_getOne({
params: { guid: id.value },
});
auditId.value = id.value;
currData.value = data || {};
formBinding.value.columns = getFormSchema({
contractTypeData: contractTypeData.value,
readOnly: !id.value || currData.value.step !== 'paEdit',
});
xGridRef.value!.reloadColumn(
getColumns({
readOnly: !id.value || currData.value.step !== 'paEdit',
}),
);
nextTick(() => {
console.log(formRef.value);
formRef.value.setFormData(data);
});
//
if (data.basisId) {
const basisList = await Apis.lxBasisSale.get_page({
params: { basisId: data.basisId },
});
nextTick(() => {
xGridRef.value!.insert(basisList.rows);
});
}
if (data.fileUuid) {
const files = await fileUploader.select(data.fileUuid);
nextTick(() => {
formRef.value.setFormData({
fileList: files,
});
});
}
loadDataByContractTypeData();
} else {
formBinding.value.columns = getFormSchema({
contractTypeData: contractTypeData.value,
readOnly: false,
});
}
} catch (error) {
logger.error('获取合同信息失败', error);
Modal.error({
title: '提示',
content: '当前合同信息不存在',
onOk() {
back();
},
});
} finally {
isLoading.value = false;
}
});
</script>
<template>
<Page ref="pageRef" content-class="h-full flex flex-col">
<ChooseUserModal
class="w-[950px]"
multiple
@confirm="handleChooseUserConfirm"
/>
<ChooseSigningBasisModal class="w-[950px]" @confirm="handleChooseConfirm" />
<TemporaryFormModal
v-model:loading="isTemporaryFormModalLoading"
class="w-[700px]"
@confirm="handleAudit('confirm', $event)"
/>
<!-- {{ currData.step }} -->
<a-affix
:offset-top="0"
:style="{ zIndex: 50 }"
:target="() => pageRef.bodyRef"
>
<div class="flex w-full flex-row bg-white pl-1 pt-1">
<a-space class="flex-1">
<vben-button
v-if="!id || ['paEdit'].includes(currData.step) || !taskId"
variant="primary"
@click="handleSave()"
>
保存
</vben-button>
<vben-button
v-if="!id || ['paEdit'].includes(currData.step) || !taskId"
:disabled="!auditId"
variant="primary"
@click="handleSubmit()"
>
提交
</vben-button>
<vben-button
v-if="['paApproval'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="primary"
@click="handleAudit('openAccessModal')"
>
通过
</vben-button>
<vben-button
v-if="['paApproval'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="destructive"
@click="handleAudit('openRejectModal')"
>
退回
</vben-button>
<!-- <vben-button
v-if="
id &&
!['edit', 'setupDepartmentAudit'].includes(currData.step) &&
currData.inputUserId === userInfo!.userId
"
variant="destructive"
@click="handleAbolish('openModal')"
>
废除
</vben-button> -->
<vben-button
v-if="id && ['paEdit'].includes(currData.step)"
variant="destructive"
@click="handleDelete()"
>
删除
</vben-button>
<!-- <vben-button
v-if="['abolishDepartmentAudit'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="warning"
@click="handleAbolishAudit('accessConfirm')"
>
废除通过
</vben-button> -->
<!-- <vben-button
v-if="['abolishDepartmentAudit'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="destructive"
@click="handleAbolishAudit('accessConfirm')"
>
废除拒绝
</vben-button>
<vben-button
v-if="['departmentAudit'].includes(currData.step) && taskId"
:disabled="!auditId"
variant="primary"
@click="handleAudit('accessConfirm')"
>
通过
</vben-button> -->
<vben-button variant="secondary" @click="handleBack()">
返回
</vben-button>
</a-space>
<vben-button variant="secondary" @click="handleFold()">
一键{{ isFold ? '展开' : '收起' }}
</vben-button>
</div>
</a-affix>
<a-spin :spinning="isLoading">
<div class="mx-auto overflow-auto py-2">
<a-collapse v-model:active-key="collapseActiveKey" :bordered="false">
<a-collapse-panel key="1" class="w-full" header="基本信息">
<fs-form ref="formRef" class="w-full" v-bind="formBinding">
<template #form_fileList="scope">
<a-upload
v-model:file-list="scope.form.fileList"
:before-upload="() => false"
:max-count="3"
accept=".pdf,.ppt,.pptx"
name="file"
@change="handleChange"
>
<a-button v-if="!id || currData.step === 'edit'">
<MdiUpload />
点击上传
</a-button>
</a-upload>
</template>
</fs-form>
</a-collapse-panel>
<a-collapse-panel key="2" class="w-full" header="签约依据">
<template #extra>
<a-button
v-if="!id || currData.step === 'edit'"
type="primary"
@click.stop="handleOpenSignBasisChooseModal()"
>
<MdiAdd class="mr-0.5 text-lg" />
选择签约依据
</a-button>
</template>
<VxeGrid ref="xGridRef" v-bind="gridOptions" class="">
<template #toolbar_buttons></template>
<template #operate="{ row }">
<a-space>
<a-button
v-if="!id || currData.step === 'edit'"
class="text-red-500"
size="small"
type="text"
@click="removeRow(row)"
>
移除
</a-button>
</a-space>
</template>
</VxeGrid>
</a-collapse-panel>
<a-collapse-panel
v-if="currData.flowInstanceId"
key="3"
class="w-full"
header="审批信息"
>
<AuditNodeTable :flow-instance-id="currData.flowInstanceId" />
</a-collapse-panel>
</a-collapse>
</div>
</a-spin>
</Page>
</template>
<style scoped></style>

View File

@ -1,205 +0,0 @@
import type { VxeGridPropTypes } from 'vxe-table';
import { dict } from '@fast-crud/fast-crud';
import { useRender } from '#/hooks/useRender';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import { getContractTypes } from '#/views/contract/utils';
export const PrimaryKey = 'guid';
export function getColumns(_params: any = {}): VxeGridPropTypes.Columns {
return [
{
type: 'radio',
width: 40,
slots: { radio: 'radio_cell' },
align: 'center',
fixed: 'left',
},
{
field: 'step',
title: '节点状态',
width: 130,
slots: {
default: ({ row }) => {
return useRender.renderDict(
row.step,
DICT_TYPE.contract_approval_flow_node,
);
},
},
},
{
field: 'contractName',
title: '合同名称',
minWidth: 200,
slots: {
default: ({ row }) => {
return useRender.renderMultiLineText(row.contractName);
},
},
},
{
field: 'reportNo',
title: '报审序号',
width: 100,
},
{
field: 'ctrTypeName',
title: '合同类别',
width: 200,
slots: {
default: ({ row }) => {
return useRender.renderText(
row.ctrTypeName,
`-${row.ctrTwoTypeName}`,
);
},
},
},
{ field: 'budgetSum', title: '预算金额', width: 100 },
{ field: 'priceTypeName', title: '币种', width: 100 },
{
field: 'organiza',
title: '组织形式',
width: 120,
slots: {
default: ({ row }) => {
return useRender.renderDict(
row.organiza,
DICT_TYPE.contract_organization_form,
);
},
},
},
{
field: 'fundAllocation',
title: '资金流向',
width: 100,
slots: {
default: ({ row }) => {
return useRender.renderDict(
row.fundAllocation,
DICT_TYPE.contract_fund_flow,
);
},
},
},
{ field: 'createTime', title: '申报时间', width: 130 },
{ field: 'inputPerson', title: '承办人', width: 100 },
{ field: 'inputDepartName', title: '承办部门', width: 100 },
{ field: 'inputDate', title: '承办时间', width: 130 },
{
field: 'operate',
title: '操作',
width: 60,
fixed: 'right',
slots: { default: 'operate' },
},
];
}
export function getFormSchema(_params: any = {}) {
return {
initialForm: {},
columns: {
contractName: {
title: '合同名称',
key: 'contractName',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
organiza: {
title: '组织形式',
key: 'organiza',
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[180px]',
allowClear: true,
dict: dict({
data: getDictOptions(DICT_TYPE.contract_organization_form),
}),
},
autoSearchTrigger: 'enter',
show: true,
},
price: {
title: '预算金额',
key: 'price',
autoSearchTrigger: 'enter',
show: true,
render({ form }) {
return (
<div class="flex">
<a-form-item class="!mb-0 inline-block">
<a-input-number
placeholder=""
v-model:value={form.budgetSum1}
/>
</a-form-item>
<span class="mx-1"></span>
<a-form-item class="!mb-0 inline-block">
<a-input-number
placeholder=""
v-model:value={form.budgetSum2}
/>
</a-form-item>
</div>
);
},
},
time: {
title: '申报时间',
key: 'time',
autoSearchTrigger: 'enter',
show: true,
render({ form }) {
// 注意此处的v-model写法
return (
<div class="flex">
<a-form-item class="!mb-0 inline-block">
<a-date-picker
format="YYYY-MM-DD"
placeholder=""
v-model:value={form.startDate}
value-format="YYYY-MM-DD"
/>
</a-form-item>
<span class="mx-1"></span>
<a-form-item class="!mb-0 inline-block">
<a-date-picker
format="YYYY-MM-DD"
placeholder=""
v-model:value={form.endDate}
value-format="YYYY-MM-DD"
/>
</a-form-item>
</div>
);
},
},
ctrType: {
title: '合同类别',
key: 'ctrType',
show: true,
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[200px]',
dict: dict({
async getData(_context) {
return await getContractTypes('-1');
},
}),
},
},
},
};
}

View File

@ -1,215 +0,0 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from "vue";
import { useRouter } from "vue-router";
import { Page } from "@vben/common-ui";
import {
MdiAdd,
MdiDelete,
MdiExport,
MdiRadioChecked,
MdiRadioUnchecked,
MdiUpdate,
} from "@vben/icons";
import { message, Modal } from "ant-design-vue";
import Apis from "#/api";
import { useVxeTable } from "#/hooks/vxeTable";
import { toDetailPage } from "#/views/contract/utils.ts";
import { getColumns, getFormSchema, PrimaryKey } from "./crud.tsx";
const router = useRouter();
const searchRef = ref();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: "xGridRef" });
const searchFormBinding = ref({
...getFormSchema(),
onSearch(_context: any) {
triggerProxy("reload");
},
});
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: async ({ page }) => {
const data = await Apis.contractBaseInfo.get_page({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
...searchRef.value?.formData,
},
});
return data;
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: true,
},
})
);
function handleEdit(record?: any) {
if (record && record[PrimaryKey]) {
router.push(`/contract/approval/edit/${record[PrimaryKey]}`);
} else {
router.push("/contract/approval/edit");
}
}
function handleDelete(row) {
Modal.confirm({
title: "提示",
content: "是否确认删除该条记录?",
okType: "danger",
onOk: async () => {
await Apis.contractBaseInfo.post_deletes({
params: { ids: row[PrimaryKey] },
});
message.success("删除成功");
triggerProxy("reload");
},
});
}
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: "xlsx",
columnFilterMethod: ({ column }) => {
if (["operate", "step"].includes(column.field)) {
return false;
}
if (column.type === "radio") {
return false;
}
return true;
},
});
message.success("导出成功");
}
}
/** 选中数据 */
const selectRow: any = computed(() => {
return xGridRef.value?.getRadioRecord() || null;
});
/** 单选框选中事件 */
const setSelectRow = (row: any) => {
if (selectRow.value && selectRow.value[PrimaryKey] === row[PrimaryKey]) {
xGridRef.value?.clearRadioRow();
} else {
xGridRef.value?.setRadioRow(row);
}
};
/** 表格单元格单击事件 */
function handleCellClick({ row }) {
setSelectRow(row);
}
onMounted(async () => {
triggerProxy("reload");
});
</script>
<template>
<Page content-class="h-full flex flex-col">
<fs-search ref="searchRef" v-bind="searchFormBinding">
<template #form_price="{ row }">
<a-input-number v-model:value="row.budgetSum1" placeholder="" />
<span class="mx-1"></span>
<a-input-number v-model:value="row.budgetSum2" placeholder="" />
</template>
<template #form_time="{ row }">
<a-date-picker
v-model:value="row.startTime"
format="YYYY-MM-DD"
placeholder=""
value-format="YYYY-MM-DD"
/>
<span class="mx-1"></span>
<a-date-picker
v-model:value="row.endTime"
format="YYYY-MM-DD"
placeholder=""
value-format="YYYY-MM-DD"
/>
</template>
</fs-search>
<div class="min-h-300px flex-1">
<vxe-grid ref="xGridRef" v-bind="gridOptions" @cell-click="handleCellClick">
<template #toolbar_buttons>
<a-space>
<vben-button variant="primary" @click="handleEdit()">
<MdiAdd class="mr-0.5 text-lg" />
新增
</vben-button>
<vben-button
:disabled="
!selectRow ||
!selectRow[PrimaryKey] ||
!['paEdit'].includes(selectRow.step)
"
variant="warning"
@click="handleEdit(selectRow)"
>
<MdiUpdate class="mr-0.5 text-lg" />
信息维护
</vben-button>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
<vben-button
:disabled="
!selectRow ||
!selectRow[PrimaryKey] ||
!['paEdit'].includes(selectRow.step)
"
variant="destructive"
@click="handleDelete(selectRow)"
>
<MdiDelete class="mr-0.5 text-lg" />
删除
</vben-button>
</a-space>
</template>
<template #radio_cell="{ row, checked }">
<span class="text-base" @click.stop="setSelectRow(row)">
<MdiRadioChecked v-if="checked" />
<MdiRadioUnchecked v-else />
</span>
</template>
<template #operate="{ row }">
<a-button
class="text-primary"
size="small"
type="text"
@click="toDetailPage('approval', row.guid)"
>
查看
</a-button>
</template>
</vxe-grid>
</div>
</Page>
</template>
<style></style>

View File

@ -1,204 +0,0 @@
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { getColumns, getFormSchema } from './crud';
const props = withDefaults(
defineProps<{
multiple?: boolean;
showDepartment?: boolean;
}>(),
{
multiple: true,
},
);
const emit = defineEmits<{
(e: 'confirm', row: any[]): any[];
(e: 'rowClick', row: any): any;
}>();
const isConfirmLoading = ref(false);
const [messageApi] = message.useMessage();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const searchRef = ref();
const data = ref({
userIds: [],
});
const checkRecords = ref([]);
const searchBinding = ref({
...getFormSchema(),
onSearch(context: any) {
triggerProxy('reload');
},
});
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
height: '400px',
columns: getColumns({ type: 'choose' }),
pagerConfig: { size: 'mini' },
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.lxBasisSale.get_page({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
...searchRef.value.formData,
},
});
},
querySuccess() {
for (const row of checkRecords.value) {
xGridRef.value!.setCheckboxRow(row, true);
}
},
},
},
rowConfig: {
keyField: 'basisId',
},
checkboxConfig: {
labelField: 'basisId',
//
showHeader: false,
highlight: true,
range: false,
//
reserve: true,
checkMethod: ({ row }) => {
const checkRecordIds =
checkRecords.value.map((item) => item.guid) || [];
if (
checkRecords.value.length === 0 ||
checkRecordIds.includes(row.guid)
) {
return true;
}
return false;
},
},
}),
);
/**
* 单元行点击事件
*/
function handleCellClick({ row }) {
console.log(row);
emit('rowClick', row);
}
/**
* 复选框选中事件
* @param e
*/
function handleCheckboxChange(e) {
const currRows = xGridRef.value?.getCheckboxRecords() || [];
const otherRows = xGridRef.value?.getCheckboxReserveRecords() || [];
const allRows = [...currRows, ...otherRows];
if (e.checked) {
const existingIds = new Set(checkRecords.value.map((item) => item.guid));
if (!existingIds.has(e.row.ACCOUNT_ID)) {
checkRecords.value = [...checkRecords.value, e.row];
}
} else {
handleCloseTag(e.row);
}
console.log('[ checkRecords.value ] >', checkRecords.value);
if (allRows.length > 0) {
messageApi.warning('最多只能选择1条数据');
}
}
function handleCloseTag(row) {
checkRecords.value = checkRecords.value.filter(
(item) => item.guid != row.guid,
);
xGridRef.value?.setCheckboxRow(row, false);
}
const title = ref('选择办公用品');
const [BaseModal, baseModalApi] = useVbenModal({
onOpenChange(isOpen: boolean) {
if (isOpen) {
isConfirmLoading.value = false;
data.value = baseModalApi.getData<Record<string, any>>() || {};
if (data.value.title) {
title.value = data.value.title;
}
console.log(data.value.userIds);
const rows: any = [];
for (const element of checkRecords.value) {
if (data.value.guids.includes(element.guid)) {
rows.push(element);
}
}
checkRecords.value = rows;
}
},
onConfirm() {
console.info('onConfirm');
emit('confirm', checkRecords.value);
baseModalApi.close();
},
onCancel() {
baseModalApi.close();
},
});
</script>
<template>
<BaseModal
:confirm-loading="isConfirmLoading"
:loading="isConfirmLoading"
:title="title"
>
<div v-if="props.multiple" class="py-12px flex flex-row">
<span class="mr-12px block">已选择</span>
<div class="flex flex-1 flex-row">
<a-space>
<a-tag
v-for="(item, index) in checkRecords"
:key="index"
closable
@close="handleCloseTag(item)"
>
{{ item.basisName }}
</a-tag>
</a-space>
</div>
</div>
<div class="flex h-full flex-col">
<fs-search ref="searchRef" v-bind="searchBinding" />
<div class="min-h-300px flex-1">
<VxeGrid
ref="xGridRef"
class="h-420px"
v-bind="gridOptions"
@cell-click="handleCellClick"
@checkbox-change="handleCheckboxChange"
/>
</div>
</div>
</BaseModal>
</template>

View File

@ -1,49 +0,0 @@
import type { VxeGridPropTypes } from 'vxe-table';
import { useRender } from '#/hooks/useRender';
import { DICT_TYPE, getDictObj } from '#/utils/dict';
export function getColumns(params?): VxeGridPropTypes.Columns {
const { readOnly = false } = params || {};
const columns: VxeGridPropTypes.Columns = [
{ type: 'seq', title: '序号', width: 60 },
{ field: 'basisId', title: '依据号', width: 130 },
{
field: 'basisName',
title: '依据名称',
width: 200,
},
{ field: 'basisNum', title: '依据编号', width: 180 },
{
field: 'basisTypeId',
title: '依据类型',
width: 100,
slots: {
default: ({ row }) => {
return getDictObj(DICT_TYPE.contract_basis_type, row.basisTypeId)
?.label;
},
},
},
{
field: 'endDate',
title: '有效期',
width: 150,
slots: {
default: ({ row }) => {
return useRender.renderDate(row.endDate, 'YYYY-MM-DD');
},
},
},
];
if (!readOnly) {
columns.push({
title: '操作',
width: 120,
slots: { default: 'operate' },
});
}
return columns;
}

View File

@ -1,176 +0,0 @@
import type { VxeGridPropTypes } from 'vxe-table';
import { dict } from '@fast-crud/fast-crud';
import { useRender } from '#/hooks/useRender';
import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict';
export const PrimaryKey = 'guid';
export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
const columns: VxeGridPropTypes.Columns = [];
if (params.type === 'choose') {
return [
{ field: 'basisId', title: '依据号', type: 'checkbox', width: 160 },
{
field: 'basisName',
title: '依据名称',
width: 200,
},
{ field: 'basisNum', title: '依据编号', width: 180 },
{
field: 'basisTypeId',
title: '依据类型',
width: 100,
slots: {
default: ({ row }) => {
return (
getDictObj(DICT_TYPE.contract_basis_type, row.basisTypeId)
?.label || ''
);
},
},
},
{
field: 'endDate',
title: '有效期',
width: 150,
slots: {
default: ({ row }) => {
return useRender.renderDate(row.endDate, 'YYYY-MM-DD');
},
},
},
{ field: 'inputPerson', title: '创建人', width: 150 },
{
field: 'inputDate',
title: '创建时间',
width: 150,
slots: {
default: ({ row }) => {
return useRender.renderDate(row.inputDate, 'YYYY-MM-DD');
},
},
},
{ field: 'remark', title: '备注', minWidth: 200 },
];
}
return [
{ field: 'basisId', title: '依据号', width: 130 },
{
field: 'basisName',
title: '依据名称',
width: 200,
},
{ field: 'basisNum', title: '依据编号', width: 180 },
{
field: 'basisTypeId',
title: '依据类型',
width: 100,
slots: {
default: ({ row }) => {
return (
getDictObj(DICT_TYPE.contract_basis_type, row.basisTypeId)?.label ||
''
);
},
},
},
{
field: 'endDate',
title: '有效期',
width: 150,
slots: {
default: ({ row }) => {
return useRender.renderDate(row.endDate, 'YYYY-MM-DD');
},
},
},
{ field: 'inputPerson', title: '创建人', width: 150 },
{
field: 'inputDate',
title: '创建时间',
width: 150,
slots: {
default: ({ row }) => {
return useRender.renderDate(row.inputDate, 'YYYY-MM-DD');
},
},
},
{ field: 'remark', title: '备注', minWidth: 200 },
];
return columns;
}
export function getFormSchema(_params: any = {}) {
return {
initialForm: {},
columns: {
basisName: {
title: '依据名称',
key: 'basisName',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
basisNum: {
title: '依据编号',
key: 'basisNum',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
basisTypeId: {
title: '依据类型',
key: 'basisTypeId',
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[180px]',
allowClear: true,
dict: dict({
async getData(_form) {
return getDictOptions(DICT_TYPE.contract_basis_type);
},
}),
},
autoSearchTrigger: 'enter',
show: true,
},
inputPerson: {
title: '创建人',
key: 'inputPerson',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
inputDate: {
title: '创建年份',
key: 'inputDate',
component: {
name: 'a-date-picker',
vModel: 'value',
allowClear: true,
picker: 'year',
format: 'YYYY年',
valueFormat: 'YYYY',
},
autoSearchTrigger: 'enter',
show: true,
},
},
};
}

View File

@ -1,173 +0,0 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui';
import {
MdiAdd,
MdiDelete,
MdiExport,
MdiRadioChecked,
MdiRadioUnchecked,
MdiUpdate,
} from '@vben/icons';
import { message, Modal } from 'ant-design-vue';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { getColumns, getFormSchema, PrimaryKey } from './crud.tsx';
import signingBasisEditModal from './signing-basis-edit-modal.vue';
const [EditModal, editModalApi] = useVbenModal({
connectedComponent: signingBasisEditModal,
});
const searchRef = ref();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: ({ page }) => {
return Apis.lxBasisSale.get_page({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
...searchRef.value?.formData,
},
});
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: true,
},
}),
);
function handleEdit(record?: any) {
editModalApi.setData({
isUpdate: Boolean(record && record[PrimaryKey]),
record: JSON.parse(JSON.stringify(record || {})),
});
editModalApi.open();
}
function handleDelete(row) {
Modal.confirm({
title: '提示',
content: '是否确认删除该条记录?',
okType: 'danger',
onOk: async () => {
await Apis.lxBasisSale.post_deletes({ params: { ids: row.guid } });
message.success('删除成功');
triggerProxy('reload');
},
});
}
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: 'xlsx',
});
message.success('导出成功');
}
}
/** 选中数据 */
const selectRow: any = computed(() => {
return xGridRef.value?.getRadioRecord() || null;
});
/** 单选框选中事件 */
const setSelectRow = (row: any) => {
if (selectRow.value && selectRow.value.guid === row.guid) {
xGridRef.value?.clearRadioRow();
} else {
xGridRef.value?.setRadioRow(row);
}
};
/** 表格单元格单击事件 */
function handleCellClick({ row }) {
setSelectRow(row);
}
onMounted(() => {
triggerProxy('reload');
});
const searchForm = ref({
...getFormSchema(),
onSearch(_context: any) {
triggerProxy('reload');
},
});
</script>
<template>
<Page content-class="h-full flex flex-col">
<EditModal
class="w-[600px] max-w-[80vw]"
@success="triggerProxy('reload')"
/>
<fs-search ref="searchRef" v-bind="searchForm" />
<div class="min-h-300px flex-1">
<vxe-grid
ref="xGridRef"
v-bind="gridOptions"
@cell-click="handleCellClick"
>
<template #toolbar_buttons>
<a-space>
<vben-button variant="primary" @click="handleEdit()">
<MdiAdd class="mr-0.5 text-lg" />
新增
</vben-button>
<vben-button
:disabled="!selectRow || !selectRow.guid"
variant="warning"
@click="handleEdit(selectRow)"
>
<MdiUpdate class="mr-0.5 text-lg" />
修改
</vben-button>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
<vben-button
:disabled="!selectRow || !selectRow.guid"
variant="destructive"
@click="handleDelete(selectRow)"
>
<MdiDelete class="mr-0.5 text-lg" />
删除
</vben-button>
</a-space>
</template>
<template #radio_cell="{ row, checked }">
<span class="text-base" @click.stop="setSelectRow(row)">
<MdiRadioChecked v-if="checked" />
<MdiRadioUnchecked v-else />
</span>
</template>
</vxe-grid>
</div>
</Page>
</template>
<style></style>

View File

@ -1,199 +0,0 @@
<script lang="tsx" setup>
import { nextTick, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { MdiCloudUpload } from '@vben/icons';
import { dict } from '@fast-crud/fast-crud';
import { message, type UploadChangeParam } from 'ant-design-vue';
import dayjs, { Dayjs } from 'dayjs';
import Apis from '#/api';
import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict';
import { FileUploader } from '#/utils/file';
const emit = defineEmits<{
(e: 'success'): void;
}>();
const fileUploader = new FileUploader({});
const data = ref({
isUpdate: false,
record: {} as any,
});
const formRef = ref();
const isConfirmLoading = ref(false);
const formBinding = ref({
col: { span: 24 },
initialForm: {},
labelCol: { style: { width: '120px' } },
columns: {
basisTypeId: {
title: '依据类型',
key: 'basisTypeId',
component: {
name: 'fs-dict-radio',
vModel: 'value',
allowClear: true,
dict: dict({
async getData() {
return await getDictOptions(DICT_TYPE.contract_basis_type);
},
}),
},
rules: [{ required: true, message: '请选择依据类型' }],
},
basisNum: {
title: '依据编号',
key: 'basisNum',
component: {
name: 'a-input',
vModel: 'value',
},
rules: [{ required: true, message: '请输入依据编号' }],
},
basisName: {
title: '依据名称',
key: 'basisName',
component: {
name: 'a-input',
vModel: 'value',
},
rules: [{ required: true, message: '请输入依据名称' }],
},
endDate: {
title: '有效期',
key: 'endDate',
component: {
name: 'a-date-picker',
vModel: 'value',
allowClear: false,
disabledDate: (current: Dayjs) => {
return current <= dayjs();
},
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD',
},
rules: [{ required: true, message: '请选择有效期' }],
},
remark: {
title: '备注',
key: 'remark',
component: {
name: 'a-textarea',
vModel: 'value',
autoSize: { minRows: 4, maxRows: 6 },
},
},
fileList: {
title: '附件上传',
key: 'fileList',
},
},
});
const handleChange = (info: UploadChangeParam) => {
formRef.value.setFormData({
fileList: info.fileList.length > 0 ? info.fileList : [],
});
};
const [BaseModal, baseModalApi] = useVbenModal({
async onOpenChange(isOpen: boolean) {
if (isOpen) {
isConfirmLoading.value = false;
data.value = baseModalApi.getData<Record<string, any>>() || {};
if (data.value.isUpdate) {
if (data.value.record.fileUuid) {
const files = await fileUploader.select(data.value.record.fileUuid);
console.log(files);
data.value.record.fileList = files;
}
nextTick(() => {
formRef.value.setFormData(data.value.record || {});
});
}
}
},
async onConfirm() {
try {
isConfirmLoading.value = true;
console.info('onConfirm');
console.log(formRef.value?.form);
await formRef.value?.submit();
const form = formRef.value.form;
{
const tempFileList = form.fileList;
let tempFiles: any = [];
if (tempFileList && tempFileList.length > 0) {
tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
}
console.log(tempFiles);
if (tempFiles) {
form.fileUuid = (tempFiles.map((item) => item.fileUuid) || []).join(
',',
);
}
delete form.fileList;
}
if (form.basisTypeId) {
form.basisTypeName = getDictObj(
DICT_TYPE.contract_basis_type,
form.basisTypeId,
)?.label;
}
await Apis.lxBasisSale.post_save({ data: form });
baseModalApi.close();
message.success('操作成功');
} catch (error) {
console.log(error);
} finally {
isConfirmLoading.value = false;
emit('success');
}
},
onCancel() {
baseModalApi.close();
},
});
</script>
<template>
<BaseModal
:confirm-loading="isConfirmLoading"
:loading="isConfirmLoading"
:title="data.isUpdate ? '修改签约依据信息' : '新增签约依据信息'"
>
<fs-form ref="formRef" v-bind="formBinding">
<template #form_fileList="{ form }">
<a-upload-dragger
v-model:file-list="form.fileList"
:before-upload="() => false"
:max-count="1"
accept=".pdf"
name="file"
@change="handleChange"
>
<div class="flex flex-col items-center">
<MdiCloudUpload class="text-center text-[50px] text-gray-600" />
<p class="ant-upload-text">点击或拖动文件到该区域来上传</p>
<p class="ant-upload-hint">仅支持 pdf 类型的文件</p>
</div>
</a-upload-dragger>
</template>
</fs-form>
</BaseModal>
</template>
<style scoped>
:deep(.ant-divider-horizontal.ant-divider-with-text) {
margin: 0 !important;
}
</style>

View File

@ -1,12 +0,0 @@
<script setup lang="ts">
import { Page } from '@vben/common-ui';
import TodoPage from '../../components/todo-page/todo-page.vue';
</script>
<template>
<Page content-class="h-full">
<TodoPage :module="['contractSetup']" />
</Page>
</template>
<style scoped></style>

View File

@ -1,85 +0,0 @@
import type { VxeGridPropTypes } from 'vxe-table';
import dayjs from 'dayjs';
export const PrimaryKey = 'guid';
export function getColumns(_params?: any): VxeGridPropTypes.Columns {
return [
{
type: 'radio',
width: 40,
slots: { radio: 'radio_cell' },
align: 'center',
fixed: 'left',
},
{
field: 'reviewNumber',
title: '报审序号',
width: 120,
align: 'center',
},
{
field: 'contractNumber',
title: '正式合同编号',
width: 150,
align: 'center',
},
{
field: 'contractName',
title: '合同名称',
width: 200,
align: 'left',
},
{
field: 'contractType',
title: '合同类别',
width: 120,
align: 'center',
},
{
field: 'contractTerminator',
title: '合同终止人',
width: 120,
align: 'center',
},
{
field: 'archiveTime',
title: '合同归档时间',
width: 150,
align: 'center',
},
];
}
export function getFormSchema(_params: any = {}) {
return {
initialForm: {
startDate: dayjs().startOf('month').format('YYYY-MM-DD'),
},
columns: {
contractName: {
title: '合同名称',
key: 'contractName',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
contractNumber: {
title: '正式合同编号',
key: 'contractNumber',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
},
};
}

View File

@ -1,122 +0,0 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import { Page } from '@vben/common-ui';
import { MdiExport, MdiRadioChecked, MdiRadioUnchecked } from '@vben/icons';
import { message } from 'ant-design-vue';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { getColumns, getFormSchema, PrimaryKey } from './crud.tsx';
const router = useRouter();
const searchRef = ref();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: async ({ page }) => {
const data = await Apis.contractFilingFormal.get_pageArchivedContract(
{
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
...searchRef.value?.formData,
},
},
);
return data;
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: true,
},
}),
);
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: 'xlsx',
});
message.success('导出成功');
}
}
/** 选中数据 */
const selectRow: any = computed(() => {
return xGridRef.value?.getRadioRecord() || null;
});
/** 单选框选中事件 */
const setSelectRow = (row: any) => {
if (selectRow.value && selectRow.value[PrimaryKey] === row[PrimaryKey]) {
xGridRef.value?.clearRadioRow();
} else {
xGridRef.value?.setRadioRow(row);
}
};
/** 表格单元格单击事件 */
function handleCellClick({ row }) {
setSelectRow(row);
}
onMounted(() => {
triggerProxy('reload');
});
const searchForm = ref({
...getFormSchema(),
onSearch(_context: any) {
triggerProxy('reload');
},
});
</script>
<template>
<Page content-class="h-full flex flex-col">
<fs-search ref="searchRef" v-bind="searchForm" />
<div class="min-h-300px flex-1">
<vxe-grid
ref="xGridRef"
v-bind="gridOptions"
@cell-click="handleCellClick"
>
<template #toolbar_buttons>
<a-space>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
</a-space>
</template>
<template #radio_cell="{ row, checked }">
<span class="text-base" @click.stop="setSelectRow(row)">
<MdiRadioChecked v-if="checked" />
<MdiRadioUnchecked v-else />
</span>
</template>
</vxe-grid>
</div>
</Page>
</template>
<style></style>

View File

@ -1,99 +0,0 @@
import type { VxeGridPropTypes } from 'vxe-table';
import dayjs from 'dayjs';
export const PrimaryKey = 'guid';
export function getColumns(_params?: any): VxeGridPropTypes.Columns {
return [
{
type: 'radio',
width: 40,
slots: { radio: 'radio_cell' },
align: 'center',
fixed: 'left',
},
{
field: 're',
title: '归档',
width: 80,
align: 'center',
},
{
field: 'reviewNumber',
title: '报审序号',
width: 120,
align: 'center',
},
{
field: 'contractNumber',
title: '正式合同编号',
width: 150,
align: 'center',
},
{
field: 'contractName',
title: '合同名称',
width: 200,
align: 'left',
},
{
field: 'contractType',
title: '合同类别',
width: 120,
align: 'center',
},
{
field: 'contractTerminator',
title: '合同终止人',
width: 120,
align: 'center',
},
{
field: 'archiveTime',
title: '合同归档时间',
width: 150,
align: 'center',
},
{
title: '操作',
width: 80,
align: 'center',
slots: {
default: 'operate',
},
},
];
}
export function getFormSchema(_params: any = {}) {
return {
initialForm: {
startDate: dayjs().startOf('month').format('YYYY-MM-DD'),
},
columns: {
contractName: {
title: '合同名称',
key: 'contractName',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
contractNumber: {
title: '正式合同编号',
key: 'contractNumber',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
},
};
}

View File

@ -1,122 +0,0 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import { Page } from '@vben/common-ui';
import { MdiExport, MdiRadioChecked, MdiRadioUnchecked } from '@vben/icons';
import { message } from 'ant-design-vue';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { getColumns, getFormSchema, PrimaryKey } from './crud.tsx';
const router = useRouter();
const searchRef = ref();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: async ({ page }) => {
const data = await Apis.contractFilingFormal.get_pageArchivedContract(
{
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
...searchRef.value?.formData,
},
},
);
return data;
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: true,
},
}),
);
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: 'xlsx',
});
message.success('导出成功');
}
}
/** 选中数据 */
const selectRow: any = computed(() => {
return xGridRef.value?.getRadioRecord() || null;
});
/** 单选框选中事件 */
const setSelectRow = (row: any) => {
if (selectRow.value && selectRow.value[PrimaryKey] === row[PrimaryKey]) {
xGridRef.value?.clearRadioRow();
} else {
xGridRef.value?.setRadioRow(row);
}
};
/** 表格单元格单击事件 */
function handleCellClick({ row }) {
setSelectRow(row);
}
onMounted(() => {
triggerProxy('reload');
});
const searchForm = ref({
...getFormSchema(),
onSearch(_context: any) {
triggerProxy('reload');
},
});
</script>
<template>
<Page content-class="h-full flex flex-col">
<fs-search ref="searchRef" v-bind="searchForm" />
<div class="min-h-300px flex-1">
<vxe-grid
ref="xGridRef"
v-bind="gridOptions"
@cell-click="handleCellClick"
>
<template #toolbar_buttons>
<a-space>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
</a-space>
</template>
<template #radio_cell="{ row, checked }">
<span class="text-base" @click.stop="setSelectRow(row)">
<MdiRadioChecked v-if="checked" />
<MdiRadioUnchecked v-else />
</span>
</template>
</vxe-grid>
</div>
</Page>
</template>
<style></style>

View File

@ -1,105 +0,0 @@
import type { VxeGridPropTypes } from 'vxe-table';
import dayjs from 'dayjs';
export const PrimaryKey = 'guid';
export function getColumns(_params?: any): VxeGridPropTypes.Columns {
return [
{
type: 'radio',
width: 40,
slots: { radio: 'radio_cell' },
align: 'center',
fixed: 'left',
},
{
field: 're',
title: '回档',
width: 80,
align: 'center',
},
{
field: 'reviewNumber',
title: '报审序号',
width: 120,
align: 'center',
},
{
field: 'contractDeclareNumber',
title: '合同申报编号',
width: 150,
align: 'center',
},
{
field: 'contractNumber',
title: '正式合同编号',
width: 150,
align: 'center',
},
{
field: 'contractName',
title: '合同名称',
width: 200,
align: 'left',
},
{
field: 'contractType',
title: '合同类别',
width: 120,
align: 'center',
},
{
field: 'contractTerminator',
title: '合同终止人',
width: 120,
align: 'center',
},
{
field: 'contractTerminationTime',
title: '合同终止时间',
width: 150,
align: 'center',
},
{
title: '操作',
width: 80,
align: 'center',
slots: {
default: 'operate',
},
},
];
}
export function getFormSchema(_params: any = {}) {
return {
initialForm: {
startDate: dayjs().startOf('month').format('YYYY-MM-DD'),
},
columns: {
contractName: {
title: '合同名称',
key: 'contractName',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
contractNumber: {
title: '正式合同编号',
key: 'contractNumber',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
},
};
}

View File

@ -1,122 +0,0 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import { Page } from '@vben/common-ui';
import { MdiExport, MdiRadioChecked, MdiRadioUnchecked } from '@vben/icons';
import { message } from 'ant-design-vue';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { getColumns, getFormSchema, PrimaryKey } from './crud.tsx';
const router = useRouter();
const searchRef = ref();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: async ({ page }) => {
const data = await Apis.contractFilingFormal.get_pageArchivedContract(
{
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
...searchRef.value?.formData,
},
},
);
return data;
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: true,
},
}),
);
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: 'xlsx',
});
message.success('导出成功');
}
}
/** 选中数据 */
const selectRow: any = computed(() => {
return xGridRef.value?.getRadioRecord() || null;
});
/** 单选框选中事件 */
const setSelectRow = (row: any) => {
if (selectRow.value && selectRow.value[PrimaryKey] === row[PrimaryKey]) {
xGridRef.value?.clearRadioRow();
} else {
xGridRef.value?.setRadioRow(row);
}
};
/** 表格单元格单击事件 */
function handleCellClick({ row }) {
setSelectRow(row);
}
onMounted(() => {
triggerProxy('reload');
});
const searchForm = ref({
...getFormSchema(),
onSearch(_context: any) {
triggerProxy('reload');
},
});
</script>
<template>
<Page content-class="h-full flex flex-col">
<fs-search ref="searchRef" v-bind="searchForm" />
<div class="min-h-300px flex-1">
<vxe-grid
ref="xGridRef"
v-bind="gridOptions"
@cell-click="handleCellClick"
>
<template #toolbar_buttons>
<a-space>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
</a-space>
</template>
<template #radio_cell="{ row, checked }">
<span class="text-base" @click.stop="setSelectRow(row)">
<MdiRadioChecked v-if="checked" />
<MdiRadioUnchecked v-else />
</span>
</template>
</vxe-grid>
</div>
</Page>
</template>
<style></style>

View File

@ -1,97 +0,0 @@
import type { VxeGridPropTypes } from 'vxe-table';
import { useRender } from '#/hooks/useRender';
import dayjs from 'dayjs';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import { dict } from '@fast-crud/fast-crud';
export const PrimaryKey = 'guid';
export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
return [
{ type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' },
{
field: 'contractName', title: '合同名称', minWidth: 200, slots: {
default: ({ row }) => {
return useRender.renderMultiLineText(row.contractName);
}
}, fixed: 'left'
},
{
field: 'reportNo', title: '报审序号', width: 100,
},
{
field: 'ctrTypeName', title: '合同类别', width: 200, slots: {
default: ({ row }) => {
return useRender.renderText(row.ctrTypeName, '-' + row.ctrTwoTypeName);
}
}
},
{ field: 'budgetSum', title: '预算金额', width: 100 },
{ field: 'priceTypeName', title: '币种', width: 100 },
{
field: 'organiza', title: '组织形式', width: 120, slots: {
default: ({ row }) => {
return useRender.renderDict(row.organiza, DICT_TYPE.contract_organization_form);
}
}
},
{
field: 'fundAllocation', title: '资金流向', width: 100, slots: {
default: ({ row }) => {
return useRender.renderDict(row.fundAllocation, DICT_TYPE.contract_fund_flow);
}
}
},
{ field: 'inputPerson', title: '承办人', width: 100 },
{ field: 'inputDepartName', title: '承办部门', width: 100 },
{ field: 'inputDate', title: '承办时间', width: 130 },
]
}
export function getFormSchema(_params: any = {}) {
return {
initialForm: {
startDate: dayjs().startOf('month').format("YYYY-MM-DD"),
},
columns: {
contractName: {
title: '合同名称',
key: 'contractName',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
organiza: {
title: '组织形式',
key: 'organiza',
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[180px]',
allowClear: true,
dict: dict({
data: getDictOptions(DICT_TYPE.contract_organization_form)
}),
},
autoSearchTrigger: 'enter',
show: true,
},
price: {
title: '预算金额',
key: 'price',
autoSearchTrigger: 'enter',
show: true,
},
time: {
title: '申报时间',
key: 'startDate',
autoSearchTrigger: 'enter',
show: true,
},
},
};
}

View File

@ -1,245 +0,0 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
import {
MdiAdd,
MdiDelete,
MdiExport,
MdiRadioChecked,
MdiRadioUnchecked,
MdiUpdate,
} from '@vben/icons';
import { message, Modal } from 'ant-design-vue';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { getMonthStartAndEnd } from '#/utils/time';
import { getColumns, getFormSchema, PrimaryKey } from './crud.tsx';
const router = useRouter();
const checkedValue = ref('all');
const exportSearchParams = ref<any>({
daterange: getMonthStartAndEnd(),
});
const searchRef = ref();
const isConfirmLoading = ref(false);
const [_Modal, modalApi] = useVbenModal({
async onConfirm() {
isConfirmLoading.value = true;
try {
let params = {};
if (checkedValue.value == 'daterange') {
params = {
startDate: exportSearchParams.value.daterange[0],
endDate: exportSearchParams.value.daterange[1],
};
}
const res = await Apis.zbgl
.post_export({
params,
config: {
meta: {
responseType: 'blob',
},
},
})
.send();
message.success('导出成功');
modalApi.close();
showExportModal.value = false;
} catch (error) {
console.error(error);
} finally {
isConfirmLoading.value = false;
}
console.info('onConfirm');
},
});
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const treeData = ref([]);
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: ({ page }) => {
return Apis.contractBaseInfo.get_page({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
...searchRef.value?.formData,
},
});
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: true,
},
}),
);
function handleEdit(record?: any) {
if (record && record[PrimaryKey]) {
router.push(`/contract/approval/edit/${record[PrimaryKey]}`);
} else {
router.push('/contract/approval/edit');
}
}
function handleDelete(row) {
Modal.confirm({
title: '提示',
content: '是否确认删除该条记录?',
okType: 'danger',
onOk: async () => {
await Apis.contractBaseInfo.post_deletes({
params: { ids: row[PrimaryKey] },
});
message.success('删除成功');
triggerProxy('reload');
},
onCancel() {
console.log('Cancel');
},
});
}
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: 'xlsx',
});
message.success('导出成功');
}
}
/** 选中数据 */
const selectRow: any = computed(() => {
return xGridRef.value?.getRadioRecord() || null;
});
/** 单选框选中事件 */
const setSelectRow = (row: any) => {
if (selectRow.value && selectRow.value[PrimaryKey] === row[PrimaryKey]) {
xGridRef.value?.clearRadioRow();
} else {
xGridRef.value?.setRadioRow(row);
}
};
/** 表格单元格单击事件 */
function handleCellClick({ row }) {
setSelectRow(row);
}
onMounted(() => {
triggerProxy('reload');
});
const searchForm = ref({
...getFormSchema(),
onSearch(context: any) {
triggerProxy('reload');
},
});
function toPage() {
window.open('/iframe/meeting/standing-book', '_blank');
}
function toDetail(row) {
window.open(`/iframe/meeting/start/${row.guid}`, '_blank');
}
//
</script>
<template>
<Page content-class="h-full flex flex-col">
<fs-search ref="searchRef" v-bind="searchForm">
<template #search_price="{ row }">
<a-input-number v-model:value="row.budgetSum1" placeholder="" />
<span class="mx-1"></span>
<a-input-number v-model:value="row.budgetSum2" placeholder="" />
</template>
<template #form_time="{ row }">
<a-date-picker
v-model:value="row.startTime"
format="YYYY-MM-DD"
placeholder=""
value-format="YYYY-MM-DD"
/>
<span class="mx-1"></span>
<a-date-picker
v-model:value="row.endTime"
format="YYYY-MM-DD"
placeholder=""
value-format="YYYY-MM-DD"
/>
</template>
</fs-search>
<div class="min-h-300px flex-1">
<vxe-grid
ref="xGridRef"
v-bind="gridOptions"
@cell-click="handleCellClick"
>
<template #toolbar_buttons>
<a-space>
<vben-button variant="primary" @click="handleEdit()">
<MdiAdd class="mr-0.5 text-lg" />
新增
</vben-button>
<vben-button
:disabled="!selectRow || !selectRow[PrimaryKey]"
variant="warning"
@click="handleEdit(selectRow)"
>
<MdiUpdate class="mr-0.5 text-lg" />
修改
</vben-button>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
<vben-button
:disabled="!selectRow || !selectRow[PrimaryKey]"
variant="destructive"
@click="handleDelete(selectRow)"
>
<MdiDelete class="mr-0.5 text-lg" />
删除
</vben-button>
</a-space>
</template>
<template #radio_cell="{ row, checked }">
<span class="text-base" @click.stop="setSelectRow(row)">
<MdiRadioChecked v-if="checked" />
<MdiRadioUnchecked v-else />
</span>
</template>
</vxe-grid>
</div>
</Page>
</template>
<style></style>

View File

@ -1,182 +0,0 @@
<template>
<Page contentClass="h-full flex flex-col">
<a-space direction="vertical" size="small">
<a-card title="待办" size="small">
<vxe-grid ref="xGridRef" v-bind="gridOptions">
<template #toolbar_buttons> </template>
</vxe-grid>
</a-card>
<a-card title="已办" size="small" contentClass="">
<vxe-grid ref="xGrid2Ref" v-bind="grid2Options">
<template #toolbar_buttons> </template>
</vxe-grid>
</a-card>
</a-space>
</Page>
</template>
<script setup lang="ts">
import { defineComponent, ref, reactive, onMounted } from 'vue';
import { FsCrud } from '@fast-crud/fast-crud';
import { type VxeGridProps } from 'vxe-table'
import { Page, useVbenModal } from '@vben/common-ui';
import { useVxeTable } from '#/hooks/vxeTable';
import {
type CreateCrudOptionsProps,
useColumns,
useFormWrapper,
useFs,
utils,
} from '@fast-crud/fast-crud';
import { MdiAdd, MdiUpdate, MdiDelete } from '@vben/icons';
import { dict } from "@fast-crud/fast-crud";
import Apis from '#/api'
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const { xGridRef:xGrid2Ref, triggerProxy:triggerProxy2 } = useVxeTable({ ref: 'xGrid2Ref' });
const treeData = ref([]);
/** Hooks - 表格 */
const gridOptions = reactive(gridProps({
columns: [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '编号', width: 100 },
{
field: 'title', title: '名称', minWidth: 200, slots: {
default: ({ row }) => {
// let text = row.title
// if (text) {
// let classArr: string[] = ["line-clamp-3"];
// return h(
// NTooltip,
// { trigger: 'hover' },
// {
// trigger: () => h('span', { class: classArr.join(' ') }, text),
// default: () => text
// }
// )
// }
return '';
}
}
},
{ field: 'contractAmount', title: '模块', width: 150 },
{ field: 'contractSubject', title: '任务', width: 200 },
{ field: 'contractCounterparty', title: '分配时间', width: 150 },
{ field: 'cumulativeSettlementAmount', title: '承办单位/部门', width: 150 },
{ field: 'changeCount', title: '承办人', width: 100 },
{ field: 'contractStatus', title: '交接给', width: 100 }
],
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.ccsq.get_toDoPage({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchParams } })
}
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: false
},
}));
/** Hooks - 表格 */
const grid2Options = reactive(gridProps({
columns: [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '编号', width: 100 },
{
field: 'title', title: '名称', minWidth: 200, slots: {
default: ({ row }) => {
// let text = row.title
// if (text) {
// let classArr: string[] = ["line-clamp-3"];
// return h(
// NTooltip,
// { trigger: 'hover' },
// {
// trigger: () => h('span', { class: classArr.join(' ') }, text),
// default: () => text
// }
// )
// }
return '';
}
}
},
{ field: 'contractAmount', title: '模块', width: 150 },
{ field: 'contractSubject', title: '任务', width: 200 },
{ field: 'contractCounterparty', title: '分配时间', width: 150 },
{ field: 'cumulativeSettlementAmount', title: '承办单位/部门', width: 150 },
{ field: 'changeCount', title: '承办人', width: 100 },
{ field: 'contractStatus', title: '交接给', width: 100 }
],
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.ccsq.get_donePage({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchParams } })
}
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: false
},
}));
onMounted(() => {
})
let searchParams = reactive({})
const searchForm = ref({
columns: {
name: {
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
props: {
type: 'text',
showWordLimit: true,
},
},
title: '字典标签',
key: 'type',
autoSearchTrigger: 'enter',
show: true,
},
age: {
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
title: '字典键值',
key: 'value',
autoSearchTrigger: 'enter',
show: true,
},
},
onSearch(context: any) {
searchParams = context.form
triggerProxy('reload')
},
onReset(context: any) {
searchParams = context.form
},
});
//
</script>
<style></style>

View File

@ -1,282 +0,0 @@
<script setup lang="tsx">
import {
computed,
defineEmits,
defineExpose,
defineProps,
onMounted,
reactive,
ref,
watch,
withDefaults,
} from 'vue';
import Apis from '#/api'; // Apis
import { filterContractTypes } from '#/views/contract/utils'; // utils
import type { UploadChangeParam } from 'ant-design-vue';
import { MdiUpload } from '@vben/icons';
import { DICT_TYPE, getDictDatasAsync } from '#/utils/dict';
import { FileUploader } from '#/utils/file';
const props = withDefaults(
defineProps<{
form: Record<string, any>;
}>(),
{
form: () => ({}),
},
);
const emit = defineEmits(['update:form', 'field-change']);
const fileUploader = new FileUploader({});
const formRef = ref();
const form = reactive({ ...props.form });
watch(
() => props.form,
async (newForm) => {
Object.assign(form, newForm);
},
{ deep: true, immediate: true },
);
const readOnly = computed(() => {
return ['smApproval'].includes(form.businessStep);
});
watch(
() => props.form.fileUuid,
async (newFileUuid) => {
if (newFileUuid) {
const files = await fileUploader.select(newFileUuid);
console.log(files);
form.fileList = files;
} else {
form.fileList = []; //
}
},
{ immediate: true },
);
watch(
() => form,
(newForm) => {
emit('update:form', newForm);
},
{ deep: true },
);
const rules = {
contractName: [{ required: true, message: '合同名称是必填项' }],
ctrType: [{ required: true, message: '合同类别是必填项' }],
ctrTwoType: [{ required: true, message: '二级类别是必填项' }],
fundAllocation: [{ required: true, message: '请选择资金流向' }],
fundDitch: [{ required: true, message: '请选择资金渠道' }],
organiza: [{ required: true, message: '请选择组织方式' }],
};
const contractTypeData = ref<any[]>([]);
function filteredContractTypes(parentType: string) {
return filterContractTypes(contractTypeData.value, parentType);
}
const dictMap = ref<any>({
common_whether: [],
contract_currency_unit: [],
contract_fund_flow: [],
contract_funding_source: [],
contract_organization_form: [],
});
onMounted(async () => {
const contractReferTypeData: any = await Apis.contractReferType.get_list({
params: {},
});
contractTypeData.value = contractReferTypeData.rows || [];
//
dictMap.value = await getDictDatasAsync([
{ type: DICT_TYPE.contract_currency_unit, valueType: 'string' },
{ type: DICT_TYPE.common_whether, valueType: 'string' },
{ type: DICT_TYPE.contract_fund_flow, valueType: 'string' },
{ type: DICT_TYPE.contract_funding_source, valueType: 'string' },
{ type: DICT_TYPE.contract_organization_form, valueType: 'string' },
]);
console.log(dictMap.value);
});
const handleChange = (info: UploadChangeParam) => {
form.fileList = info.fileList.length > 0 ? info.fileList : [];
};
function validate() {
return formRef.value?.validate();
}
function submit() {
// return f
}
defineExpose({ validate, submit });
</script>
<template>
<a-form
ref="formRef"
:label-col="{ style: { width: '120px' } }"
:model="form"
:rules="rules"
>
<a-row :gutter="16">
<a-col :span="16">
<a-form-item label="合同名称" name="contractName">
<a-input v-model:value="form.contractName" :disabled="readOnly" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="报审序号" name="reportNo">
<a-input v-model:value="form.reportNo" :disabled="readOnly" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="合同类别" name="ctrType">
<a-select
v-model:value="form.ctrType"
:disabled="readOnly"
:options="filteredContractTypes('-1')"
class="min-w-[200px]"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="二级类别" name="ctrTwoType">
<a-select
v-model:value="form.ctrTwoType"
:disabled="readOnly"
:options="filteredContractTypes(form.ctrType)"
class="min-w-[200px]"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<!-- <a-form-item label="三级类别" name="ctrThreeType">
<span>{{ form.ctrThreeType }}</span>
</a-form-item> -->
</a-col>
<a-col :span="24">
<a-row :gutter="16">
<a-form-item label="预算金额" name="budgetSum">
<a-input-number
v-model:value="form.budgetSum"
:disabled="readOnly"
:min="0"
class="min-w-[200px]"
/>
</a-form-item>
<a-col :span="3">
<a-form-item :colon="false" label="" name="priceType">
<a-select
v-model:value="form.priceType"
:disabled="readOnly"
:min="0"
:options="dictMap[DICT_TYPE.contract_currency_unit]"
class="w-full min-w-[120px]"
/>
</a-form-item>
</a-col>
</a-row>
</a-col>
<a-col :span="12">
<a-form-item label="资金流向" name="fundAllocation">
<a-select
v-model:value="form.fundAllocation"
:disabled="readOnly"
:options="dictMap[DICT_TYPE.contract_fund_flow]"
class="min-w-[200px]"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="资金渠道" name="fundDitch">
<a-select
v-model:value="form.fundDitch"
:disabled="readOnly"
:options="dictMap[DICT_TYPE.contract_funding_source]"
class="min-w-[200px]"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="框架协议" name="frameProtocol">
<a-radio-group
v-model:value="form.frameProtocol"
:disabled="readOnly"
:options="dictMap[DICT_TYPE.common_whether]"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="框架协议下的合同" name="frameProtocolCtr">
<a-radio-group
v-model:value="form.frameProtocolCtr"
:disabled="readOnly"
:options="dictMap[DICT_TYPE.common_whether]"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="组织方式" name="organiza">
<a-radio-group
v-model:value="form.organiza"
:disabled="readOnly"
:options="dictMap[DICT_TYPE.contract_organization_form]"
class="min-w-[200px]"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="合同附件" name="fileList">
<a-upload
v-model:file-list="form.fileList"
:before-upload="() => false"
:disabled="readOnly"
:max-count="3"
accept=".pdf,.ppt,.pptx"
name="file"
@change="handleChange"
>
<a-button v-if="!readOnly">
<MdiUpload />
点击上传
</a-button>
<div
v-if="readOnly && form.fileList.length === 0"
class="text-gray-700"
>
无附件
</div>
</a-upload>
</a-form-item>
</a-col>
</a-row>
</a-form>
</template>
<style scoped></style>

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