处理一些问题

This commit is contained in:
z9130 2024-09-26 20:53:54 +08:00
parent d2e2d448ad
commit 48fbc140f5
42 changed files with 1463 additions and 713 deletions

View File

@ -79,7 +79,7 @@ export default {
functiontree: { functiontree: {
/** 用户中心 获取菜单接口 */ /** 用户中心 获取菜单接口 */
get_XTBGXT: (data?: QueryOptions) => get_XTBGXT: (data?: QueryOptions) =>
http.get('/uc/sys/user/functiontree/XTBGXT', data), http.get('/uc/sys/user/functiontree/HTGLXT', data),
/** 统一授权 未命名接口 */ /** 统一授权 未命名接口 */
get_PLRL: (data?: QueryOptions) => get_PLRL: (data?: QueryOptions) =>
http.get('/uc/sys/user/functiontree/PLRL', data), http.get('/uc/sys/user/functiontree/PLRL', data),
@ -161,6 +161,9 @@ export default {
get_toDoPage: (data?: QueryOptions) => http.get('/app/ccsq/toDoPage', data), get_toDoPage: (data?: QueryOptions) => http.get('/app/ccsq/toDoPage', data),
/** 协同办公/出差申请 已办 */ /** 协同办公/出差申请 已办 */
get_donePage: (data?: QueryOptions) => http.get('/app/ccsq/donePage', 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) => get_getFlowNodeUserConfig: (data?: QueryOptions) =>
http.get('/app/ccsq/getFlowNodeUserConfig', data), http.get('/app/ccsq/getFlowNodeUserConfig', data),
@ -278,6 +281,9 @@ export default {
/** 协同办公/督查督办/执行反馈 执行反馈已办查询 */ /** 协同办公/督查督办/执行反馈 执行反馈已办查询 */
get_pageDone: (data?: QueryOptions) => get_pageDone: (data?: QueryOptions) =>
http.get('/app/feedback/pageDone', data), http.get('/app/feedback/pageDone', data),
/** 协同办公/督查督办/立项发起 查询立项对应的反馈 */
get_queryFeedback: (data?: QueryOptions) =>
http.get('/app/feedback/queryFeedback', data),
}, },
file: { file: {
/** 协同办公/文件上传/下载 多文件上传 */ /** 协同办公/文件上传/下载 多文件上传 */
@ -381,6 +387,12 @@ export default {
/** 合同系统/申报 退回 */ /** 合同系统/申报 退回 */
post_rollback: (data?: BodyOptions) => post_rollback: (data?: BodyOptions) =>
http.post('/app/sbCtrBasePt/rollback', data), 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: { contractBaseInfo: {
/** 合同系统/立项 合同立项保存 */ /** 合同系统/立项 合同立项保存 */
@ -625,8 +637,8 @@ export default {
get_getContractSignInfo: (data?: QueryOptions) => get_getContractSignInfo: (data?: QueryOptions) =>
http.get('/app/qdSign/getContractSignInfo', data), http.get('/app/qdSign/getContractSignInfo', data),
/** 合同系统/签订 打印签订审批表 */ /** 合同系统/签订 打印签订审批表 */
get_createUserListWord: (data?: QueryOptions) => get_printApprove: (data?: QueryOptions) =>
http.get('/app/qdSign/createUserListWord', data), http.get('/app/qdSign/printApprove', data),
/** 合同系统/签订 打印文本 */ /** 合同系统/签订 打印文本 */
get_textPrint: (data?: QueryOptions) => get_textPrint: (data?: QueryOptions) =>
http.get('/app/qdSign/textPrint', data), http.get('/app/qdSign/textPrint', data),
@ -721,6 +733,9 @@ export default {
/** 公共 获取请求ip */ /** 公共 获取请求ip */
get_getClientIp: (data?: QueryOptions) => get_getClientIp: (data?: QueryOptions) =>
http.get('/app/common/getClientIp', data), http.get('/app/common/getClientIp', data),
/** 公共 获取项目地址 */
get_getProjectAddress: (data?: QueryOptions) =>
http.get('/app/common/getProjectAddress', data),
}, },
address: { address: {
/** 协同办公/订餐管理/订餐地址 查询(分页) */ /** 协同办公/订餐管理/订餐地址 查询(分页) */
@ -772,9 +787,40 @@ export default {
/** 合同系统/选商/选商结果 保存 */ /** 合同系统/选商/选商结果 保存 */
post_save: (data?: BodyOptions) => post_save: (data?: BodyOptions) =>
http.post('/app/biddingResult/save', data), 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),
}, },
home: { home: {
/** 合同系统/首页待办/已办 待办 */ /** 合同系统/首页待办/已办 首页待办 */
get_todo: (data?: QueryOptions) => http.get('/app/home/todo', data), 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),
}, },
}; };

View File

@ -86,20 +86,20 @@ export const alovaInstance = createAlova({
statesHook: vueHook, statesHook: vueHook,
requestAdapter: fetchAdapter(), requestAdapter: fetchAdapter(),
/** 设置缓存状态:不开启 */ /** 设置缓存状态:不开启 */
// cacheFor: null, cacheFor: null,
cacheFor: { // cacheFor: {
// 统一设置POST的缓存模式 // // 统一设置POST的缓存模式
GET: { // GET: {
mode: 'restore', // mode: 'restore',
expire: 60 * 10 * 1000, // expire: 60 * 10 * 1000,
}, // },
// POST: { // // POST: {
// mode: 'restore', // // mode: 'restore',
// expire: 60 * 10 * 1000 // // expire: 60 * 10 * 1000
// }, // // },
// // 统一设置HEAD请求的缓存模式 // // // 统一设置HEAD请求的缓存模式
// HEAD: 60 * 10 * 1000 // // HEAD: 60 * 10 * 1000
}, // },
/** 请求拦截器 */ /** 请求拦截器 */
beforeRequest: onAuthRequired((method) => { beforeRequest: onAuthRequired((method) => {
const accessStore = useAccessStore(); const accessStore = useAccessStore();
@ -194,6 +194,9 @@ export const alovaInstance = createAlova({
}), }),
}); });
// 请求配置处理中间件
function requestConfigMiddleware(method: string, url: string) {}
class Http { class Http {
private appendParamsToUrl(url: string, params: any): string { private appendParamsToUrl(url: string, params: any): string {
let queryString = ''; let queryString = '';

View File

@ -43,7 +43,7 @@ export function transferResponse(response: any) {
code = 0; code = 0;
} }
if (code == 'failure' || (msg && msg.includes('token无效'))) { if (code == 'failure' && msg && msg.includes('token无效')) {
code = 401; code = 401;
} }

View File

@ -1,18 +1,24 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { NotificationItem } from "@vben/layouts"; import type { NotificationItem } from './notification';
import { computed, ref } from "vue"; import { computed, onMounted, ref } from 'vue';
import { storeToRefs, useAccessStore } from "@vben/stores";
import { storeToRefs, useAccessStore, useUserStore } from '@vben/stores';
// import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores'; // import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
import { AuthenticationLoginExpiredModal } from "@vben/common-ui"; import { useRouter } from 'vue-router';
import { BasicLayout, LockScreen, Notification, UserDropdown } from "@vben/layouts";
import { preferences } from "@vben/preferences"; import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
import { useUserStore } from "@vben/stores"; import { PhUserCircle } from '@vben/icons';
import { BookOpenText, CircleHelp, 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';
import { useAuthStore } from "#/store";
import { useRouter } from "vue-router";
const router = useRouter(); const router = useRouter();
const notifications = ref<NotificationItem[]>([ const notifications = ref<NotificationItem[]>([
@ -49,15 +55,17 @@ const notifications = ref<NotificationItem[]>([
const userStore = useUserStore(); const userStore = useUserStore();
const authStore = useAuthStore(); const authStore = useAuthStore();
const accessStore = useAccessStore(); const accessStore = useAccessStore();
const showDot = computed(() => notifications.value.some((item) => !item.isRead)); const showDot = computed(() =>
notifications.value.some((item) => !item.isRead),
);
const menus = computed(() => [ const menus = computed(() => [
{ {
handler: () => { handler: () => {
router.push("/user/center"); router.push('/user/center');
}, },
icon: PhUserCircle, icon: PhUserCircle,
text: "个人中心", text: '个人中心',
}, },
// { // {
// handler: () => { // handler: () => {
@ -98,21 +106,46 @@ function handleMakeAll() {
} }
function handleViewAll() { function handleViewAll() {
console.log("viewAll"); console.log('viewAll');
router.push("/user/todo"); router.push('/user/todo');
} }
const isDev = import.meta.env.MODE === 'development'; const isDev = import.meta.env.MODE === 'development';
const value = ref(localStorage.getItem("@@@proxy_type") || ""); // /zp const value = ref(localStorage.getItem('@@@proxy_type') || ''); // /zp
function handleMenuClick(e) { function handleMenuClick(e) {
console.log(e); console.log(e);
if (e.key == "pro") { if (e.key === 'pro') {
localStorage.setItem("@@@proxy_type", ""); localStorage.setItem('@@@proxy_type', '');
} else { } else {
localStorage.setItem("@@@proxy_type", "/" + e.key); localStorage.setItem('@@@proxy_type', `/${e.key}`);
} }
location.reload() 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> </script>
<template> <template>
@ -130,7 +163,7 @@ function handleMenuClick(e) {
<template #notification> <template #notification>
<a-dropdown v-if="isDev"> <a-dropdown v-if="isDev">
<template #overlay> <template #overlay>
<a-menu @click="handleMenuClick" selectable> <a-menu selectable @click="handleMenuClick">
<a-menu-item key="pro"> 正式 </a-menu-item> <a-menu-item key="pro"> 正式 </a-menu-item>
<a-menu-item key="czg"> czg </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="zp"> zp </a-menu-item>
@ -138,7 +171,7 @@ function handleMenuClick(e) {
<a-menu-item key="xmh"> xmh </a-menu-item> <a-menu-item key="xmh"> xmh </a-menu-item>
</a-menu> </a-menu>
</template> </template>
<a-button> {{ value ? "代理" + value : "代理切换" }} </a-button> <a-button> {{ value ? `代理${value}` : '代理切换' }} </a-button>
</a-dropdown> </a-dropdown>
<Notification <Notification
@ -160,7 +193,11 @@ function handleMenuClick(e) {
/> />
</template> </template>
<template #lock-screen> <template #lock-screen>
<LockScreen :avatar :text="userStore.userInfo?.displayName" @to-login="handleLogout" /> <LockScreen
:avatar
:text="userStore.userInfo?.displayName"
@to-login="handleLogout"
/>
</template> </template>
</BasicLayout> </BasicLayout>
</template> </template>

View File

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

View File

@ -0,0 +1,187 @@
<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

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

View File

@ -3,6 +3,12 @@ import { unmountGlobalLoading } from '@vben/utils';
import { overridesPreferences } from './preferences'; import { overridesPreferences } from './preferences';
// const dict = new Dictionary(http.get, {});
// dict.getAll('dict').then((res) => {
// console.log('dict', res);
// });
/** /**
* *
*/ */

View File

@ -7,10 +7,11 @@ import { startProgress, stopProgress } from '@vben/utils';
import { useTitle } from '@vueuse/core'; import { useTitle } from '@vueuse/core';
import Apis from '#/api';
import { $t } from '#/locales'; import { $t } from '#/locales';
import { coreRouteNames, dynamicRoutes } from '#/router/routes'; import { coreRouteNames, dynamicRoutes } from '#/router/routes';
import { useAuthStore } from '#/store'; import { useAuthStore } from '#/store';
import Apis from '#/api';
import { generateAccess } from './access'; import { generateAccess } from './access';
/** /**
@ -57,8 +58,12 @@ function setupCommonGuard(router: Router) {
* permission.path = "/xx/edit" route.path = "/xx/edit/:id?" id可以为任意值meetingId roleId等 * permission.path = "/xx/edit" route.path = "/xx/edit/:id?" id可以为任意值meetingId roleId等
*/ */
function matchPaths(routePath, permissionPath) { function matchPaths(routePath, permissionPath) {
const routeParts = routePath.split('/'); const routeParts = routePath.path.split('/');
const permissionParts = permissionPath.split('/'); const permissionParts = permissionPath.path.split('/');
if (routePath.name === permissionPath.id) {
return true;
}
if (permissionParts.length > routeParts.length) { if (permissionParts.length > routeParts.length) {
return false; return false;
@ -72,13 +77,14 @@ function matchPaths(routePath, permissionPath) {
// 过滤路由,只保留第三个数据源配置的路由 // 过滤路由,只保留第三个数据源配置的路由
function filterRoutesByPermissions(routes, permissions, staticRouteKeys) { function filterRoutesByPermissions(routes, permissions, staticRouteKeys) {
const filteredRoutes = []; const filteredRoutes = [];
for (let route of routes) { for (const route of routes) {
// console.log('[ route ] >', route) // console.log('[ route ] >', route)
// console.log('[ permission.path ] >', permissions) // console.log('[ permission.path ] >', permissions)
const permission = permissions.find(permission => const permission = permissions.find((permission) =>
matchPaths(route.path, permission.path) matchPaths(route, permission),
); );
const isStaticRoute = staticRouteKeys.includes(route.name); const isStaticRoute = staticRouteKeys.includes(route.name);
if (permission || isStaticRoute) { if (permission || isStaticRoute) {
@ -89,16 +95,18 @@ function filterRoutesByPermissions(routes, permissions, staticRouteKeys) {
title: permission.name, title: permission.name,
}; };
if (permission.order) { if (permission.order) {
newRoute.meta.order = permission.order newRoute.meta.order = permission.order;
} }
} }
if (route.children) { if (route.children) {
newRoute.children = filterRoutesByPermissions(route.children, permissions, staticRouteKeys); newRoute.children = filterRoutesByPermissions(
route.children,
permissions,
staticRouteKeys,
);
} }
filteredRoutes.push(newRoute); filteredRoutes.push(newRoute);
// console.log(JSON.parse(JSON.stringify(filteredRoutes))); // console.log(JSON.parse(JSON.stringify(filteredRoutes)));
} }
} }
@ -159,16 +167,28 @@ function setupAccessGuard(router: Router) {
// 二开从统一授权获取菜单key值遍历本地所有菜单进行添加 // 二开从统一授权获取菜单key值遍历本地所有菜单进行添加
let staticRouteKeys = ["Dashboard", "home", "User", "UserCenter", "UserTodo","IFrame","MeetingStandingBook","MeetingStart","DutyStandingBook","ContractInfo"]; const staticRouteKeys = [
'Dashboard',
'home',
'User',
'UserCenter',
'UserTodo',
'IFrame',
'MeetingStandingBook',
'MeetingStart',
'DutyStandingBook',
'ContractInfo',
];
let r = await Apis.sys.user.functiontree.get_XTBGXT() const r = await Apis.sys.user.functiontree.get_XTBGXT();
let originRouters = r.rows[0].children; let originRouters = r.rows[0].children;
// 提取数据的函数 // 提取数据的函数
const extractData = (input: any[]) => { const extractData = (input: any[]) => {
const result: any[] = []; const result: any[] = [];
function traverse(node: any) { function traverse(node: any) {
if (node.id && node.name && node.remark) { if (node.id && node.name) {
result.push({ result.push({
id: node.id,
path: node.remark, path: node.remark,
name: node.name, name: node.name,
order: node.showOrder || 0, order: node.showOrder || 0,
@ -186,26 +206,28 @@ function setupAccessGuard(router: Router) {
} }
return result; return result;
} };
// console.log('originRouters', originRouters) // console.log('originRouters', originRouters)
originRouters = extractData(originRouters); originRouters = extractData(originRouters);
// console.log('originRouters', originRouters) // console.log('originRouters', originRouters)
let finalRoutes = filterRoutesByPermissions(dynamicRoutes, originRouters, staticRouteKeys); let finalRoutes = filterRoutesByPermissions(
dynamicRoutes,
console.log(originRouters) originRouters,
staticRouteKeys,
);
console.log(originRouters);
// console.log('finalRoutes', finalRoutes) // console.log('finalRoutes', finalRoutes)
// console.log('dynamicRoutes', dynamicRoutes) // console.log('dynamicRoutes', dynamicRoutes)
// console.log('userInfo', userInfo) // console.log('userInfo', userInfo)
if (userInfo.accountId == 'Admin.itl'|| userInfo._isSkip) { if (userInfo.accountId == 'Admin.itl' || userInfo._isSkip) {
finalRoutes = dynamicRoutes; finalRoutes = dynamicRoutes;
} }
// console.log(userInfo) // console.log(userInfo)
// 生成菜单和路由 // 生成菜单和路由
const { accessibleMenus, accessibleRoutes } = await generateAccess({ const { accessibleMenus, accessibleRoutes } = await generateAccess({
roles: userRoles, roles: userRoles,

View File

@ -9,7 +9,7 @@ const routes: RouteRecordRaw[] = [
icon: 'lucide:layout-dashboard', icon: 'lucide:layout-dashboard',
title: '合同配置', title: '合同配置',
}, },
name: 'ContractConfig', name: 'HTGLHTPZ',
path: '/contract/config', path: '/contract/config',
children: [ children: [
{ {
@ -25,7 +25,7 @@ const routes: RouteRecordRaw[] = [
], ],
}, },
{ {
name: 'ContractApproval', name: 'HTGLHTLX',
path: '/contract/approval', path: '/contract/approval',
component: BasicLayout, component: BasicLayout,
meta: { meta: {
@ -80,7 +80,7 @@ const routes: RouteRecordRaw[] = [
], ],
}, },
{ {
name: 'ContractBusiness', name: 'HTGLHTXS',
path: '/contract/business', path: '/contract/business',
component: BasicLayout, component: BasicLayout,
meta: { meta: {
@ -127,7 +127,7 @@ const routes: RouteRecordRaw[] = [
], ],
}, },
{ {
name: 'ContractDeclaration', name: 'HTGLHTSB',
path: '/contract/declaration', path: '/contract/declaration',
component: BasicLayout, component: BasicLayout,
meta: { meta: {
@ -212,7 +212,7 @@ const routes: RouteRecordRaw[] = [
// ], // ],
// }, // },
{ {
name: 'ContractSign', name: 'HTGLHTQD',
path: '/contract/sign', path: '/contract/sign',
component: BasicLayout, component: BasicLayout,
meta: { meta: {
@ -241,7 +241,7 @@ const routes: RouteRecordRaw[] = [
], ],
}, },
{ {
name: 'ContractPerform', name: 'HTGLHTLVX',
path: '/contract/perform', path: '/contract/perform',
component: BasicLayout, component: BasicLayout,
meta: { meta: {
@ -307,7 +307,7 @@ const routes: RouteRecordRaw[] = [
], ],
}, },
{ {
name: 'ContractArchive', name: 'HTGLHTGD',
path: '/contract/archive', path: '/contract/archive',
component: BasicLayout, component: BasicLayout,
meta: { meta: {
@ -347,7 +347,7 @@ const routes: RouteRecordRaw[] = [
], ],
}, },
{ {
name: 'ContractSignAuthorization', name: 'HTGLHTQYSQ',
path: '/contract/sign-authorization', path: '/contract/sign-authorization',
component: BasicLayout, component: BasicLayout,
meta: { meta: {
@ -385,7 +385,7 @@ const routes: RouteRecordRaw[] = [
], ],
}, },
{ {
name: 'ContractCompany', name: 'HTGLHTXDR',
path: '/contract/company', path: '/contract/company',
component: BasicLayout, component: BasicLayout,
meta: { meta: {

View File

@ -11,7 +11,6 @@ import { notification } from 'ant-design-vue';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { getUserInfoApi, loginApi } from '#/api/system/auth'; import { getUserInfoApi, loginApi } from '#/api/system/auth';
import { $t } from '#/locales'; import { $t } from '#/locales';
export const useAuthStore = defineStore('auth', () => { export const useAuthStore = defineStore('auth', () => {
@ -34,20 +33,20 @@ export const useAuthStore = defineStore('auth', () => {
let userInfo: null | UserInfo = null; let userInfo: null | UserInfo = null;
try { try {
loginLoading.value = true; loginLoading.value = true;
if(params.username == 'Admin.itl' || params._isSkip){ if (params.username == 'Admin.itl' || params._isSkip) {
}else{ } else {
params.username = params.username + '.RL' params.username = `${params.username}.RL`;
} }
const loginRes = await loginApi({ const loginRes = await loginApi({
...params, ...params,
appId: 'PLRL', appId: 'HTGLXT',
appName: 'ERP管理系统', appName: '合同管理系统',
appSecret: 'r1og4wiyrrvr4qvw2aafhgvy', appSecret: 'r1og4wiyrrvr4qvw2aafhgvy',
}); });
console.log(loginRes); console.log(loginRes);
if (params._isSkip) { if (params._isSkip) {
loginRes._isSkip = params._isSkip loginRes._isSkip = params._isSkip;
} }
loginInfo = JSON.stringify(loginRes); loginInfo = JSON.stringify(loginRes);
@ -63,7 +62,7 @@ export const useAuthStore = defineStore('auth', () => {
userInfo = fetchUserInfoResult; userInfo = fetchUserInfoResult;
if (params._isSkip) { if (params._isSkip) {
userInfo._isSkip = params._isSkip userInfo._isSkip = params._isSkip;
} }
userStore.setUserInfo(userInfo); userStore.setUserInfo(userInfo);
@ -102,8 +101,8 @@ export const useAuthStore = defineStore('auth', () => {
path: LOGIN_PATH, path: LOGIN_PATH,
query: redirect query: redirect
? { ? {
redirect: encodeURIComponent(router.currentRoute.value.fullPath), redirect: encodeURIComponent(router.currentRoute.value.fullPath),
} }
: {}, : {},
}); });
} }
@ -111,7 +110,7 @@ export const useAuthStore = defineStore('auth', () => {
async function fetchUserInfo() { async function fetchUserInfo() {
let userInfo: null | UserInfo = null; let userInfo: null | UserInfo = null;
userInfo = await getUserInfoApi(); userInfo = await getUserInfoApi();
userInfo = { ...JSON.parse(loginInfo), ...userInfo } userInfo = { ...JSON.parse(loginInfo), ...userInfo };
userStore.setUserInfo(userInfo); userStore.setUserInfo(userInfo);
return userInfo; return userInfo;
} }

View File

@ -1,5 +1,7 @@
import { defineStore } from 'pinia';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { defineStore } from 'pinia';
// import { getDictDataList } from '@/api/system/dict'; // import { getDictDataList } from '@/api/system/dict';
import Apis from '#/api'; import Apis from '#/api';
import dataModule from '#/utils/dict/static.data'; import dataModule from '#/utils/dict/static.data';
@ -9,7 +11,7 @@ const DICT_STORAGE_KEY = 'DICT_KEY';
interface DictDataVO { interface DictDataVO {
dictType: string; dictType: string;
label: string; label: string;
value: string | number | null; value: null | number | string;
colorType: string; colorType: string;
cssClass: string; cssClass: string;
} }
@ -37,7 +39,7 @@ export const useDictStore = defineStore('app-dict', () => {
const setDictMap = async (): Promise<boolean> => { const setDictMap = async (): Promise<boolean> => {
try { try {
const data = await Apis.dictData.get_page({ const data = await Apis.dictData.get_page({
params: { pageNum: 1, pageSize: 10000 }, params: { pageNum: 1, pageSize: 10_000 },
}); });
const dictDataMap: Record<string, DictDataVO[]> = {}; const dictDataMap: Record<string, DictDataVO[]> = {};
// 处理静态字典数据 // 处理静态字典数据
@ -85,38 +87,45 @@ export const useDictStore = defineStore('app-dict', () => {
const getDictData = async ( const getDictData = async (
dictTypeArr: string[], dictTypeArr: string[],
): Promise<Record<string, DictDataVO[]>> => { ): Promise<Record<string, DictDataVO[]>> => {
if (initDict.value) { const newDictMap: Record<string, DictDataVO[]> = {};
const newDictMap: Record<string, DictDataVO[]> = {};
if (isSetDict.value && Object.keys(dictMap.value).length) { return await new Promise((resolve) => {
if (
initDict.value &&
isSetDict.value &&
Object.keys(dictMap.value).length > 0
) {
dictTypeArr.forEach((dictType) => { dictTypeArr.forEach((dictType) => {
newDictMap[dictType] = dictMap.value[dictType] || []; newDictMap[dictType] = dictMap.value[dictType] || [];
}); });
return newDictMap; resolve(newDictMap);
} }
if (!isSetDict.value) { // if (!isSetDict.value) {
console.warn('字典数据尚未加载,正在等待...'); // console.warn('字典数据尚未加载,正在等待...');
await new Promise((resolve) => {
const checkInterval = setInterval(() => {
if (isSetDict.value) {
clearInterval(checkInterval);
dictTypeArr.forEach((dictType) => {
newDictMap[dictType] = dictMap.value[dictType] || [];
});
resolve(true);
}
}, 45);
});
return newDictMap;
}
}
try { // const checkInterval = setInterval(() => {
return {}; // console.warn('字典数据加载中...');
} catch (error) {
console.error('getDictMap 函数报错:', error); // if (isSetDict.value) {
return {}; // 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);
});
}; };
/** /**

View File

@ -1,4 +1,3 @@
/** 数据字典工具类 */ /** 数据字典工具类 */
import { useDictStore } from '#/store/dict'; import { useDictStore } from '#/store/dict';
@ -15,7 +14,7 @@ const dictStore = useDictStore();
export interface DictDataType { export interface DictDataType {
dictTyp?: string; dictTyp?: string;
label: string; label: string;
value: string | number | null; value: null | number | string;
key?: any; key?: any;
colorType?: string; colorType?: string;
cssClass?: string; cssClass?: string;
@ -24,7 +23,7 @@ export interface DictDataType {
export interface DictDataOptions { export interface DictDataOptions {
label?: any; label?: any;
value?: string | number | null; value?: null | number | string;
} }
export function getDictDatas(dictType: string) { export function getDictDatas(dictType: string) {
@ -40,7 +39,10 @@ export function getDictOpts(dictType: string) {
return getDictDatas(dictType); return getDictDatas(dictType);
} }
export function getDictOptions(dictType: string, valueType?: 'string' | 'number' | 'boolean'): any[] { export function getDictOptions(
dictType: string,
valueType?: 'boolean' | 'number' | 'string',
): any[] {
const dictOption: DictDataType[] = []; const dictOption: DictDataType[] = [];
valueType ||= 'string'; valueType ||= 'string';
@ -55,7 +57,7 @@ export function getDictOptions(dictType: string, valueType?: 'string' | 'number'
? `${dict.value}` ? `${dict.value}`
: valueType === 'boolean' : valueType === 'boolean'
? `${dict.value}` === 'true' ? `${dict.value}` === 'true'
: Number.parseInt(`${dict.value}`) : Number.parseInt(`${dict.value}`),
}); });
}); });
} }
@ -68,7 +70,11 @@ export function getDictObj(dictType: string, value: any): DictDataType | null {
const dictOptions: DictDataType[] = getDictDatas(dictType); const dictOptions: DictDataType[] = getDictDatas(dictType);
if (dictOptions) { if (dictOptions) {
if (value) { if (value) {
return dictOptions.find((dict: DictDataType) => dict.value === value.toString()) || null; return (
dictOptions.find(
(dict: DictDataType) => dict.value === value.toString(),
) || null
);
} }
return null; return null;
} else { } else {
@ -79,9 +85,8 @@ export function getDictObj(dictType: string, value: any): DictDataType | null {
/** 获取字典默认数据 */ /** 获取字典默认数据 */
export function getDictDefaultObj(dictType: string): DictDataType | null { export function getDictDefaultObj(dictType: string): DictDataType | null {
const dictOptions: DictDataType[] = getDictDatas(dictType); const dictOptions: DictDataType[] = getDictDatas(dictType);
if (dictOptions) { return dictOptions
return dictOptions.find((dict: DictDataType) => dict.isDefault == '1') || dictOptions[0]; ? dictOptions.find((dict: DictDataType) => dict.isDefault == '1') ||
} else { dictOptions[0]
return null; : null;
}
} }

View File

@ -51,5 +51,7 @@ export enum DICT_TYPE {
/** 合同立项节点流程 */ /** 合同立项节点流程 */
contract_abolish_flow_node = 'contract_abolish_flow_node', contract_abolish_flow_node = 'contract_abolish_flow_node',
/** 合同授权期限 */ /** 合同授权期限 */
contract_authorization_period = 'contract_authorization_period' contract_authorization_period = 'contract_authorization_period',
/** 合同待办类型 */
contract_todo_type = 'contract_todo_type'
} }

View File

@ -89,7 +89,22 @@ export default {
// 授权期限 // 授权期限
contract_authorization_period: createEntry('合同授权期限', [ contract_authorization_period: createEntry('合同授权期限', [
{ label: '确定', value: 'forever' }, { label: '确定', value: '0' },
{ label: '不确定', value: 'date' }, { label: '不确定', value: '1' },
]),
// 合同待办类型
contract_todo_type: createEntry('合同待办类型', [
{ label: '合同立项', value: 'contractSetup' },
{ label: '合同立项废除', value: 'contractSetupAbolish' },
{ label: '合同选商', value: 'selectMerchant' },
{ label: '合同选商废除', value: 'selectMerchantAbolish' },
{ label: '合同选商结果', value: 'selectMerchantResult' },
{ label: '合同选商结果废除', value: 'selectMerchantResultAbolish' },
{ label: '合同申报', value: 'contractDeclare' },
{ label: '合同签订', value: 'contractSign' },
{ label: '合同履行', value: 'contractPerform' },
{ label: '合同归档', value: 'contractFile' },
{ label: '签约授权', value: 'signAuthorization' },
]), ]),
}; };

View File

@ -49,7 +49,7 @@ export function getFormSchema(params: any = {}) {
class: 'min-w-[200px]', class: 'min-w-[200px]',
prototype: true, prototype: true,
dict: dict({ dict: dict({
async getData({ form = {} }) { async getData(_context) {
return filterContractTypes(contractTypeData, '-1'); return filterContractTypes(contractTypeData, '-1');
}, },
}), }),

View File

@ -186,8 +186,9 @@ onMounted(async () => {
<template #operate="{ row }"> <template #operate="{ row }">
<a-button <a-button
class="text-primary"
size="small" size="small"
type="primary" type="text"
@click="toDetailPage('approval', row.guid)" @click="toDetailPage('approval', row.guid)"
> >
查看 查看

View File

@ -1,12 +1,16 @@
<script lang="tsx" setup> <script lang="tsx" setup>
import { ref, nextTick } from 'vue'; import { nextTick, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui'; import { useVbenModal } from '@vben/common-ui';
import dayjs, { Dayjs } from 'dayjs'; import { MdiCloudUpload } from '@vben/icons';
import Apis from '#/api';
import { message, type UploadChangeParam } from 'ant-design-vue';
import { FileUploader } from '#/utils/file';
import { dict } from '@fast-crud/fast-crud'; import { dict } from '@fast-crud/fast-crud';
import { DICT_TYPE, getDictOptions, getDictObj } from '#/utils/dict'; 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<{ const emit = defineEmits<{
(e: 'success'): void; (e: 'success'): void;
@ -20,7 +24,7 @@ const data = ref({
}); });
const formRef = ref(); const formRef = ref();
let isConfirmLoading = ref(false); const isConfirmLoading = ref(false);
const formBinding = ref({ const formBinding = ref({
col: { span: 24 }, col: { span: 24 },
@ -35,8 +39,8 @@ const formBinding = ref({
vModel: 'value', vModel: 'value',
allowClear: true, allowClear: true,
dict: dict({ dict: dict({
async getData(form) { async getData() {
return getDictOptions(DICT_TYPE.contract_basis_type); return await getDictOptions(DICT_TYPE.contract_basis_type);
}, },
}), }),
}, },
@ -81,7 +85,7 @@ const formBinding = ref({
component: { component: {
name: 'a-textarea', name: 'a-textarea',
vModel: 'value', vModel: 'value',
props: {}, autoSize: { minRows: 4, maxRows: 6 },
}, },
}, },
fileList: { fileList: {
@ -93,7 +97,7 @@ const formBinding = ref({
const handleChange = (info: UploadChangeParam) => { const handleChange = (info: UploadChangeParam) => {
formRef.value.setFormData({ formRef.value.setFormData({
fileList: info.fileList.length ? info.fileList : [], fileList: info.fileList.length > 0 ? info.fileList : [],
}); });
}; };
@ -105,7 +109,7 @@ const [BaseModal, baseModalApi] = useVbenModal({
data.value = baseModalApi.getData<Record<string, any>>() || {}; data.value = baseModalApi.getData<Record<string, any>>() || {};
if (data.value.isUpdate) { if (data.value.isUpdate) {
if (data.value.record.fileUuid) { if (data.value.record.fileUuid) {
let files = await fileUploader.select(data.value.record.fileUuid); const files = await fileUploader.select(data.value.record.fileUuid);
console.log(files); console.log(files);
data.value.record.fileList = files; data.value.record.fileList = files;
} }
@ -123,11 +127,11 @@ const [BaseModal, baseModalApi] = useVbenModal({
console.log(formRef.value?.form); console.log(formRef.value?.form);
await formRef.value?.submit(); await formRef.value?.submit();
let form = formRef.value.form; const form = formRef.value.form;
{ {
let tempFileList = form.fileList; const tempFileList = form.fileList;
let tempFiles: any = []; let tempFiles: any = [];
if (tempFileList && tempFileList.length) { if (tempFileList && tempFileList.length > 0) {
tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' }); tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
} }
console.log(tempFiles); console.log(tempFiles);
@ -142,7 +146,7 @@ const [BaseModal, baseModalApi] = useVbenModal({
if (form.basisTypeId) { if (form.basisTypeId) {
form.basisTypeName = getDictObj( form.basisTypeName = getDictObj(
DICT_TYPE.contract_basis_type, DICT_TYPE.contract_basis_type,
row.basisTypeId, form.basisTypeId,
)?.label; )?.label;
} }
@ -163,18 +167,18 @@ const [BaseModal, baseModalApi] = useVbenModal({
</script> </script>
<template> <template>
<BaseModal <BaseModal
:title="data.isUpdate ? '修改签约依据信息' : '新增签约依据信息'" :confirm-loading="isConfirmLoading"
:loading="isConfirmLoading" :loading="isConfirmLoading"
:confirmLoading="isConfirmLoading" :title="data.isUpdate ? '修改签约依据信息' : '新增签约依据信息'"
> >
<fs-form ref="formRef" v-bind="formBinding"> <fs-form ref="formRef" v-bind="formBinding">
<template #form_fileList="{ form }"> <template #form_fileList="{ form }">
<a-upload-dragger <a-upload-dragger
v-model:fileList="form.fileList" v-model:file-list="form.fileList"
accept=".pdf"
:max-count="1"
name="file"
:before-upload="() => false" :before-upload="() => false"
:max-count="1"
accept=".pdf"
name="file"
@change="handleChange" @change="handleChange"
> >
<div class="flex flex-col items-center"> <div class="flex flex-col items-center">

View File

@ -1,12 +1,163 @@
<script setup lang="ts">
import { onMounted, reactive } from 'vue';
import { Page } from '@vben/common-ui';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const { xGridRef: xGrid2Ref, triggerProxy: triggerProxy2 } = useVxeTable({
ref: 'xGrid2Ref',
});
/** 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.home.get_todo({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
},
});
},
},
},
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.home.get_done({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
},
});
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: false,
},
}),
);
onMounted(() => {});
//
</script>
<template> <template>
<Page contentClass="h-full flex flex-col"> <Page content-class="h-full flex flex-col">
<a-space direction="vertical" size="small"> <a-space class="flex h-full flex-col" direction="vertical" size="small">
<a-card title="待办" size="small"> <a-card
:body-style="{ flex: '1' }"
class="flex h-full flex-col"
size="small"
title="待办"
>
<vxe-grid ref="xGridRef" v-bind="gridOptions"> <vxe-grid ref="xGridRef" v-bind="gridOptions">
<template #toolbar_buttons> </template> <template #toolbar_buttons> </template>
</vxe-grid> </vxe-grid>
</a-card> </a-card>
<a-card title="已办" size="small" contentClass=""> <a-card
:body-style="{ flex: '1' }"
class="flex h-full flex-col"
size="small"
title="已办"
>
<vxe-grid ref="xGrid2Ref" v-bind="grid2Options"> <vxe-grid ref="xGrid2Ref" v-bind="grid2Options">
<template #toolbar_buttons> </template> <template #toolbar_buttons> </template>
</vxe-grid> </vxe-grid>
@ -15,168 +166,8 @@
</Page> </Page>
</template> </template>
<script setup lang="ts"> <style scoped>
import { defineComponent, ref, reactive, onMounted } from 'vue'; :deep(.ant-space-item) {
import { FsCrud } from '@fast-crud/fast-crud'; flex: 1;
import { type VxeGridProps } from 'vxe-table' }
import { Page, useVbenModal } from '@vben/common-ui'; </style>
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,7 +1,11 @@
import type { VxeGridPropTypes } from 'vxe-table'; import type { VxeGridPropTypes } from 'vxe-table';
import { h } from 'vue'; import { h } from 'vue';
import { Tooltip } from 'ant-design-vue'; import { Tooltip } from 'ant-design-vue';
import { DICT_TYPE, getDictObj } from '#/utils/dict';
export const PrimaryKey = 'guid'; export const PrimaryKey = 'guid';
/** 获取待办/已办列表的列 */ /** 获取待办/已办列表的列 */
@ -10,33 +14,35 @@ export function getTodoColumns(_params: any = {}): VxeGridPropTypes.Columns {
{ type: 'seq', width: 50, align: 'center', fixed: 'left' }, { type: 'seq', width: 50, align: 'center', fixed: 'left' },
{ field: 'contractId', title: '编号', width: 100 }, { field: 'contractId', title: '编号', width: 100 },
{ {
field: 'title', field: 'contractName',
title: '名称', title: '名称',
minWidth: 200, minWidth: 200,
slots: { default: 'title_slot' },
},
{
field: 'module',
title: '模块',
width: 150,
slots: { slots: {
default: ({ row }) => { default: ({ row }) => {
let text = row.title; return (
if (text) { getDictObj(DICT_TYPE.contract_todo_type, row.module)?.label || ''
let classArr: string[] = ['line-clamp-3']; );
return h(
Tooltip,
{ trigger: 'hover' },
{
trigger: () => h('span', { class: classArr.join(' ') }, text),
default: () => text,
},
);
}
return '';
}, },
}, },
}, },
{ field: 'contractAmount', title: '模块', width: 150 }, { field: 'taskName', title: '任务', width: 200 },
{ field: 'contractSubject', title: '任务', width: 200 }, { field: 'createTime', title: '分配时间', width: 150 },
{ field: 'contractCounterparty', title: '分配时间', width: 150 }, { field: 'inputDepartName', title: '承办单位/部门', width: 150 },
{ field: 'cumulativeSettlementAmount', title: '承办单位/部门', width: 150 }, { field: 'assignee', title: '承办人', width: 100 },
{ field: 'changeCount', title: '承办人', width: 100 }, {
{ field: 'contractStatus', title: '交接给', width: 100 }, field: 'operate',
title: '操作',
width: 60,
fixed: 'right',
slots: { default: 'operate' },
},
// { field: 'contractStatus', title: '交接给', width: 100 },
]; ];
} }
@ -53,9 +59,9 @@ export function getApprovalColumns(
minWidth: 200, minWidth: 200,
slots: { slots: {
default: ({ row }) => { default: ({ row }) => {
let text = row.title; const text = row.title;
if (text) { if (text) {
let classArr: string[] = ['line-clamp-3']; const classArr: string[] = ['line-clamp-3'];
return h( return h(
Tooltip, Tooltip,
{ trigger: 'hover' }, { trigger: 'hover' },

View File

@ -3,10 +3,12 @@ import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui'; import { useVbenModal } from '@vben/common-ui';
import { dict } from '@fast-crud/fast-crud'; import { dict } from '@fast-crud/fast-crud';
import { message } from 'ant-design-vue';
import dayjs, { type Dayjs } from 'dayjs';
import { VxeGrid, type VxeGridPropTypes } from 'vxe-table'; import { VxeGrid, type VxeGridPropTypes } from 'vxe-table';
import { unitComponentProps } from '#/common/unit'; import { unitComponentProps } from '#/common/unit';
import { DICT_TYPE, getDictOptions } from '#/utils/dict'; import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict';
import chooseUserModal from '#/views/system/user/choose-user-modal.vue'; import chooseUserModal from '#/views/system/user/choose-user-modal.vue';
const [ChooseUserModal, chooseUserModalApi] = useVbenModal({ const [ChooseUserModal, chooseUserModalApi] = useVbenModal({
@ -23,7 +25,8 @@ export function getUserColumns(_params?: any): VxeGridPropTypes.Columns {
]; ];
} }
export function getFormSchema(_params?: any): any { export function getFormSchema(params?: any): any {
const { formRef } = params || {};
const xGridRef = ref(); const xGridRef = ref();
/** Hooks - 表格 */ /** Hooks - 表格 */
@ -38,67 +41,99 @@ export function getFormSchema(_params?: any): any {
}, },
}; };
const disabledDate = (current: Dayjs) => {
const form = formRef.value.form;
return current && current < dayjs(form.consignDateBegin);
};
const handleUpdateFormattedValue = () => {
const { consignDateBegin, consignDateEnd } = formRef.value.form;
if (
consignDateBegin &&
consignDateEnd &&
consignDateEnd < consignDateBegin
) {
message.error('截止时间不能早于开始时间');
formRef.value.setFormData({
consignDateEnd: '',
});
}
};
return { return {
col: { span: 24 }, col: { span: 24 },
initialForm: { initialForm: {
entrustUserName: '克拉玛依市热力有限责任公司',
lawUserId: '',
lawUserName: '吴兴明',
positionName: '经理',
contractName: '', contractName: '',
priceType: 'CNY', priceType: 'CNY',
isBid: '0', isBid: '0',
}, },
labelCol: { style: { width: '120px' } }, labelCol: { style: { width: '120px' } },
columns: { columns: {
projectNum: { entrustUserName: {
title: '委托人', title: '委托人',
key: 'projectNum', key: 'entrustUserName',
col: { span: 12 }, col: { span: 8 },
component: { component: {
name: 'a-input', name: 'a-input',
vModel: 'value', vModel: 'value',
allowClear: false, allowClear: false,
}, },
render({ form }) { render({ form }) {
return <span>{form.projectNum}</span>; return <span>{form.entrustUserName}</span>;
}, },
}, },
projectProp: { lawUserName: {
title: '法定代表人', title: '法定代表人',
key: 'projectProp', key: 'lawUserName',
col: { span: 12 }, col: { span: 8 },
component: { component: {
name: 'a-input', name: 'a-input',
vModel: 'value', vModel: 'value',
allowClear: false, allowClear: false,
}, },
render(_context) { render({ form }) {
return <span></span>; return <span>{form.lawUserName}</span>;
}, },
}, },
projectProp1: { positionName: {
title: '职务', title: '职务',
key: 'projectProp1', key: 'positionName',
col: { span: 12 }, col: { span: 8 },
component: { component: {
name: 'a-input', name: 'a-input',
vModel: 'value', vModel: 'value',
allowClear: false, allowClear: false,
}, },
render(_context) { render({ form }) {
return <span></span>; return <span>{form.positionName}</span>;
}, },
}, },
projectProp2: { consignType: {
title: '授权类型', title: '授权类型',
key: 'projectProp2', key: 'consignType',
col: { span: 12 }, col: { span: 24 },
component: { component: {
name: 'fs-dict-select', name: 'fs-dict-radio',
vModel: 'value', vModel: 'value',
allowClear: false, allowClear: false,
class: 'w-[200px]',
dict: dict({ dict: dict({
data: getDictOptions(DICT_TYPE.contract_authorization_type), data: getDictOptions(DICT_TYPE.contract_authorization_type),
}), }),
}, },
valueChange: {
immediate: true, // 是否立即执行一次
handle({ form }) {
form.consignTypeName = getDictObj(
DICT_TYPE.contract_authorization_type,
form.consignType,
)?.label;
},
},
}, },
projectNum5: { projectNum5: {
title: '受托人', title: '受托人',
@ -142,9 +177,9 @@ export function getFormSchema(_params?: any): any {
}, },
}, },
}, },
isBid: { isconsignDate: {
title: '授权期限', title: '授权期限',
key: 'isBid', key: 'isconsignDate',
col: { span: 24 }, col: { span: 24 },
render({ form }) { render({ form }) {
// 注意此处的v-model写法 // 注意此处的v-model写法
@ -156,21 +191,48 @@ export function getFormSchema(_params?: any): any {
return ( return (
<div class="flex"> <div class="flex">
<a-form-item class="!mb-0 inline-block"> <a-form-item class="!mb-0 inline-block">
<a-radio-group options={options1} v-model:value={form.isBid} /> <a-radio-group
options={options1}
v-model:value={form.isconsignDate}
/>
</a-form-item> </a-form-item>
<div class="w-2"></div> <div class="w-2"></div>
{form.isBid === 1 && ( {form.isconsignDate === '0' && (
<div class="flex">
<a-form-item class="!mb-0 inline-block">
<a-date-picker
format="YYYY-MM-DD"
onChange={handleUpdateFormattedValue}
placeholder=""
v-model:value={form.consignDateBegin}
value-format="YYYY-MM-DD"
/>
</a-form-item>
<span class="mx-1"></span>
<a-form-item class="!mb-0 inline-block">
<a-date-picker
disabledDate={disabledDate}
format="YYYY-MM-DD"
onChange={handleUpdateFormattedValue}
placeholder=""
v-model:value={form.consignDateEnd}
value-format="YYYY-MM-DD"
/>
</a-form-item>
</div>
)}
{form.isconsignDate === '1' && (
<a-form-item class="!mb-0 inline-block" label=""> <a-form-item class="!mb-0 inline-block" label="">
<a-input v-model:value={form.budgetSum2} /> <a-input v-model:value={form.consignDescribe} />
</a-form-item> </a-form-item>
)} )}
</div> </div>
); );
}, },
}, },
remark: { remarks: {
title: '备注', title: '备注',
key: 'remark', key: 'remarks',
col: { span: 24 }, col: { span: 24 },
component: { component: {
name: 'a-textarea', name: 'a-textarea',
@ -199,6 +261,8 @@ export function getFormSchemaByAuthRange(params?: any): any {
const { contractTypeData, readOnly = false } = params || {}; const { contractTypeData, readOnly = false } = params || {};
return { return {
col: { span: 24 },
labelCol: { style: { width: '120px' } },
initialForm: { initialForm: {
priceType: 'CNY', priceType: 'CNY',
}, },
@ -218,7 +282,7 @@ export function getFormSchemaByAuthRange(params?: any): any {
component: { component: {
name: 'fs-dict-select', name: 'fs-dict-select',
vModel: 'value', vModel: 'value',
class: 'min-w-[200px]', class: 'min-w-[180px]',
prototype: true, prototype: true,
dict: dict({ dict: dict({
async getData(_context) { async getData(_context) {
@ -255,7 +319,7 @@ export function getFormSchemaByAuthRange(params?: any): any {
component: { component: {
name: 'fs-dict-select', name: 'fs-dict-select',
vModel: 'value', vModel: 'value',
class: 'min-w-[200px]', class: 'min-w-[180px]',
prototype: true, prototype: true,
dict: dict({ dict: dict({
async getData({ form = {} }) { async getData({ form = {} }) {
@ -288,14 +352,14 @@ export function getFormSchemaByAuthRange(params?: any): any {
<a-form-item class="!mb-0 inline-block"> <a-form-item class="!mb-0 inline-block">
<a-input-number <a-input-number
placeholder="" placeholder=""
v-model:value={form.budgetSum1} v-model:value={form.contractMoneyDown}
/> />
</a-form-item> </a-form-item>
<span class="mx-1"></span> <span class="mx-1"></span>
<a-form-item class="!mb-0 inline-block"> <a-form-item class="!mb-0 inline-block">
<a-input-number <a-input-number
placeholder="" placeholder=""
v-model:value={form.budgetSum2} v-model:value={form.contractMoneyUp}
/> />
</a-form-item> </a-form-item>
<span class="mx-1"></span> <span class="mx-1"></span>

View File

@ -32,11 +32,17 @@ const formRef = ref();
const formRefByAuthRange = ref(); const formRefByAuthRange = ref();
const isLoading = ref(false); const isLoading = ref(false);
const currData = ref<any>({});
const nodeInfo = ref<any>({});
const contractTypeData = ref([]); const contractTypeData = ref<any>([]);
const formBinding = ref({ const formBinding = ref({
...(({ columns: _, ...rest }) => rest)(getFormSchema()), ...(({ columns: _, ...rest }) => rest)(
getFormSchema({
formRef,
}),
),
}); });
const formBindingByAuthRange = ref({ const formBindingByAuthRange = ref({
@ -81,6 +87,133 @@ function handleFold() {
collapseActiveKey.value = isFold.value ? collapses : []; collapseActiveKey.value = isFold.value ? collapses : [];
} }
function handleDelete() {
Modal.confirm({
title: '提示',
content: '是否确认删除该条记录?',
okType: 'danger',
onOk: async () => {
await Apis.ccsq.post_deletes({
params: { ids: id.value },
});
message.success('删除成功');
back();
},
});
}
async function handleSave() {
const form = formRef.value.form;
const formByAuthRange = formRefByAuthRange.value.form;
console.log('提交表单', form, formBindingByAuthRange);
try {
await formRef.value.submit();
await formRefByAuthRange.value.submit();
} catch {
message.error('请完成必填项的填写');
}
//
{
const tempFileList = form.fileList;
let tempFiles: any = [];
if (fileList.value && tempFileList && tempFileList.length > 0) {
tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
}
if (tempFiles) {
form.fileUuid = (tempFiles.map((item) => item.fileUuid) || []).join(',');
}
}
// name
for (const item of contractTypeData.value) {
if (item.contrLevelId === form.ctrType) {
form.ctrTypeName = item.contrLevelName;
}
if (item.contrLevelId === form.ctrTwoType) {
form.ctrTwoTypeName = item.contrLevelName;
}
}
const newForm = {
RlHtSqConsignPt: {
entrustUserId: 'xiong',
entrustUserName: form.entrustUserName,
lawUserId: form.lawUserName,
lawUserName: form.lawUserName,
unitName: '热力公司',
unitId: '0',
remarks: form.remarks,
positionId: '01',
positionName: form.positionName,
consignType: form.consignType,
consignDateBegin: form.consignDateBegin,
consignDateEnd: form.consignDateEnd,
consignDescribe: form.consignDescribe,
},
RlHtSqConsignUser: {
consignUserId: 'xiong',
userId: 'liu01',
userName: '柳柳',
userPerson: '柳柳',
unitId: '24352234',
unitName: '一分公司机关楼高压电缆更换。',
departId: '其他',
departName: '8',
positionTypeId: null,
positionTypeName: '1',
identityCardId: '657665462381112901',
status: '1',
remarks: '1',
},
RlHtSqConsignCqtype: {
consignCqtypeId: '3452345',
contractOneTypeId: form.ctrType,
contractOneTypeName: form.ctrTypeName,
contractTwoTypeId: form.ctrTwoType,
contractTwoTypeName: form.ctrTwoTypeName,
// inputDepartId: '2024',
// inputDepartName: 'xxxx',
// remark: '',
contractMoneyDown: form.contractMoneyDown,
contractMoneyUp: form.contractMoneyUp,
priceTypeId: form.priceType,
priceTypeName: getDictObj(
DICT_TYPE.contract_currency_unit,
form.priceType,
)?.label,
},
RlHtSqConsignDxtype: {
consignCqtypeId: '',
consignId: '',
},
};
console.log(newForm);
return;
try {
await Apis.qdSign.post_save({
data: newForm,
});
message.success('保存成功');
Modal.confirm({
title: '提示',
content: '保存成功!是否进行提交?',
onOk: () => {
handleSubmit();
},
onCancel: () => {
back();
},
});
} catch (error) {
message.error('保存失败,请稍候再试');
logger.error('签约申报报错失败', error);
} finally {
isLoading.value = false;
}
}
async function handleSubmit() { async function handleSubmit() {
isLoading.value = true; isLoading.value = true;
@ -95,20 +228,6 @@ async function handleSubmit() {
const form = formRef.value.form; const form = formRef.value.form;
//
{
const tempFileList = form.fileList;
let tempFiles: any = [];
if (fileList.value && tempFileList.length > 0) {
tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' });
}
if (tempFiles) {
form.fileUuid = (tempFiles.map((item) => item.fileUuid) || []).join(
',',
);
}
}
console.log('提交表单', form); console.log('提交表单', form);
return; return;
@ -178,7 +297,9 @@ async function handleSubmit() {
} }
onMounted(async () => { onMounted(async () => {
formBinding.value.columns = getFormSchema().columns; formBinding.value.columns = getFormSchema({
formRef,
}).columns;
const contractReferTypeData: any = await Apis.contractReferType.get_list({ const contractReferTypeData: any = await Apis.contractReferType.get_list({
params: {}, params: {},
@ -254,9 +375,28 @@ onMounted(async () => {
> >
<div class="flex w-full flex-row bg-white pl-1 pt-1"> <div class="flex w-full flex-row bg-white pl-1 pt-1">
<a-space class="flex-1"> <a-space class="flex-1">
<vben-button variant="primary" @click="handleSubmit()"> <vben-button
v-if="!id || ['填报'].includes(currData.status)"
variant="primary"
@click="handleSave()"
>
保存
</vben-button>
<vben-button
v-if="!id || ['填报'].includes(currData.status)"
:disabled="!id"
variant="primary"
@click="handleSubmit()"
>
提交 提交
</vben-button> </vben-button>
<vben-button
v-if="!isLoading && id && ['填报'].includes(currData.status)"
variant="destructive"
@click="handleDelete()"
>
删除
</vben-button>
<vben-button variant="secondary" @click="handleBack()"> <vben-button variant="secondary" @click="handleBack()">
返回 返回
</vben-button> </vben-button>

View File

@ -1,7 +1,5 @@
import type { VxeGridPropTypes } from 'vxe-table'; import type { VxeGridPropTypes } from 'vxe-table';
import dayjs from 'dayjs';
export const PrimaryKey = 'guid'; export const PrimaryKey = 'guid';
export function getColumns(_params?: any): VxeGridPropTypes.Columns { export function getColumns(_params?: any): VxeGridPropTypes.Columns {
@ -15,7 +13,7 @@ export function getColumns(_params?: any): VxeGridPropTypes.Columns {
}, },
{ {
title: '签约授权编号', title: '签约授权编号',
field: 'authorizationCode', field: 'consignId',
width: 200, width: 200,
align: 'center', align: 'center',
}, },
@ -44,19 +42,19 @@ export function getColumns(_params?: any): VxeGridPropTypes.Columns {
align: 'center', align: 'center',
}, },
{ {
field: 'operate',
title: '操作', title: '操作',
width: 80, width: 60,
align: 'center', align: 'center',
fixed: 'right', fixed: 'right',
slots: { default: 'operate' },
}, },
]; ];
} }
export function getFormSchema(_params: any = {}) { export function getFormSchema(_params: any = {}) {
return { return {
initialForm: { initialForm: {},
startDate: dayjs().startOf('month').format('YYYY-MM-DD'),
},
columns: { columns: {
contractName: { contractName: {
title: '受托人姓名', title: '受托人姓名',

View File

@ -33,7 +33,7 @@ const gridOptions = reactive(
autoLoad: false, autoLoad: false,
ajax: { ajax: {
query: async ({ page }) => { query: async ({ page }) => {
const data = await Apis.contractBaseInfo.get_page({ const data = await Apis.sqConsignPt.get_SigningaAuthorizationSerch({
params: { params: {
pageNum: page.currentPage, pageNum: page.currentPage,
pageSize: page.pageSize, pageSize: page.pageSize,
@ -67,7 +67,7 @@ function handleDelete(row) {
content: '是否确认删除该条记录?', content: '是否确认删除该条记录?',
okType: 'danger', okType: 'danger',
onOk: async () => { onOk: async () => {
await Apis.contractBaseInfo.post_deletes({ await Apis.sqConsignPt.post_deletes({
params: { ids: row[PrimaryKey] }, params: { ids: row[PrimaryKey] },
}); });
message.success('删除成功'); message.success('删除成功');
@ -166,7 +166,12 @@ function toDetailPage(_row) {}
</template> </template>
<template #operate="{ row }"> <template #operate="{ row }">
<a-button size="small" type="primary" @click="toDetailPage(row)"> <a-button
class="text-primary"
size="small"
type="text"
@click="toDetailPage(row)"
>
查看 查看
</a-button> </a-button>
</template> </template>

View File

@ -0,0 +1,46 @@
import type { Component } from 'vue';
interface AnalysisOverviewItem {
icon: Component | string;
title: string;
totalTitle: string;
totalValue: number;
value: number;
}
interface WorkbenchProjectItem {
color?: string;
content: string;
date: string;
group: string;
icon: Component | string;
title: string;
}
interface WorkbenchTrendItem {
avatar: string;
content: string;
date: string;
title: string;
}
interface WorkbenchTodoItem {
completed: boolean;
content: string;
date: string;
title: string;
}
interface WorkbenchQuickNavItem {
color?: string;
icon: Component | string;
title: string;
}
export type {
AnalysisOverviewItem,
WorkbenchProjectItem,
WorkbenchQuickNavItem,
WorkbenchTodoItem,
WorkbenchTrendItem,
};

View File

@ -0,0 +1,74 @@
<script setup lang="ts">
import type { WorkbenchTodoItem } from './typing';
import { useRouter } from 'vue-router';
import {
Card,
CardContent,
CardHeader,
CardTitle,
VbenButton,
} from '@vben-core/shadcn-ui';
defineOptions({
name: 'WorkbenchTodo',
});
withDefaults(defineProps<Props>(), {
items: () => [],
});
const router = useRouter();
interface Props {
items: WorkbenchTodoItem[];
title: string;
}
function handleViewAll() {
router.push('/user/todo');
}
</script>
<template>
<Card>
<CardHeader class="py-4">
<div class="flex items-center justify-between">
<CardTitle class="text-lg">{{ title }}</CardTitle>
<VbenButton size="sm" @click="handleViewAll"> 查看所有待办 </VbenButton>
</div>
</CardHeader>
<CardContent class="flex h-[60vh] flex-wrap overflow-auto p-5 pt-0">
<ul class="divide-border w-full divide-y" role="list">
<li
v-for="item in items"
:key="item.title"
:class="{
'select-none line-through opacity-60': item.completed,
}"
class="flex cursor-pointer justify-between gap-x-6 px-4 py-2"
>
<div class="flex min-w-0 items-center gap-x-4">
<div class="min-w-0 flex-auto">
<p class="text-foreground text-sm font-semibold leading-6">
{{ item.module }} {{ item.title }}
</p>
<!-- eslint-disable vue/no-v-html -->
<p
class="text-foreground/80 *:text-primary mt-1 truncate text-xs leading-5"
v-html="item.message"
></p>
</div>
</div>
<div class="hidden h-full shrink-0 sm:flex sm:flex-col sm:items-end">
<span class="text-foreground/80 mt-6 text-xs leading-6">
{{ item.date }}
</span>
</div>
</li>
</ul>
</CardContent>
</Card>
</template>

View File

@ -1,13 +1,17 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted } from "vue"; import type { WorkbenchTodoItem } from '../components/typing';
import { preferences } from "@vben/preferences";
import { useUserStore } from "@vben/stores";
import WorkbenchHeader from "../components/workbench-header.vue"; import { onMounted, ref } from 'vue';
import WorkbenchQuickNav from "../components/workbench-quick-nav.vue"; import { useRouter } from 'vue-router';
import { useAccessStore } from "@vben/stores";
import { useRouter } from "vue-router"; import { preferences } from '@vben/preferences';
import { DEFAULT_HOME_PATH, LOGIN_PATH } from "@vben/constants"; import { useUserStore } from '@vben/stores';
import Apis from '#/api';
import { DICT_TYPE, getDictObj } from '#/utils/dict';
import WorkbenchHeader from '../components/workbench-header.vue';
import WorkbenchTodo from '../components/workbench-todo.vue';
const userStore = useUserStore(); const userStore = useUserStore();
const router = useRouter(); const router = useRouter();
@ -22,11 +26,11 @@ const quickNavItems: WorkbenchQuickNavItem[] = [
// }, // },
// }, // },
{ {
color: "#bf0c2c", color: '#bf0c2c',
icon: "ion:grid-outline", icon: 'ion:grid-outline',
title: "订餐", title: '订餐',
onClick: () => { onClick: () => {
router.push("/canteen/orderfood"); router.push('/canteen/orderfood');
}, },
}, },
// { // {
@ -55,9 +59,31 @@ const quickNavItems: WorkbenchQuickNavItem[] = [
// }, // },
]; ];
onMounted(() => { const todoItems = ref<WorkbenchTodoItem[]>([]);
const accessStore = useAccessStore();
console.log(accessStore.accessMenus); onMounted(async () => {
const data = await Apis.home.get_todo({
params: { pageNum: 1, pageSize: 20 },
});
todoItems.value = data.rows.map((item) => {
let module =
getDictObj(DICT_TYPE.contract_todo_type, item.module)?.label || '';
if (module) {
module = `[${module}]`;
}
return {
module,
avatar: '',
date: item.createTime,
isRead: true,
message: item.contractName,
title: item.taskName,
};
});
// resetAllStores();
}); });
</script> </script>
@ -75,5 +101,7 @@ onMounted(() => {
<div class="mt-5 flex flex-col lg:flex-row"> <div class="mt-5 flex flex-col lg:flex-row">
<!-- <WorkbenchQuickNav :items="quickNavItems" title="快捷导航" /> --> <!-- <WorkbenchQuickNav :items="quickNavItems" title="快捷导航" /> -->
</div> </div>
<WorkbenchTodo :items="todoItems" class="mt-5" title="待办事项" />
</div> </div>
</template> </template>

View File

@ -1,22 +1,166 @@
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue';
import { Page } from '@vben/common-ui';
import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import { getTodoColumns } from '#/views/contract/schema';
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const { xGridRef: xGrid2Ref, triggerProxy: triggerProxy2 } = useVxeTable({
ref: 'xGrid2Ref',
});
const treeData = ref();
const selectedKeys = ref<string[]>([]);
/** Hooks - 表格 */
const gridOptions = reactive(
gridProps({
columns: getTodoColumns(),
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.home.get_todo({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
moduleId: selectedKeys.value[0],
},
});
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: false,
},
}),
);
/** Hooks - 表格 */
const grid2Options = reactive(
gridProps({
columns: getTodoColumns(),
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.home.get_done({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
moduleId: selectedKeys.value[0],
},
});
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: false,
},
}),
);
function onTreeSelect() {
triggerProxy('reload');
triggerProxy2('reload');
}
const expandedKeys = ref<string[]>([]);
async function loadDataByDictType() {
const data = getDictOptions(DICT_TYPE.contract_todo_type);
data.forEach((item) => {
item.key = item.value;
item.title = item.label;
});
expandedKeys.value = ['all'];
treeData.value = [{ title: '全部', key: 'all', children: data }];
}
function toDetail(row) {}
function toDetailPage(row) {}
onMounted(() => {
loadDataByDictType();
});
</script>
<template> <template>
<Page contentClass="h-full"> <Page content-class="h-full">
<a-row class="h-full" :gutter="[8, 8]"> <a-row :gutter="[8, 8]" class="h-full">
<a-col :span="5" class="min-w-[200px]"> <a-col :span="5" class="min-w-[200px]">
<a-card title="事项类型" size="small" contentClass=""> <a-card content-class="" size="small" title="事项类型">
<div class="min-h-[500px]"> <div class="min-h-[500px]">
<a-tree class="draggable-tree" block-node :tree-data="treeData" /> <a-tree
v-model:expanded-keys="expandedKeys"
v-model:selected-keys="selectedKeys"
:tree-data="treeData"
block-node
class="draggable-tree"
@select="onTreeSelect"
/>
</div> </div>
</a-card> </a-card>
</a-col> </a-col>
<a-col :span="19" class="flex flex-col min-w-700px"> <a-col :span="19" class="min-w-700px flex flex-col">
<a-card title="待办" size="small" class=" flex-1"> <a-card
<vxe-grid ref="xGridRef" v-bind="gridOptions" class=" flex-1"> :body-style="{ flex: '1' }"
class="flex h-full flex-col"
size="small"
title="待办"
>
<vxe-grid ref="xGridRef" v-bind="gridOptions" class="flex-1">
<template #toolbar_buttons> </template> <template #toolbar_buttons> </template>
<template #title_slot="{ row }">
<span
class="cursor-pointer text-blue-500 hover:underline"
@click="toDetail(row)"
>
{{ row.contractName }}
</span>
</template>
<template #operate="{ row }">
<a-button
class="text-blue-500"
size="small"
type="text"
@click="toDetailPage(row)"
>
查看
</a-button>
</template>
</vxe-grid> </vxe-grid>
</a-card> </a-card>
<a-card title="已办" size="small" class=" flex-1 mt-[8px]"> <a-card
<vxe-grid ref="xGridRef" v-bind="gridOptions" class=" flex-1"> :body-style="{ flex: '1' }"
class="flex h-full flex-col"
size="small"
title="已办"
>
<vxe-grid ref="xGridRef" v-bind="grid2Options" class="flex-1">
<template #toolbar_buttons> </template> <template #toolbar_buttons> </template>
<template #operate="{ row }">
<a-button
class="text-blue-500"
size="small"
type="text"
@click="toDetailPage(row)"
>
查看
</a-button>
</template>
</vxe-grid> </vxe-grid>
</a-card> </a-card>
</a-col> </a-col>
@ -24,201 +168,8 @@
</Page> </Page>
</template> </template>
<script setup lang="ts"> <style scoped>
import { defineComponent, ref, reactive, onMounted } from 'vue'; :deep(.ant-space-item) {
import { FsCrud } from '@fast-crud/fast-crud'; flex: 1;
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 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: false,
ajax: {
query: ({ page }) => {
return Apis.dictData.get_page({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchParams } })
}
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: false
},
}));
//
function transTree(list) {
//
const _treeData = [];
//
list.forEach((item) => {
//
// item.children = []
item.key = item.code;
item.title = item.name;
// pid _treeData
if (!item.parentId || item.parentId == 0) {
_treeData.push(item);
}
// pid id
// filter
const children = list.filter((data) => data.parentId === item.id);
// return
if (!children.length) return;
// (item) children
item.children = children;
});
//
return _treeData;
} }
</style>
let DictTypeData = ref([])
async function loadDataByDictType() {
// try {
// let data = await Apis.dictType.get_list();
// console.log(data);
// treeData.value = transTree(data.rows)
// console.log(treeData.value);
// } catch (error) {
// console.log(error)
// } finally {
// triggerProxy('reload')
// }
}
onMounted(() => {
loadDataByDictType()
})
let searchParams = reactive({})
const searchForm = ref({
columns: {
tree: {
title: "树形选择",
show: true,
valueChange({ getComponentRef }) {
const compRef = getComponentRef("tree");
console.log("tree ref:", compRef, compRef.$refs.treeRef);
},
component: {
name: "fs-dict-tree",
dict: dict({
isTree: true,
async getData(dict, context) {
return
}
}),
on: {
selectedChange({ form, $event }) {
// $event option
// utils.logger.info("onSelectedChange", form, $event);
// ui.message.info(`${JSON.stringify($event.label)}`);
// label
// context.form.xxxLabel = context.$event.label
}
},
slots: {
title({ scope }) {
//text
return `${scope.label}(${scope.value})`;
}
}
}
},
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

@ -43,7 +43,7 @@ export function transferResponse(response: any) {
code = 0; code = 0;
} }
if (code == 'failure' || (msg && msg.includes('token无效'))) { if (code == 'failure' && msg && msg.includes('token无效')) {
code = 401; code = 401;
} }

View File

@ -1,12 +1,9 @@
import { merge } from "lodash-es"; import { ref } from 'vue';
import { ref } from "vue";
import { type VxeGridInstance, type VxeGridProps } from "vxe-table";
export function useVxeTable(props: {
ref: string,
}) {
import { merge } from 'lodash-es';
import { type VxeGridInstance, type VxeGridProps } from 'vxe-table';
export function useVxeTable(props: { ref: string }) {
const xGridRef = ref<VxeGridInstance<any>>(); const xGridRef = ref<VxeGridInstance<any>>();
return { return {
@ -19,10 +16,10 @@ export function useVxeTable(props: {
height: 'auto', height: 'auto',
border: true, border: true,
editConfig: { editConfig: {
mode: 'row' mode: 'row',
}, },
rowConfig: { rowConfig: {
isCurrent: true isCurrent: true,
}, },
// 斑马条纹 // 斑马条纹
stripe: false, stripe: false,
@ -30,7 +27,7 @@ export function useVxeTable(props: {
enabled: true, enabled: true,
size: 'mini', size: 'mini',
pageSize: 50, pageSize: 50,
autoHidden: false autoHidden: false,
}, },
// 列设置 // 列设置
columnConfig: { columnConfig: {
@ -38,7 +35,7 @@ export function useVxeTable(props: {
isCurrent: false, isCurrent: false,
isHover: false, isHover: false,
// 取消列宽拖动功能 // 取消列宽拖动功能
resizable: false resizable: false,
}, },
toolbarConfig: { toolbarConfig: {
enabled: true, enabled: true,
@ -48,11 +45,11 @@ export function useVxeTable(props: {
custom: true, custom: true,
refresh: true, refresh: true,
slots: { slots: {
buttons: 'toolbar_buttons' buttons: 'toolbar_buttons',
} },
}, },
headerAlign: 'left', headerAlign: 'left',
align: 'left' align: 'left',
}; };
// 如果mergedProps.proxyConfig是空对象则删除该字段不然 vxetable 可能会误判断 // 如果mergedProps.proxyConfig是空对象则删除该字段不然 vxetable 可能会误判断
@ -61,8 +58,8 @@ export function useVxeTable(props: {
props: { props: {
list: 'rows', list: 'rows',
result: 'rows', result: 'rows',
total: 'total' total: 'total',
} },
}; };
} }
@ -74,6 +71,6 @@ export function useVxeTable(props: {
if ($grid) { if ($grid) {
$grid.commitProxy(code); $grid.commitProxy(code);
} }
} },
} };
} }

View File

@ -1,15 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue'; import { computed, onMounted, reactive, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { MdiRadioChecked, MdiRadioUnchecked } from '@vben/icons'; import { MdiRadioChecked, MdiRadioUnchecked } from '@vben/icons';
import { message } from 'ant-design-vue';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import Apis from '#/api'; import Apis from '#/api';
import { useVxeTable } from '#/hooks/vxeTable'; import { useVxeTable } from '#/hooks/vxeTable';
import { getMonthStartAndEnd } from '#/utils/time';
import { getColumns } from './crud.tsx'; import { getColumns } from './crud.tsx';
@ -17,7 +14,7 @@ const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const currentDate = ref(dayjs()); const currentDate = ref(dayjs());
const currentMonth = computed(() => currentDate.value.format('YYYY年MM月')); const currentMonth = computed(() => currentDate.value.format('YYYY年M月'));
const prevMonth = () => { const prevMonth = () => {
currentDate.value = currentDate.value.subtract(1, 'month'); currentDate.value = currentDate.value.subtract(1, 'month');
@ -29,48 +26,6 @@ const nextMonth = () => {
triggerProxy('reload'); triggerProxy('reload');
}; };
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 tableData = ref([]); const tableData = ref([]);
/** Hooks - 表格 */ /** Hooks - 表格 */
@ -231,12 +186,12 @@ const gridOptions = reactive(
); );
/** 选中数据 */ /** 选中数据 */
const selectRow: Recordable = computed(() => { const selectRow: any = computed(() => {
return xGridRef.value?.getRadioRecord() || null; return xGridRef.value?.getRadioRecord() || null;
}); });
/** 单选框选中事件 */ /** 单选框选中事件 */
const setSelectRow = (row: Recordable) => { const setSelectRow = (row: any) => {
if (selectRow.value && selectRow.value.guid === row.guid) { if (selectRow.value && selectRow.value.guid === row.guid) {
xGridRef.value?.clearRadioRow(); xGridRef.value?.clearRadioRow();
} else { } else {
@ -258,7 +213,7 @@ onMounted(() => {
<div class="mx-auto flex h-screen flex-col bg-gray-100 px-8"> <div class="mx-auto flex h-screen flex-col bg-gray-100 px-8">
<p class="my-6 text-center text-3xl font-bold text-gray-800">值班信息栏</p> <p class="my-6 text-center text-3xl font-bold text-gray-800">值班信息栏</p>
<div class="mb-6 flex items-center justify-center h-4"> <div class="mb-6 flex h-4 items-center justify-center">
<!-- 增加按钮区域的高度 --> <!-- 增加按钮区域的高度 -->
<button <button
class="bg-primary hover:bg-primary/90 rounded-l-xl px-4 py-2 text-white" class="bg-primary hover:bg-primary/90 rounded-l-xl px-4 py-2 text-white"
@ -275,12 +230,15 @@ onMounted(() => {
</button> </button>
</div> </div>
<div class="flex-1 rounded-lg bg-white p-4 shadow-md overflow-auto" style="flex-grow: 2;"> <div
class="flex-1 overflow-auto rounded-lg bg-white p-4 shadow-md"
style="flex-grow: 2"
>
<vxe-grid <vxe-grid
ref="xGridRef" ref="xGridRef"
v-bind="gridOptions" v-bind="gridOptions"
style="min-height: 40vh; max-height: 60vh"
@cell-click="handleCellClick" @cell-click="handleCellClick"
style="min-height: 40vh; max-height: 60vh;"
> >
<template #toolbar_buttons> <template #toolbar_buttons>
<!-- 可添加工具栏按钮 --> <!-- 可添加工具栏按钮 -->
@ -298,7 +256,7 @@ onMounted(() => {
</vxe-grid> </vxe-grid>
</div> </div>
<div class="mt-4" style="width: 100%; min-height: 120px;"> <div class="mt-4" style="width: 100%; min-height: 120px">
<p> <p>
1.公司机关值班人员包括值班司机都必须严格遵守值班管理要求值班期间保持值班电话畅通 1.公司机关值班人员包括值班司机都必须严格遵守值班管理要求值班期间保持值班电话畅通
</p> </p>

View File

@ -3,6 +3,7 @@ import type { VxeGridPropTypes } from 'vxe-table';
import { dict } from '@fast-crud/fast-crud'; import { dict } from '@fast-crud/fast-crud';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useRender } from '#/hooks/useRender';
import { DICT_TYPE, getDictOptions } from '#/utils/dict'; import { DICT_TYPE, getDictOptions } from '#/utils/dict';
export const PrimaryKey = 'guid'; export const PrimaryKey = 'guid';
@ -61,7 +62,16 @@ export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
}, },
}, },
}, },
{ field: 'conferee', title: '参会人员', minWidth: 200 }, {
field: 'conferee',
title: '参会人员',
minWidth: 200,
slots: {
default: ({ row }) => {
return useRender.renderMultiLineText(row.conferee, { maxLine: 3 });
},
},
},
{ {
field: 'otherEquipment', field: 'otherEquipment',
title: '备注', title: '备注',
@ -176,9 +186,7 @@ export function getFormSchema(_params: any = {}) {
class: 'min-w-[180px]', class: 'min-w-[180px]',
allowClear: true, allowClear: true,
dict: dict({ dict: dict({
data: getDictOptions(DICT_TYPE.meeting_type).filter( data: getDictOptions(DICT_TYPE.meeting_type),
(option) => option.value !== '生产会议',
),
}), }),
}, },
autoSearchTrigger: 'enter', autoSearchTrigger: 'enter',

View File

@ -10,6 +10,7 @@ import { useUserStore } from '@vben/stores';
import { dict } from '@fast-crud/fast-crud'; import { dict } from '@fast-crud/fast-crud';
import { message, Modal, type UploadChangeParam } from 'ant-design-vue'; import { message, Modal, type UploadChangeParam } from 'ant-design-vue';
import dayjs from 'dayjs';
import Sortable from 'sortablejs'; import Sortable from 'sortablejs';
import Apis from '#/api'; import Apis from '#/api';
@ -71,7 +72,6 @@ const formBinding = ref({
return <span class="">{form.meetingTheme}</span>; return <span class="">{form.meetingTheme}</span>;
}, },
}, },
rules: [{ required: true, message: '请输入会议主题' }],
}, },
meetingType: { meetingType: {
title: '会议类型', title: '会议类型',
@ -97,7 +97,6 @@ const formBinding = ref({
); );
}, },
}, },
rules: [{ required: true, message: '请选择会议类型' }],
}, },
isEmployeeRepresentatives: { isEmployeeRepresentatives: {
title: '职工代表会', title: '职工代表会',
@ -151,7 +150,6 @@ const formBinding = ref({
); );
}, },
}, },
rules: [{ required: true, message: '请选择会议室' }],
}, },
meetingDate: { meetingDate: {
title: '会议时间', title: '会议时间',
@ -178,7 +176,6 @@ const formBinding = ref({
); );
}, },
}, },
rules: [{ required: true, message: '请选择会议时间' }],
}, },
compere: { compere: {
title: '主持人', title: '主持人',

View File

@ -2,11 +2,13 @@ import type { VxeGridPropTypes } from 'vxe-table';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useRender } from '#/hooks/useRender';
export const PrimaryKey = 'guid'; export const PrimaryKey = 'guid';
export function getColumns(_params?: any): VxeGridPropTypes.Columns { export function getColumns(_params?: any): VxeGridPropTypes.Columns {
const columns: VxeGridPropTypes.Columns = [ const columns: VxeGridPropTypes.Columns = [
{ type: 'seq', width: 50, align: 'center', fixed: 'left' }, { type: 'seq', width: 60, align: 'center', fixed: 'left' },
{ {
field: 'meetingDate', field: 'meetingDate',
title: '会议时间', title: '会议时间',
@ -33,8 +35,16 @@ export function getColumns(_params?: any): VxeGridPropTypes.Columns {
width: 150, width: 150,
}, },
{ field: 'compere', title: '主持人', width: 80 }, { field: 'compere', title: '主持人', width: 80 },
{ field: 'conferee', title: '参会人员', minWidth: 200 }, {
field: 'conferee',
title: '参会人员',
minWidth: 200,
slots: {
default: ({ row }) => {
return useRender.renderMultiLineText(row.conferee, { maxLine: 3 });
},
},
},
{ field: 'meetingType', title: '会议类型', width: 120 }, { field: 'meetingType', title: '会议类型', width: 120 },
{ {
field: 'otherEquipment', field: 'otherEquipment',

View File

@ -15,10 +15,10 @@ const searchRef = ref();
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' }); const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const treeData = ref([]);
/** Hooks - 表格 */ /** Hooks - 表格 */
const gridOptions = reactive( const gridOptions = reactive(
gridProps({ gridProps({
size: 'medium',
columns: getColumns({ type: 'taizhang' }), columns: getColumns({ type: 'taizhang' }),
proxyConfig: { proxyConfig: {
autoLoad: false, autoLoad: false,
@ -36,6 +36,7 @@ const gridOptions = reactive(
}, },
}, },
pagerConfig: { pagerConfig: {
size: 'medium',
enabled: true, enabled: true,
}, },
toolbarConfig: { toolbarConfig: {
@ -140,4 +141,11 @@ const searchForm = ref({
</div> </div>
</template> </template>
<style></style> <style scoped>
:deep(.vxe-table--render-default.size--medium) {
font-size: 20px;
}
:deep(.ant-form-item .ant-form-item-label > label) {
font-size: 16px !important;
}
</style>

View File

@ -359,7 +359,7 @@ function downloadFile(fileUrl) {
<div <div
:class="[bgColor]" :class="[bgColor]"
class="content-area mb-4 flex h-[55vh] items-center justify-center overflow-y-auto rounded-lg p-4" class="content-area mb-4 flex h-[50vh] items-center justify-center overflow-y-auto rounded-lg p-4"
> >
<p :class="[textColor, textSize]" class="text-center"> <p :class="[textColor, textSize]" class="text-center">
{{ currentSpeaker.abstracts }} {{ currentSpeaker.abstracts }}

23
cli.sh Normal file
View File

@ -0,0 +1,23 @@
#!/bin/bash
# Send request and capture response data
response=$(curl -s http://192.168.147.164:8083/rl/dictData/page)
# Check if response is not empty
if [ -z "$response" ]; then
echo "请求失败,未收到响应"
echo "export const responseStatus = '请求失败,未收到响应';" > response.ts
exit 1
fi
# Extract status code and records using grep and sed
http_code=$(echo "$response" | grep -o '"code":[0-9]*' | sed 's/"code"://')
records=$(echo "$response" | grep -o '"records":\[[^]]*\]' | sed 's/"records"://')
# Define the TypeScript file path
ts_file="response.ts"
# Write to the TypeScript file
echo "请求成功"
echo "export const records = $records;" > $ts_file

View File

@ -42,9 +42,9 @@ function defineApplicationConfig(userConfigPromise?: DefineApplicationOptions) {
nitroMock: !isBuild, nitroMock: !isBuild,
nitroMockOptions: {}, nitroMockOptions: {},
print: !isBuild, print: !isBuild,
printInfoMap: { // printInfoMap: {
'Vben Admin Docs': 'https://doc.vben.pro', // 'Vben Admin Docs': 'https://doc.vben.pro',
}, // },
pwa: true, pwa: true,
pwaOptions: getDefaultPwaOptions(appTitle), pwaOptions: getDefaultPwaOptions(appTitle),
...envConfig, ...envConfig,

View File

@ -0,0 +1,66 @@
type RequestMethod = (url: string) => Promise<any>;
interface DictionaryItem {
[key: string]: any;
}
interface DictionaryOptions {
baseUrl: string;
endpoints?: {
all: string;
byId: (id: number) => string;
byType: (type: string) => string;
};
parseResponse?: (response: any) => any;
}
export class Dictionary {
private options: DictionaryOptions;
private request: RequestMethod;
constructor(requestMethod: RequestMethod, options: DictionaryOptions) {
this.request = requestMethod;
this.options = options;
}
private parseResponse(response: any): any {
return this.options.parseResponse
? this.options.parseResponse(response)
: response.data;
}
// Fetch all dictionary items
async getAll(): Promise<DictionaryItem[]> {
// try {
const response = await this.request(`123`);
// return this.parseResponse(response);
// } catch (error) {
// console.error('Error fetching all dictionaries', error);
// throw error;
// }
}
// Fetch a specific dictionary item by ID
async getById(id: number): Promise<DictionaryItem> {
try {
const endpoint = this.options.endpoints?.byId(id) || `/id/${id}`;
const response = await this.request(`${this.options.baseUrl}${endpoint}`);
return this.parseResponse(response);
} catch (error) {
console.error(`Error fetching dictionary by ID: ${id}`, error);
throw error;
}
}
// Fetch dictionary items by type
async getByType(type: string): Promise<DictionaryItem[]> {
try {
const endpoint = this.options.endpoints?.byType(type) || `/type/${type}`;
const response = await this.request(`${this.options.baseUrl}${endpoint}`);
return this.parseResponse(response);
} catch (error) {
console.error(`Error fetching dictionaries by type: ${type}`, error);
throw error;
}
}
}

View File

@ -1,6 +1,6 @@
// export * from './logger/index'; // export * from './logger/index';
export * from './dict/index';
export * from './utils/index'; export * from './utils/index';
// export const logger = { // export const logger = {
// log(level: string, message: any, error?: any) { // log(level: string, message: any, error?: any) {
// const timestamp = new Date().toISOString(); // const timestamp = new Date().toISOString();

View File

@ -284,6 +284,9 @@ export default {
/** 协同办公/督查督办/执行反馈 执行反馈已办查询 */ /** 协同办公/督查督办/执行反馈 执行反馈已办查询 */
get_pageDone: (data?: QueryOptions) => get_pageDone: (data?: QueryOptions) =>
http.get('/app/feedback/pageDone', data), http.get('/app/feedback/pageDone', data),
/** 协同办公/督查督办/立项发起 查询立项对应的反馈 */
get_queryFeedback: (data?: QueryOptions) =>
http.get('/app/feedback/queryFeedback', data),
}, },
file: { file: {
/** 协同办公/文件上传/下载 多文件上传 */ /** 协同办公/文件上传/下载 多文件上传 */
@ -637,8 +640,8 @@ export default {
get_getContractSignInfo: (data?: QueryOptions) => get_getContractSignInfo: (data?: QueryOptions) =>
http.get('/app/qdSign/getContractSignInfo', data), http.get('/app/qdSign/getContractSignInfo', data),
/** 合同系统/签订 打印签订审批表 */ /** 合同系统/签订 打印签订审批表 */
get_createUserListWord: (data?: QueryOptions) => get_printApprove: (data?: QueryOptions) =>
http.get('/app/qdSign/createUserListWord', data), http.get('/app/qdSign/printApprove', data),
/** 合同系统/签订 打印文本 */ /** 合同系统/签订 打印文本 */
get_textPrint: (data?: QueryOptions) => get_textPrint: (data?: QueryOptions) =>
http.get('/app/qdSign/textPrint', data), http.get('/app/qdSign/textPrint', data),
@ -733,6 +736,9 @@ export default {
/** 公共 获取请求ip */ /** 公共 获取请求ip */
get_getClientIp: (data?: QueryOptions) => get_getClientIp: (data?: QueryOptions) =>
http.get('/app/common/getClientIp', data), http.get('/app/common/getClientIp', data),
/** 公共 获取项目地址 */
get_getProjectAddress: (data?: QueryOptions) =>
http.get('/app/common/getProjectAddress', data),
}, },
address: { address: {
/** 协同办公/订餐管理/订餐地址 查询(分页) */ /** 协同办公/订餐管理/订餐地址 查询(分页) */
@ -776,6 +782,9 @@ export default {
/** 合同系统 流程已办 */ /** 合同系统 流程已办 */
get_getDoneTaskByUserID: (data?: QueryOptions) => get_getDoneTaskByUserID: (data?: QueryOptions) =>
http.get('/app/workFlow/getDoneTaskByUserID', data), http.get('/app/workFlow/getDoneTaskByUserID', data),
/** 合同系统 获取流程图 */
get_getFlowImg: (data?: QueryOptions) =>
http.get('/app/workFlow/getFlowImg', data),
}, },
biddingResult: { biddingResult: {
/** 合同系统/选商/选商结果 分页查询 */ /** 合同系统/选商/选商结果 分页查询 */
@ -784,17 +793,40 @@ export default {
/** 合同系统/选商/选商结果 保存 */ /** 合同系统/选商/选商结果 保存 */
post_save: (data?: BodyOptions) => post_save: (data?: BodyOptions) =>
http.post('/app/biddingResult/save', data), 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),
}, },
home: { home: {
/** 合同系统/首页待办/已办 待办 */ /** 合同系统/首页待办/已办 首页待办 */
get_todo: (data?: QueryOptions) => http.get('/app/home/todo', data), get_todo: (data?: QueryOptions) => http.get('/app/home/todo', data),
/** 合同系统/首页待办/已办 首页已办 */
get_done: (data?: QueryOptions) => http.get('/app/home/done', data),
}, },
sqConsignPt: { sqConsignPt: {
/** 合同系统/签约授权 签约授权保存 */ /** 合同系统/签约授权 签约授权保存 */
post_saveSignMultiEntity: (data?: BodyOptions) => post_saveSignMultiEntity: (data?: BodyOptions) =>
http.post('/app/sqConsignPt/saveSignMultiEntity', data), http.post('/app/sqConsignPt/saveSignMultiEntity', data),
/** 合同系统/签约授权 签约依据查询 */ /** 合同系统/签约授权 签约授权查询 */
get_SigningaAuthorizationSerch: (data?: QueryOptions) => get_SigningaAuthorizationSerch: (data?: QueryOptions) =>
http.get('/app/sqConsignPt/SigningaAuthorizationSerch', data), 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),
}, },
}; };

0
response.ts Normal file
View File