提交
This commit is contained in:
@ -12,9 +12,7 @@ VITE_APP_BASE_API = 'http://192.168.110.209:8899'
|
|||||||
# 罗成
|
# 罗成
|
||||||
# VITE_APP_BASE_API = 'http://192.168.110.213:8899'
|
# VITE_APP_BASE_API = 'http://192.168.110.213:8899'
|
||||||
# 朱银
|
# 朱银
|
||||||
# VITE_APP_BASE_API = 'http://192.168.110.149:8899'
|
# VITE_APP_BASE_API = 'http://192.168.110.180:8899'
|
||||||
#曾涛
|
|
||||||
# VITE_APP_BASE_API = 'http://192.168.110.171:8899'
|
|
||||||
|
|
||||||
# 无人机接口地址
|
# 无人机接口地址
|
||||||
|
|
||||||
|
Binary file not shown.
@ -19,3 +19,11 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
-webkit-user-select: none; /* Safari */
|
||||||
|
-moz-user-select: none; /* Firefox */
|
||||||
|
-ms-user-select: none; /* IE10+/Edge */
|
||||||
|
user-select: none; /* Standard syntax */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -27,3 +27,11 @@ export const systemUserList = (query) => {
|
|||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
// 查询
|
||||||
|
export const desUserList = (query) => {
|
||||||
|
return request({
|
||||||
|
url: '/design/drawingreviewReceipts/desUser/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -56,7 +56,7 @@ export const fillOutTheDesignVerificationForm = (data) => {
|
|||||||
export const drawingreviewReceipts = (data) => {
|
export const drawingreviewReceipts = (data) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/design/drawingreviewReceipts',
|
url: '/design/drawingreviewReceipts',
|
||||||
method: 'post',
|
method: 'put',
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -96,3 +96,10 @@ export const drawingreview = (id) => {
|
|||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
// 获取单据
|
||||||
|
export const getDrawingreviewReceipts = (id) => {
|
||||||
|
return request({
|
||||||
|
url: '/design/drawingreviewReceipts/review/' + id,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -75,3 +75,12 @@ export const getWhetherItExists = (id: string | number): AxiosPromise<ListOfForm
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//模版新增
|
||||||
|
export const addFormalities = (data: any): AxiosPromise<ListOfFormalitiesVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/formalities/formalitiesAreConsolidated/addFormalities',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -160,3 +160,13 @@ export const obtainTheVersion = (query: any) => {
|
|||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* 获取到物资剩余量
|
||||||
|
*/
|
||||||
|
export const mrpBaseRemaining = (query: any) => {
|
||||||
|
return request({
|
||||||
|
url: '/cailiaoshebei/mrpBase/remaining',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -68,3 +68,10 @@ export const getMaterialName = (id: any) => {
|
|||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
//获取出库记录
|
||||||
|
export const inventoryList = (id: any) => {
|
||||||
|
return request({
|
||||||
|
url: '/materials/materialIssue/inventory/list/' + id,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -3,9 +3,9 @@ import { AxiosPromise } from 'axios';
|
|||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
// 获取路由
|
// 获取路由
|
||||||
export function getRouters(): AxiosPromise<RouteRecordRaw[]> {
|
export function getRouters(id: string): AxiosPromise<RouteRecordRaw[]> {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/menu/getRouters',
|
url: '/system/menu/getRouters/' + id,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,14 @@ export interface ContractorForm extends BaseEntity {
|
|||||||
* 主键id
|
* 主键id
|
||||||
*/
|
*/
|
||||||
id?: string | number;
|
id?: string | number;
|
||||||
|
/**
|
||||||
|
* 供应商id
|
||||||
|
*/
|
||||||
|
supplierId?: string | number;
|
||||||
|
/**
|
||||||
|
* 供应商
|
||||||
|
*/
|
||||||
|
supplier?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 主键id
|
* 主键id
|
||||||
|
@ -186,3 +186,14 @@ export const uploadProjectFile = (data: any) => {
|
|||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换项目
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const changeProject = (id: string | number) => {
|
||||||
|
return request({
|
||||||
|
url: '/project/project/changeProject/' + id,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -8,7 +8,7 @@ import { SupplierInputVO, SupplierInputForm, SupplierInputQuery } from '@/api/su
|
|||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const listSupplierInput = (query?: SupplierInputQuery): AxiosPromise<SupplierInputVO[]> => {
|
export const listSupplierInput = (query?: any): AxiosPromise<SupplierInputVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/supplierInput/supplierInput/list',
|
url: '/supplierInput/supplierInput/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
|
@ -68,3 +68,11 @@ export const delMenu = (menuId: string | number) => {
|
|||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取所有路由
|
||||||
|
export const getAllRouters = () => {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/getAllRouters',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -75,3 +75,11 @@ export function getRoleList(deptId?: number | string): AxiosPromise<any[]> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取部门下的项目列表
|
||||||
|
export function getProjectByDeptId(deptId?: number | string): AxiosPromise<any[]> {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/projectIdList/' + deptId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -60,19 +60,20 @@ export interface UserForm {
|
|||||||
nickName?: string;
|
nickName?: string;
|
||||||
password: string;
|
password: string;
|
||||||
phonenumber?: string;
|
phonenumber?: string;
|
||||||
|
projectRoles?: any[];
|
||||||
email?: string;
|
email?: string;
|
||||||
sex?: string;
|
sex?: string;
|
||||||
status: string;
|
status: string;
|
||||||
remark?: string;
|
remark?: string;
|
||||||
postIds: string[];
|
postIds: string[];
|
||||||
roleIds: string[];
|
|
||||||
filePath?: string;
|
filePath?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserInfoVO {
|
export interface UserInfoVO {
|
||||||
user: UserVO;
|
user: UserVO;
|
||||||
roles: RoleVO[];
|
roles: RoleVO[];
|
||||||
roleIds: string[];
|
|
||||||
|
projectRoles: any[];
|
||||||
posts: PostVO[];
|
posts: PostVO[];
|
||||||
postIds: string[];
|
postIds: string[];
|
||||||
roleGroup: string;
|
roleGroup: string;
|
||||||
|
@ -185,6 +185,10 @@ const props = defineProps({
|
|||||||
taskVariables: {
|
taskVariables: {
|
||||||
type: Object as () => Record<string, any>,
|
type: Object as () => Record<string, any>,
|
||||||
default: () => {}
|
default: () => {}
|
||||||
|
},
|
||||||
|
businessId1: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//遮罩层
|
//遮罩层
|
||||||
@ -336,6 +340,9 @@ const handleCompleteTask = async () => {
|
|||||||
}
|
}
|
||||||
if (isDrawing.value) {
|
if (isDrawing.value) {
|
||||||
isShowSubmit.value = true;
|
isShowSubmit.value = true;
|
||||||
|
nextTick(() => {
|
||||||
|
detailFormTeRef.value.getInfo(props.businessId1);
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await proxy?.$modal.confirm('是否确认提交?');
|
await proxy?.$modal.confirm('是否确认提交?');
|
||||||
@ -538,6 +545,9 @@ const handleTermination = async () => {
|
|||||||
const handleTerminationTask = async () => {
|
const handleTerminationTask = async () => {
|
||||||
if (isDrawing.value) {
|
if (isDrawing.value) {
|
||||||
isShowTermination.value = true;
|
isShowTermination.value = true;
|
||||||
|
nextTick(() => {
|
||||||
|
detailFormTeRef.value.getInfo(props.businessId);
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const params = {
|
const params = {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="select-container">
|
<div class="select-container" v-loading.fullscreen.lock="fullscreenLoading">
|
||||||
<label for="projectSelect" class="select-label">项目列表:</label>
|
<label for="projectSelect" class="select-label">项目列表:</label>
|
||||||
<el-select
|
<el-select
|
||||||
id="projectSelect"
|
id="projectSelect"
|
||||||
@ -19,12 +19,18 @@
|
|||||||
import { ref, computed, watch } from 'vue';
|
import { ref, computed, watch } from 'vue';
|
||||||
import { useUserStore } from '@/store/modules/user';
|
import { useUserStore } from '@/store/modules/user';
|
||||||
import { getProjectTeam } from '@/utils/projectTeam';
|
import { getProjectTeam } from '@/utils/projectTeam';
|
||||||
|
import router, { resetRouter } from '@/router';
|
||||||
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
|
import { isHttp } from '@/utils/validate';
|
||||||
|
import { changeProject } from '@/api/project/project';
|
||||||
|
const fullscreenLoading = ref(false);
|
||||||
|
const route = useRoute();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const projects = computed(() => [
|
const projects = computed(() => [
|
||||||
// { id: '', name: '全部工程项目' }, // 添加空选项
|
// { id: '', name: '全部工程项目' }, // 添加空选项
|
||||||
...userStore.projects
|
...userStore.projects
|
||||||
]);
|
]);
|
||||||
|
const proxy = getCurrentInstance()?.proxy as any;
|
||||||
|
|
||||||
const selectedProjectId = ref(userStore.selectedProject?.id || '');
|
const selectedProjectId = ref(userStore.selectedProject?.id || '');
|
||||||
|
|
||||||
@ -37,13 +43,66 @@ watch(
|
|||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSelect = (projectId: string) => {
|
/** 切换项目逻辑 */
|
||||||
|
const handleSelect = async (projectId: string) => {
|
||||||
|
proxy.$cache.local.setJSON('isCheckRole', 'true');
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const permissionStore = usePermissionStore();
|
||||||
const selectedProject = projects.value.find((p) => p.id === projectId);
|
const selectedProject = projects.value.find((p) => p.id === projectId);
|
||||||
if (selectedProject) {
|
if (!selectedProject) return;
|
||||||
userStore.setSelectedProject(selectedProject);
|
const loadingInstance = ElLoading.service({
|
||||||
console.log(userStore.selectedProject); // 打印选中的项目
|
lock: true,
|
||||||
|
text: '项目切换中...',
|
||||||
|
background: 'rgba(0, 0, 0, 0.7)'
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
if (loadingInstance && loadingInstance.visible) {
|
||||||
|
loadingInstance.close();
|
||||||
}
|
}
|
||||||
|
}, 3000);
|
||||||
|
await changeProject(projectId);
|
||||||
|
console.log('切换项目', selectedProject);
|
||||||
|
|
||||||
|
// 更新项目 & 权限
|
||||||
|
userStore.setSelectedProject(selectedProject);
|
||||||
|
await userStore.setInfo();
|
||||||
|
await userStore.setRoles(); // 这里会刷新 permissions/roles
|
||||||
|
// 重新生成路由
|
||||||
|
permissionStore.generateRoutes().then((routeList) => {
|
||||||
|
const currentPath = router.currentRoute.value.fullPath;
|
||||||
|
const exist = currentPath == '/' || currentPath == '/index' ? true : routeExists(currentPath, routeList);
|
||||||
|
if (exist) return loadingInstance.close();
|
||||||
|
|
||||||
|
proxy?.$tab.closeAllPage();
|
||||||
|
router.push('/index');
|
||||||
|
loadingInstance.close();
|
||||||
|
|
||||||
|
// 刷新当前路由
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
function routeExists(fullPath: string, routes: any[], parentPath = ''): boolean {
|
||||||
|
for (const route of routes) {
|
||||||
|
// 拼接完整 path
|
||||||
|
let currentPath = route.path.startsWith('/') ? route.path : `${parentPath}/${route.path}`;
|
||||||
|
|
||||||
|
// 处理多余的 "//"
|
||||||
|
currentPath = currentPath.replace(/\/+/g, '/');
|
||||||
|
|
||||||
|
// 判断
|
||||||
|
if (currentPath === fullPath) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归子路由
|
||||||
|
if (route.children && route.children.length > 0) {
|
||||||
|
if (routeExists(fullPath, route.children, currentPath)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<el-menu-item v-if="index < visibleNumber" :key="index" :style="{ '--theme': theme }" :index="item.path">
|
<el-menu-item v-if="index < visibleNumber" :key="index" :style="{ '--theme': theme }" :index="item.path">
|
||||||
<svg-icon v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" :icon-class="item.meta ? item.meta.icon : ''" />
|
<svg-icon v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" :icon-class="item.meta ? item.meta.icon : ''" />
|
||||||
{{ item.meta?.title }}
|
{{ item.meta?.title }}
|
||||||
|
<!-- <span class="bage" v-if="item.meta?.title == '我的任务' && total > 0">{{ total }}</span> -->
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -26,20 +27,27 @@ import useAppStore from '@/store/modules/app';
|
|||||||
import useSettingsStore from '@/store/modules/settings';
|
import useSettingsStore from '@/store/modules/settings';
|
||||||
import usePermissionStore from '@/store/modules/permission';
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
import useUserStore from '@/store/modules/user';
|
||||||
|
import useNoticeStore from '@/store/modules/notice';
|
||||||
|
import { pageByTaskWait } from '@/api/workflow/task';
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const noticeStore = storeToRefs(useNoticeStore());
|
||||||
// 顶部栏初始数
|
// 顶部栏初始数
|
||||||
const visibleNumber = ref<number>(-1);
|
const visibleNumber = ref<number>(-1);
|
||||||
// 当前激活菜单的 index
|
// 当前激活菜单的 index
|
||||||
const currentIndex = ref<string>();
|
const currentIndex = ref<string>();
|
||||||
// 隐藏侧边栏路由
|
// 隐藏侧边栏路由
|
||||||
const hideList = ['/index', '/user/profile'];
|
const hideList = ['/index', '/user/profile'];
|
||||||
|
const total = ref(1);
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const permissionStore = usePermissionStore();
|
const permissionStore = usePermissionStore();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
onMounted(() => {
|
||||||
|
console.log(33333);
|
||||||
|
getWaitingList();
|
||||||
|
});
|
||||||
// 主题颜色
|
// 主题颜色
|
||||||
const theme = computed(() => settingsStore.theme);
|
const theme = computed(() => settingsStore.theme);
|
||||||
// 所有的路由信息
|
// 所有的路由信息
|
||||||
@ -158,6 +166,26 @@ onBeforeUnmount(() => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setVisibleNumber();
|
setVisibleNumber();
|
||||||
});
|
});
|
||||||
|
// 获取我的待办
|
||||||
|
//分页
|
||||||
|
const getWaitingList = () => {
|
||||||
|
pageByTaskWait({ pageNum: 1, pageSize: 10 }).then((resp) => {
|
||||||
|
console.log(resp);
|
||||||
|
|
||||||
|
total.value = resp.total;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
//用深度监听 消息
|
||||||
|
watch(
|
||||||
|
() => noticeStore.state.value.notices,
|
||||||
|
(newVal) => {
|
||||||
|
let time = setTimeout(() => {
|
||||||
|
getWaitingList();
|
||||||
|
clearTimeout(time);
|
||||||
|
}, 500);
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@ -197,4 +225,31 @@ onMounted(() => {
|
|||||||
.topmenu-container .svg-icon {
|
.topmenu-container .svg-icon {
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
.bage {
|
||||||
|
position: absolute;
|
||||||
|
top: 6px;
|
||||||
|
right: -12px;
|
||||||
|
padding: 0 6px;
|
||||||
|
height: 16px;
|
||||||
|
line-height: 16px;
|
||||||
|
background: #ff7a7a;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #fff;
|
||||||
|
white-space: nowrap;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-menu-item .el-menu-item__content {
|
||||||
|
position: relative;
|
||||||
|
padding-right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-title {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: calc(100% - 24px);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
<svg-icon :icon-class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" />
|
<svg-icon :icon-class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" />
|
||||||
<template #title>
|
<template #title>
|
||||||
<span class="menu-title" :title="hasTitle(onlyOneChild.meta.title)">{{ onlyOneChild.meta.title }}</span>
|
<span class="menu-title" :title="hasTitle(onlyOneChild.meta.title)">{{ onlyOneChild.meta.title }}</span>
|
||||||
|
<span class="bage" v-if="onlyOneChild.meta?.title == '我的待办' && total > 0">{{ total }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</app-link>
|
</app-link>
|
||||||
@ -15,6 +16,7 @@
|
|||||||
<template v-if="item.meta" #title>
|
<template v-if="item.meta" #title>
|
||||||
<svg-icon :icon-class="item.meta ? item.meta.icon : ''" />
|
<svg-icon :icon-class="item.meta ? item.meta.icon : ''" />
|
||||||
<span class="menu-title" :title="hasTitle(item.meta?.title)">{{ item.meta?.title }}</span>
|
<span class="menu-title" :title="hasTitle(item.meta?.title)">{{ item.meta?.title }}</span>
|
||||||
|
<!-- <span class="bage" v-if="item.meta?.title == '我的任务' && total >= 0">{{ total }}</span> -->
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<sidebar-item
|
<sidebar-item
|
||||||
@ -34,7 +36,11 @@ import { isExternal } from '@/utils/validate';
|
|||||||
import AppLink from './Link.vue';
|
import AppLink from './Link.vue';
|
||||||
import { getNormalPath } from '@/utils/ruoyi';
|
import { getNormalPath } from '@/utils/ruoyi';
|
||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
import { pageByTaskWait } from '@/api/workflow/task';
|
||||||
|
import useUserStore from '@/store/modules/user';
|
||||||
|
import useNoticeStore from '@/store/modules/notice';
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const noticeStore = storeToRefs(useNoticeStore());
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
item: {
|
item: {
|
||||||
type: Object as PropType<RouteRecordRaw>,
|
type: Object as PropType<RouteRecordRaw>,
|
||||||
@ -49,7 +55,22 @@ const props = defineProps({
|
|||||||
default: ''
|
default: ''
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const total = ref(0);
|
||||||
|
onMounted(() => {
|
||||||
|
if (onlyOneChild.value.meta?.title == '我的待办' || props.item.meta?.title == '我的任务') {
|
||||||
|
console.log(44444444);
|
||||||
|
getWaitingList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 获取我的待办
|
||||||
|
//分页
|
||||||
|
const getWaitingList = () => {
|
||||||
|
pageByTaskWait({ pageNum: 1, pageSize: 10 }).then((resp) => {
|
||||||
|
console.log(resp);
|
||||||
|
|
||||||
|
total.value = resp.total;
|
||||||
|
});
|
||||||
|
};
|
||||||
const onlyOneChild = ref<any>({});
|
const onlyOneChild = ref<any>({});
|
||||||
|
|
||||||
const hasOneShowingChild = (parent: RouteRecordRaw, children?: RouteRecordRaw[]) => {
|
const hasOneShowingChild = (parent: RouteRecordRaw, children?: RouteRecordRaw[]) => {
|
||||||
@ -64,12 +85,12 @@ const hasOneShowingChild = (parent: RouteRecordRaw, children?: RouteRecordRaw[])
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// When there is only one child router, the child router is displayed by default
|
// 只有一个子路由时默认显示子路由
|
||||||
if (showingChildren.length === 1) {
|
if (showingChildren.length === 1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show parent if there are no child router to display
|
// 没有子路由可显示时显示父路由
|
||||||
if (showingChildren.length === 0) {
|
if (showingChildren.length === 0) {
|
||||||
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true };
|
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true };
|
||||||
return true;
|
return true;
|
||||||
@ -98,4 +119,49 @@ const hasTitle = (title: string | undefined): string => {
|
|||||||
}
|
}
|
||||||
return title;
|
return title;
|
||||||
};
|
};
|
||||||
|
//用深度监听 消息
|
||||||
|
watch(
|
||||||
|
() => noticeStore.state.value.notices,
|
||||||
|
(newVal) => {
|
||||||
|
if (onlyOneChild.value.meta?.title == '我的待办') {
|
||||||
|
console.log(121212121);
|
||||||
|
|
||||||
|
let time = setTimeout(() => {
|
||||||
|
getWaitingList();
|
||||||
|
clearTimeout(time);
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.bage {
|
||||||
|
position: absolute;
|
||||||
|
top: 6px;
|
||||||
|
right: 36px;
|
||||||
|
padding: 0 6px;
|
||||||
|
height: 16px;
|
||||||
|
line-height: 16px;
|
||||||
|
background: #ff7a7a;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #fff;
|
||||||
|
white-space: nowrap;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-menu-item .el-menu-item__content {
|
||||||
|
position: relative;
|
||||||
|
padding-right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-title {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: calc(100% - 24px);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import $cache from '@/plugins/cache';
|
||||||
import { to as tos } from 'await-to-js';
|
import { to as tos } from 'await-to-js';
|
||||||
import router from './router';
|
import router from './router';
|
||||||
import NProgress from 'nprogress';
|
import NProgress from 'nprogress';
|
||||||
@ -9,6 +10,8 @@ import useUserStore from '@/store/modules/user';
|
|||||||
import useSettingsStore from '@/store/modules/settings';
|
import useSettingsStore from '@/store/modules/settings';
|
||||||
import usePermissionStore from '@/store/modules/permission';
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
|
|
||||||
|
let isFirst = false;
|
||||||
|
|
||||||
NProgress.configure({ showSpinner: false });
|
NProgress.configure({ showSpinner: false });
|
||||||
const whiteList = ['/login', '/register', '/social-callback', '/register*', '/register/*', '/materials/purchaseDoc/uploadCode'];
|
const whiteList = ['/login', '/register', '/social-callback', '/register*', '/register/*', '/materials/purchaseDoc/uploadCode'];
|
||||||
|
|
||||||
@ -16,54 +19,64 @@ const isWhiteList = (path: string) => {
|
|||||||
return whiteList.some((pattern) => isPathMatch(pattern, path));
|
return whiteList.some((pattern) => isPathMatch(pattern, path));
|
||||||
};
|
};
|
||||||
|
|
||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from) => {
|
||||||
NProgress.start();
|
NProgress.start();
|
||||||
if (to.path == '/indexEquipment' || to.path == '/materials/purchaseDoc/uploadCode' || to.path == '/codeDetail') {
|
|
||||||
next();
|
// 特殊页面放行
|
||||||
} else if (getToken()) {
|
if (['/indexEquipment', '/materials/purchaseDoc/uploadCode', '/codeDetail'].includes(to.path)) {
|
||||||
to.meta.title && useSettingsStore().setTitle(to.meta.title);
|
return true;
|
||||||
/* has token*/
|
}
|
||||||
|
|
||||||
|
// 已登录
|
||||||
|
if (getToken()) {
|
||||||
|
if (to.meta.title) useSettingsStore().setTitle(to.meta.title);
|
||||||
|
|
||||||
if (to.path === '/login') {
|
if (to.path === '/login') {
|
||||||
next({ path: '/' });
|
|
||||||
NProgress.done();
|
NProgress.done();
|
||||||
} else if (isWhiteList(to.path)) {
|
return { path: '/' };
|
||||||
next();
|
}
|
||||||
} else {
|
|
||||||
if (useUserStore().roles.length === 0) {
|
if (isWhiteList(to.path)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((!isFirst && useUserStore().roles.length === 0) || $cache.local.getJSON('isCheckRole') === 'true') {
|
||||||
|
isFirst = true;
|
||||||
isRelogin.show = true;
|
isRelogin.show = true;
|
||||||
// 判断当前用户是否已拉取完user_info信息
|
|
||||||
const [err] = await tos(useUserStore().getInfo());
|
const [err] = await tos(useUserStore().getInfo());
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
await useUserStore().logout();
|
await useUserStore().logout();
|
||||||
ElMessage.error(err);
|
ElMessage.error(err);
|
||||||
next({ path: '/' });
|
NProgress.done();
|
||||||
} else {
|
return { path: '/' };
|
||||||
|
}
|
||||||
|
|
||||||
isRelogin.show = false;
|
isRelogin.show = false;
|
||||||
const accessRoutes = await usePermissionStore().generateRoutes();
|
const accessRoutes = await usePermissionStore().generateRoutes();
|
||||||
// 根据roles权限生成可访问的路由表
|
|
||||||
accessRoutes.forEach((route) => {
|
accessRoutes.forEach((route) => {
|
||||||
if (!isHttp(route.path)) {
|
if (!isHttp(route.path)) router.addRoute(route);
|
||||||
router.addRoute(route); // 动态添加可访问路由表
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
// @ts-expect-error hack方法 确保addRoutes已完成
|
|
||||||
next({ path: to.path, replace: true, params: to.params, query: to.query, hash: to.hash, name: to.name as string }); // hack方法 确保addRoutes已完成
|
$cache.local.remove('isCheckRole');
|
||||||
|
|
||||||
|
// 确保路由已添加后再跳转
|
||||||
|
return { ...to, replace: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
next();
|
isFirst = false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
// 未登录
|
||||||
// 没有token
|
|
||||||
if (isWhiteList(to.path)) {
|
if (isWhiteList(to.path)) {
|
||||||
// 在免登录白名单,直接进入
|
return true;
|
||||||
next();
|
}
|
||||||
} else {
|
|
||||||
const redirect = encodeURIComponent(to.fullPath || '/');
|
const redirect = encodeURIComponent(to.fullPath || '/');
|
||||||
next(`/login?redirect=${redirect}`); // 否则全部重定向到登录页
|
|
||||||
NProgress.done();
|
NProgress.done();
|
||||||
}
|
return { path: `/login?redirect=${redirect}` };
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
router.afterEach(() => {
|
router.afterEach(() => {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { createWebHistory, createRouter, RouteRecordRaw } from 'vue-router';
|
import { createWebHistory, createRouter, RouteRecordRaw } from 'vue-router';
|
||||||
/* Layout */
|
/* Layout */
|
||||||
import Layout from '@/layout/index.vue';
|
import Layout from '@/layout/index.vue';
|
||||||
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note: 路由配置项
|
* Note: 路由配置项
|
||||||
@ -65,11 +66,7 @@ export const constantRoutes: RouteRecordRaw[] = [
|
|||||||
component: () => import('@/views/register.vue'),
|
component: () => import('@/views/register.vue'),
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/:pathMatch(.*)*',
|
|
||||||
component: () => import('@/views/error/404.vue'),
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/401',
|
path: '/401',
|
||||||
component: () => import('@/views/error/401.vue'),
|
component: () => import('@/views/error/401.vue'),
|
||||||
@ -134,10 +131,16 @@ export const constantRoutes: RouteRecordRaw[] = [
|
|||||||
component: () => import('@/views/gis2D/index.vue'),
|
component: () => import('@/views/gis2D/index.vue'),
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/materials/purchaseDoc/uploadCode',
|
path: '/materials/purchaseDoc/uploadCode',
|
||||||
component: () => import('@/views/materials/purchaseDoc/uploadCode.vue'),
|
component: () => import('@/views/materials/purchaseDoc/uploadCode.vue'),
|
||||||
hidden: true
|
hidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/:pathMatch(.*)*',
|
||||||
|
component: () => import('@/views/error/404.vue'),
|
||||||
|
hidden: true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -231,3 +234,11 @@ const router = createRouter({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
||||||
|
export function resetRouter() {
|
||||||
|
router.getRoutes().forEach((route) => {
|
||||||
|
if (route.name && !constantRoutes.find((r) => r.name === route.name)) {
|
||||||
|
router.hasRoute(route.name) && router.removeRoute(route.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -10,6 +10,7 @@ import ParentView from '@/components/ParentView/index.vue';
|
|||||||
import InnerLink from '@/layout/components/InnerLink/index.vue';
|
import InnerLink from '@/layout/components/InnerLink/index.vue';
|
||||||
|
|
||||||
import { createCustomNameComponent } from '@/utils/createCustomNameComponent';
|
import { createCustomNameComponent } from '@/utils/createCustomNameComponent';
|
||||||
|
import { useUserStoreHook } from './user';
|
||||||
|
|
||||||
// 匹配views里面所有的.vue文件
|
// 匹配views里面所有的.vue文件
|
||||||
const modules = import.meta.glob('./../../views/**/*.vue');
|
const modules = import.meta.glob('./../../views/**/*.vue');
|
||||||
@ -44,7 +45,7 @@ export const usePermissionStore = defineStore('permission', () => {
|
|||||||
sidebarRouters.value = routes;
|
sidebarRouters.value = routes;
|
||||||
};
|
};
|
||||||
const generateRoutes = async (): Promise<RouteRecordRaw[]> => {
|
const generateRoutes = async (): Promise<RouteRecordRaw[]> => {
|
||||||
const res = await getRouters();
|
const res = await getRouters(useUserStoreHook().selectedProject?.id || '0');
|
||||||
const { data } = res;
|
const { data } = res;
|
||||||
const sdata = JSON.parse(JSON.stringify(data));
|
const sdata = JSON.parse(JSON.stringify(data));
|
||||||
const rdata = JSON.parse(JSON.stringify(data));
|
const rdata = JSON.parse(JSON.stringify(data));
|
||||||
|
@ -28,7 +28,6 @@ const getSelectedProjectFromStorage = () => {
|
|||||||
const getProjectTeamListFromStorage = () => {
|
const getProjectTeamListFromStorage = () => {
|
||||||
const stored = $cache.local.getJSON('ProjectTeamList');
|
const stored = $cache.local.getJSON('ProjectTeamList');
|
||||||
console.log('获取缓存的项目班组列表:', stored);
|
console.log('获取缓存的项目班组列表:', stored);
|
||||||
|
|
||||||
return stored ? stored : null;
|
return stored ? stored : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -41,7 +40,9 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
const deptId = ref<string | number>('');
|
const deptId = ref<string | number>('');
|
||||||
const avatar = ref('');
|
const avatar = ref('');
|
||||||
const roles = ref<Array<string>>([]); // 用户角色编码集合 → 判断路由权限
|
const roles = ref<Array<string>>([]); // 用户角色编码集合 → 判断路由权限
|
||||||
const permissions = ref<Array<string>>([]); // 用户权限编码集合 → 判断按钮权限
|
const permissions = ref<Array<any>>([]); // 用户权限编码集合 → 判断按钮权限
|
||||||
|
const permissionList = ref<Array<any>>([]); // 用户所有权限列表
|
||||||
|
const roleList = ref<Array<any>>([]); // 用户所有角色列表
|
||||||
|
|
||||||
const projects = ref<Array<{ id: string; name: string }>>([]);
|
const projects = ref<Array<{ id: string; name: string }>>([]);
|
||||||
// 从localStorage获取缓存的项目,如果没有则默认为null
|
// 从localStorage获取缓存的项目,如果没有则默认为null
|
||||||
@ -66,15 +67,32 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
|
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
const getInfo = async (): Promise<void> => {
|
const getInfo = async (): Promise<void> => {
|
||||||
|
// **新增项目数据获取**
|
||||||
|
const [projectErr, projectRes] = await to(getUserProject());
|
||||||
|
if (projectRes?.data) {
|
||||||
|
const projectList = projectRes.data.map((p) => ({
|
||||||
|
id: p.projectId,
|
||||||
|
name: p.projectName || '未知项目'
|
||||||
|
}));
|
||||||
|
setProjects(projectList);
|
||||||
|
// 如果有缓存的选中项目,且该项目在当前项目列表中存在,则使用缓存的项目
|
||||||
|
const storedProject = getSelectedProjectFromStorage();
|
||||||
|
if (storedProject && projectList.some((p) => p.id === storedProject.id)) {
|
||||||
|
setSelectedProject(storedProject);
|
||||||
|
} else if (projectList.length > 0) {
|
||||||
|
// 否则默认选择第一个项目
|
||||||
|
setSelectedProject(projectList[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
const [err, res] = await to(getUserInfo());
|
const [err, res] = await to(getUserInfo());
|
||||||
if (res) {
|
if (res) {
|
||||||
const data = res.data;
|
const data = res.data;
|
||||||
const user = data.user;
|
const user = data.user;
|
||||||
const profile = user.avatar == '' || user.avatar == null ? defAva : user.avatar;
|
const profile = user.avatar == '' || user.avatar == null ? defAva : user.avatar;
|
||||||
|
|
||||||
if (data.roles && data.roles.length > 0) {
|
if (data.roles && data.roles.length > 0) {
|
||||||
roles.value = data.roles;
|
permissionList.value = data.permissions;
|
||||||
permissions.value = data.permissions;
|
roleList.value = data.roles;
|
||||||
|
setRoles();
|
||||||
} else {
|
} else {
|
||||||
roles.value = ['ROLE_DEFAULT'];
|
roles.value = ['ROLE_DEFAULT'];
|
||||||
}
|
}
|
||||||
@ -85,30 +103,38 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
tenantId.value = user.tenantId;
|
tenantId.value = user.tenantId;
|
||||||
deptId.value = user.deptId;
|
deptId.value = user.deptId;
|
||||||
|
|
||||||
// **新增项目数据获取**
|
|
||||||
const [projectErr, projectRes] = await to(getUserProject());
|
|
||||||
if (projectRes?.data) {
|
|
||||||
const projectList = projectRes.data.map((p) => ({
|
|
||||||
id: p.projectId,
|
|
||||||
name: p.projectName || '未知项目'
|
|
||||||
}));
|
|
||||||
|
|
||||||
setProjects(projectList);
|
|
||||||
|
|
||||||
// 如果有缓存的选中项目,且该项目在当前项目列表中存在,则使用缓存的项目
|
|
||||||
const storedProject = getSelectedProjectFromStorage();
|
|
||||||
if (storedProject && projectList.some((p) => p.id === storedProject.id)) {
|
|
||||||
setSelectedProject(storedProject);
|
|
||||||
} else if (projectList.length > 0) {
|
|
||||||
// 否则默认选择第一个项目
|
|
||||||
setSelectedProject(projectList[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
return Promise.reject(err);
|
return Promise.reject(err);
|
||||||
};
|
};
|
||||||
|
const setInfo = async () => {
|
||||||
|
const [err, res] = await to(getUserInfo());
|
||||||
|
if (res) {
|
||||||
|
const data = res.data;
|
||||||
|
const user = data.user;
|
||||||
|
const profile = user.avatar == '' || user.avatar == null ? defAva : user.avatar;
|
||||||
|
if (data.roles && data.roles.length > 0) {
|
||||||
|
permissionList.value = data.permissions;
|
||||||
|
roleList.value = data.roles;
|
||||||
|
setRoles();
|
||||||
|
} else {
|
||||||
|
roles.value = ['ROLE_DEFAULT'];
|
||||||
|
}
|
||||||
|
name.value = user.userName;
|
||||||
|
nickname.value = user.nickName;
|
||||||
|
avatar.value = profile;
|
||||||
|
userId.value = user.userId;
|
||||||
|
tenantId.value = user.tenantId;
|
||||||
|
deptId.value = user.deptId;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setRoles = () => {
|
||||||
|
const projectRole = roleList.value.find((item) => item.projectId == selectedProject.value?.id)?.projectRoles || [];
|
||||||
|
roles.value = projectRole;
|
||||||
|
const projectPermissions = permissionList.value.find((item) => item.projectId == selectedProject.value?.id)?.projectPermissions || [];
|
||||||
|
permissions.value = projectPermissions;
|
||||||
|
};
|
||||||
|
|
||||||
// 注销
|
// 注销
|
||||||
const logout = async (): Promise<void> => {
|
const logout = async (): Promise<void> => {
|
||||||
@ -158,7 +184,9 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
setProjectTeamList,
|
setProjectTeamList,
|
||||||
projects,
|
projects,
|
||||||
selectedProject,
|
selectedProject,
|
||||||
ProjectTeamList
|
ProjectTeamList,
|
||||||
|
setInfo,
|
||||||
|
setRoles
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -20,12 +20,10 @@ export const initSSE = (url: any) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
watch(error, () => {
|
watch(error, () => {
|
||||||
console.log('SSE connection error:', error.value);
|
|
||||||
error.value = null;
|
error.value = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(data, () => {
|
watch(data, () => {
|
||||||
console.log('🚀 ~ initSSE ~ data:', JSON.parse(data.value));
|
|
||||||
let label = '';
|
let label = '';
|
||||||
let route1 = '';
|
let route1 = '';
|
||||||
let detailId = '';
|
let detailId = '';
|
||||||
@ -33,6 +31,9 @@ export const initSSE = (url: any) => {
|
|||||||
if (JSON.parse(data.value)) {
|
if (JSON.parse(data.value)) {
|
||||||
const obj = JSON.parse(data.value);
|
const obj = JSON.parse(data.value);
|
||||||
route1 = obj.type;
|
route1 = obj.type;
|
||||||
|
if (obj.type == 'count') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
label = obj.content;
|
label = obj.content;
|
||||||
// detailId = obj.detailId;
|
// detailId = obj.detailId;
|
||||||
data.value = null;
|
data.value = null;
|
||||||
|
@ -63,14 +63,7 @@
|
|||||||
<el-table-column prop="quantity" label="数量" />
|
<el-table-column prop="quantity" label="数量" />
|
||||||
<el-table-column prop="remark" label="单价" align="center">
|
<el-table-column prop="remark" label="单价" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input-number
|
<span>{{ scope.row.unitPrice }}</span>
|
||||||
:model-value="scope.row.unitPrice"
|
|
||||||
@change="(val) => (scope.row.unitPrice = val)"
|
|
||||||
:precision="2"
|
|
||||||
:step="0.1"
|
|
||||||
:controls="false"
|
|
||||||
v-if="scope.row.quantity && scope.row.quantity != 0"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="price" label="总价" align="center">
|
<el-table-column prop="price" label="总价" align="center">
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
icon="view"
|
icon="view"
|
||||||
@click="handleViewInfo"
|
@click="handleViewInfo"
|
||||||
v-hasPermi="['bidding:biddingLimitList:getVersionDetail']"
|
v-hasPermi="['bidding:biddingLimitList:getVersionDetail']"
|
||||||
v-if="versionObj.status != 'draft'"
|
v-if="versionObj.status && versionObj.status != 'draft'"
|
||||||
>查看流程</el-button
|
>查看流程</el-button
|
||||||
>
|
>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -60,13 +60,22 @@
|
|||||||
<el-table-column prop="num" label="编号" />
|
<el-table-column prop="num" label="编号" />
|
||||||
<el-table-column prop="name" label="工程或费用名称" />
|
<el-table-column prop="name" label="工程或费用名称" />
|
||||||
<el-table-column prop="unit" label="单位" />
|
<el-table-column prop="unit" label="单位" />
|
||||||
<el-table-column prop="quantity" label="数量" />
|
<el-table-column prop="quantity" label="数量">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ scope.row.children.length > 0 ? '' : scope.row.quantity }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="remark" label="单价" align="center">
|
<el-table-column prop="remark" label="单价" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="versionObj.status != 'draft'"
|
:disabled="versionObj.status != 'draft'"
|
||||||
:model-value="scope.row.unitPrice"
|
:model-value="scope.row.unitPrice"
|
||||||
@change="(val) => (scope.row.unitPrice = val)"
|
@change="
|
||||||
|
(val) => {
|
||||||
|
scope.row.unitPrice = val;
|
||||||
|
changePrice(scope.row);
|
||||||
|
}
|
||||||
|
"
|
||||||
:precision="2"
|
:precision="2"
|
||||||
:step="0.1"
|
:step="0.1"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
@ -85,7 +94,7 @@
|
|||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
size="small"
|
||||||
:disabled="versionObj.status != 'draft'"
|
:disabled="versionObj.status != 'draft'"
|
||||||
@click="handleSave(scope.row)"
|
@click="handleSave(scope.row, 'all')"
|
||||||
v-if="scope.row.quantity && scope.row.quantity != 0"
|
v-if="scope.row.quantity && scope.row.quantity != 0"
|
||||||
v-hasPermi="['bidding:biddingLimitList:edit']"
|
v-hasPermi="['bidding:biddingLimitList:edit']"
|
||||||
>确定</el-button
|
>确定</el-button
|
||||||
@ -187,18 +196,21 @@ const getTableData = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//修改单价
|
const modifyPrice = new Map();
|
||||||
const handleSave = (row: any) => {
|
|
||||||
|
const changePrice = (row: any) => {
|
||||||
|
modifyPrice.set(row.id, row);
|
||||||
|
// if (!row.unitPrice) {
|
||||||
|
// modifyPrice.delete(row.id);
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
//修改单价 biddingLimitListUpdate
|
||||||
|
const handleSave = (row?: any, type?: any) => {
|
||||||
try {
|
try {
|
||||||
if (!row.unitPrice) {
|
if (type == 'single') {
|
||||||
ElMessage({
|
|
||||||
message: '请输入单价',
|
|
||||||
type: 'warning'
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
biddingLimitListUpdate(row).then((res) => {
|
const list = [{ ...row }];
|
||||||
|
biddingLimitListUpdate(list).then((res) => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: '修改成功',
|
message: '修改成功',
|
||||||
@ -207,11 +219,30 @@ const handleSave = (row: any) => {
|
|||||||
getTableData();
|
getTableData();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
if (type == 'all') {
|
||||||
|
loading.value = true;
|
||||||
|
const list = [];
|
||||||
|
modifyPrice.forEach((item) => {
|
||||||
|
list.push({ ...item });
|
||||||
|
});
|
||||||
|
biddingLimitListUpdate(list).then((res) => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
ElMessage({
|
||||||
|
message: '修改成功',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
getTableData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: '修改失败',
|
message: '修改失败',
|
||||||
type: 'error'
|
type: 'error'
|
||||||
});
|
});
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const tableRef = ref<any>();
|
const tableRef = ref<any>();
|
||||||
|
@ -26,20 +26,39 @@
|
|||||||
<el-table-column prop="name" label="名称" />
|
<el-table-column prop="name" label="名称" />
|
||||||
<el-table-column prop="content" label="内容" />
|
<el-table-column prop="content" label="内容" />
|
||||||
<el-table-column prop="price" label="限价" />
|
<el-table-column prop="price" label="限价" />
|
||||||
<el-table-column prop="plannedBiddingTime" label="计划招标时间" align="center">
|
<el-table-column prop="plannedBiddingTime" align="center">
|
||||||
|
<template #header> <span style="color: red">*</span>计划招标时间 </template>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-date-picker v-model="scope.row.plannedBiddingTime" type="date" value-format="YYYY-MM-DD" placeholder="选择时间" />
|
<el-date-picker v-model="scope.row.plannedBiddingTime" type="date" value-format="YYYY-MM-DD" placeholder="选择时间" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="price" label="操作" align="center">
|
<el-table-column prop="price" label="操作" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button type="warning" size="small" @click="handleDetail(scope.row)" v-hasPermi="['tender:segmentedIndicatorPlanning:getMore']"
|
<el-button
|
||||||
|
type="warning"
|
||||||
|
icon="view"
|
||||||
|
size="small"
|
||||||
|
link
|
||||||
|
@click="handleDetail(scope.row)"
|
||||||
|
v-hasPermi="['tender:segmentedIndicatorPlanning:getMore']"
|
||||||
>详情</el-button
|
>详情</el-button
|
||||||
>
|
>
|
||||||
<el-button type="primary" size="small" @click="handleSave(scope.row)" v-hasPermi="['tender:segmentedIndicatorPlanning:edit']"
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
icon="edit"
|
||||||
|
size="small"
|
||||||
|
link
|
||||||
|
@click="handleSave(scope.row)"
|
||||||
|
v-hasPermi="['tender:segmentedIndicatorPlanning:edit']"
|
||||||
>确定</el-button
|
>确定</el-button
|
||||||
>
|
>
|
||||||
<el-button type="danger" size="small" @click="delHandle(scope.row)" v-hasPermi="['tender:segmentedIndicatorPlanning:remove']"
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
icon="delete"
|
||||||
|
size="small"
|
||||||
|
link
|
||||||
|
@click="delHandle(scope.row)"
|
||||||
|
v-hasPermi="['tender:segmentedIndicatorPlanning:remove']"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
@ -99,7 +118,8 @@
|
|||||||
<el-table-column prop="name" label="工程或费用名称" />
|
<el-table-column prop="name" label="工程或费用名称" />
|
||||||
<el-table-column prop="unit" label="单位" />
|
<el-table-column prop="unit" label="单位" />
|
||||||
<!-- <el-table-column prop="quantity" label="数量" /> -->
|
<!-- <el-table-column prop="quantity" label="数量" /> -->
|
||||||
<el-table-column prop="selectNum" label="选择数量" align="center">
|
<el-table-column prop="quantity" label="计划量" align="center" />
|
||||||
|
<el-table-column prop="selectNum" label="设计量" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:model-value="scope.row.selectNum"
|
:model-value="scope.row.selectNum"
|
||||||
@ -113,16 +133,36 @@
|
|||||||
:step="1"
|
:step="1"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
:max="Math.floor(scope.row.quantity)"
|
:max="Math.floor(scope.row.quantity)"
|
||||||
v-if="scope.row.quantity && scope.row.quantity != 0"
|
v-if="scope.row.quantity && scope.row.quantity != 0 && scope.row.unitPrice"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="unitPrice" label="单价" align="center" />
|
|
||||||
<!-- <el-table-column prop="price" label="总价" align="center">
|
<el-table-column prop="useQuantity" label="剩余量" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
{{ scope.row.price }}
|
{{
|
||||||
|
(scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) == 0
|
||||||
|
? ''
|
||||||
|
: (scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)
|
||||||
|
}}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column> -->
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="unitPrice" label="单价" align="center" />
|
||||||
|
<el-table-column prop="price" label="总价" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
{{
|
||||||
|
((scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)) *
|
||||||
|
Number(scope.row.unitPrice) ==
|
||||||
|
0
|
||||||
|
? ''
|
||||||
|
: (
|
||||||
|
((scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)) *
|
||||||
|
Number(scope.row.unitPrice)
|
||||||
|
).toFixed(2)
|
||||||
|
}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
@ -35,14 +35,15 @@
|
|||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="handleExport()" v-hasPermi="['tender:billofquantitiesLimitList:export']">导出excel</el-button>
|
<el-button type="primary" @click="handleExport()" v-hasPermi="['tender:billofquantitiesLimitList:export']">导出excel</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" v-if="reviewStatus == 'draft'" @click="clickApprovalSheet()">审核</el-button>
|
<el-button type="primary" v-if="reviewStatus && reviewStatus == 'draft'" @click="clickApprovalSheet()">审核</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button
|
<el-button
|
||||||
type="warning"
|
type="warning"
|
||||||
icon="view"
|
icon="view"
|
||||||
v-if="reviewStatus != 'draft'"
|
v-if="reviewStatus && reviewStatus != 'draft'"
|
||||||
@click="clickApprovalSheet()"
|
@click="clickApprovalSheet()"
|
||||||
v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
|
v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
|
||||||
>查看流程</el-button
|
>查看流程</el-button
|
||||||
@ -56,7 +57,11 @@
|
|||||||
<el-table-column prop="num" label="编号" />
|
<el-table-column prop="num" label="编号" />
|
||||||
<el-table-column prop="name" label="工程或费用名称" />
|
<el-table-column prop="name" label="工程或费用名称" />
|
||||||
<el-table-column prop="unit" label="单位" />
|
<el-table-column prop="unit" label="单位" />
|
||||||
<el-table-column prop="quantity" label="数量" />
|
<el-table-column prop="quantity" label="数量">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ scope.row.children.length > 0 ? '' : scope.row.quantity }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="unitPrice" label="单价" align="center">
|
<el-table-column prop="unitPrice" label="单价" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
@ -65,6 +70,7 @@
|
|||||||
@change="
|
@change="
|
||||||
(val) => {
|
(val) => {
|
||||||
scope.row.unitPrice = val;
|
scope.row.unitPrice = val;
|
||||||
|
changePrice(scope.row);
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
:precision="2"
|
:precision="2"
|
||||||
@ -87,7 +93,7 @@
|
|||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
size="small"
|
||||||
:disabled="reviewStatus != 'draft'"
|
:disabled="reviewStatus != 'draft'"
|
||||||
@click="handleSave(scope.row)"
|
@click="handleSave(scope.row, 'all')"
|
||||||
v-if="scope.row.quantity && scope.row.quantity != 0"
|
v-if="scope.row.quantity && scope.row.quantity != 0"
|
||||||
v-hasPermi="['tender:billofquantitiesLimitList:edit']"
|
v-hasPermi="['tender:billofquantitiesLimitList:edit']"
|
||||||
>确定</el-button
|
>确定</el-button
|
||||||
@ -220,18 +226,18 @@ const getTableData = async () => {
|
|||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const modifyPrice = new Map();
|
||||||
|
|
||||||
|
const changePrice = (row: any) => {
|
||||||
|
modifyPrice.set(row.id, row);
|
||||||
|
};
|
||||||
//修改单价
|
//修改单价
|
||||||
const handleSave = (row: any) => {
|
const handleSave = (row?: any, type?: any) => {
|
||||||
try {
|
try {
|
||||||
if (!row.unitPrice) {
|
if (type == 'single') {
|
||||||
ElMessage({
|
|
||||||
message: '请输入单价',
|
|
||||||
type: 'warning'
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
updatePrice({ ...row, type: '1' }).then((res) => {
|
const list = [{ ...row, type: '1' }];
|
||||||
|
updatePrice(list).then((res) => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: '修改成功',
|
message: '修改成功',
|
||||||
@ -240,11 +246,30 @@ const handleSave = (row: any) => {
|
|||||||
getTableData();
|
getTableData();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
if (type == 'all') {
|
||||||
|
loading.value = true;
|
||||||
|
const list = [];
|
||||||
|
modifyPrice.forEach((item) => {
|
||||||
|
list.push({ ...item, type: '1' });
|
||||||
|
});
|
||||||
|
updatePrice(list).then((res) => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
ElMessage({
|
||||||
|
message: '修改成功',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
getTableData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: '修改失败',
|
message: '修改失败',
|
||||||
type: 'error'
|
type: 'error'
|
||||||
});
|
});
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const tableRef = ref<any>();
|
const tableRef = ref<any>();
|
||||||
|
@ -38,7 +38,14 @@
|
|||||||
<el-table-column label="操作" align="center">
|
<el-table-column label="操作" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['design:extract:query']">审核</el-button>
|
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['design:extract:query']">审核</el-button>
|
||||||
<el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-hasPermi="['design:extract:export']">导出</el-button
|
<el-button
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
v-if="scope.row.status != 'finish'"
|
||||||
|
icon="Download"
|
||||||
|
@click="handleDownload(scope.row)"
|
||||||
|
v-hasPermi="['design:extract:export']"
|
||||||
|
>导出</el-button
|
||||||
><el-button
|
><el-button
|
||||||
link
|
link
|
||||||
type="warning"
|
type="warning"
|
||||||
@ -65,15 +72,17 @@
|
|||||||
<el-table :loading="loadingFlie" :data="fileList" style="width: 100%" border>
|
<el-table :loading="loadingFlie" :data="fileList" style="width: 100%" border>
|
||||||
<el-table-column prop="fileName" label="文件名称" align="center">
|
<el-table-column prop="fileName" label="文件名称" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-link
|
<!-- <el-link
|
||||||
:key="scope.row.fileId"
|
:key="scope.row.fileId"
|
||||||
:href="scope.row.fileUrl"
|
:href="scope.row.fileUrl"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
:type="scope.row.status == '1' ? 'primary' : 'info'"
|
:type="scope.row.status == '1' ? 'primary' : 'info'"
|
||||||
:underline="false"
|
:underline="false"
|
||||||
|
disabled
|
||||||
>
|
>
|
||||||
{{ scope.row.fileName }}
|
{{ scope.row.fileName }}
|
||||||
</el-link>
|
</el-link> -->
|
||||||
|
<span>{{ scope.row.fileName }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="版本号" align="center" width="120" prop="version"> </el-table-column>
|
<el-table-column label="版本号" align="center" width="120" prop="version"> </el-table-column>
|
||||||
|
@ -445,7 +445,9 @@ const getMajor = async () => {
|
|||||||
let res = await extractUserMajor({ userId: userId.value, projectId: currentProject.value?.id });
|
let res = await extractUserMajor({ userId: userId.value, projectId: currentProject.value?.id });
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
des_user_major.value = res.data;
|
des_user_major.value = res.data;
|
||||||
console.log(des_user_major.value);
|
if (res.data.length > 0) {
|
||||||
|
form.user_major = res.data[0].userMajor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/** 回显表单数据(编辑/查看/审批场景) */
|
/** 回显表单数据(编辑/查看/审批场景) */
|
||||||
|
804
src/views/design/appointment/index copy 2.vue
Normal file
804
src/views/design/appointment/index copy 2.vue
Normal file
@ -0,0 +1,804 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-6 bg-gray-50">
|
||||||
|
<div class="appointment mx-auto bg-white rounded-xl shadow-sm overflow-hidden transition-all duration-300 hover:shadow-md">
|
||||||
|
<!-- 表单标题区域 -->
|
||||||
|
<div class="bg-gradient-to-r from-blue-500 to-blue-600 text-white p-6">
|
||||||
|
<h2 class="text-2xl font-bold flex items-center"><i class="el-icon-user-circle mr-3"></i>人员配置</h2>
|
||||||
|
<p class="text-blue-100 mt-2 opacity-90">请配置项目相关负责人员信息</p>
|
||||||
|
<el-button @click="disabledForm = false" class="px-8 py-2.5 transition-all duration-300 font-medium" v-if="disabledForm">
|
||||||
|
点击编辑
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<!-- 表单内容区域 -->
|
||||||
|
<el-form ref="leaveFormRef" :model="form" :disabled="disabledForm" :rules="rules" label-width="120px" class="p-6 space-y-6">
|
||||||
|
<!-- 设计负责人 -->
|
||||||
|
<div class="fonts">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="8"
|
||||||
|
><el-form-item label="设计负责人" prop="designLeader" class="mb-4">
|
||||||
|
<el-select
|
||||||
|
v-model="form.designLeader"
|
||||||
|
placeholder="请选择设计负责人"
|
||||||
|
class="w-full transition-all duration-300 border-gray-300 focus:border-blue-400 focus:ring-1 focus:ring-blue-400"
|
||||||
|
>
|
||||||
|
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 专业人员配置:专业 + 设计人员 + 校审人员 横向排列 -->
|
||||||
|
<div class="border border-gray-200 rounded-lg p-5 transition-all duration-300 hover:shadow-md bg-gray-50">
|
||||||
|
<div class="flex justify-between items-center mb-5">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-700 flex items-center"><i class="el-icon-users mr-2 text-blue-500"></i>专业人员配置</h3>
|
||||||
|
<div class="flex gap-3">
|
||||||
|
<!-- 新增专业按钮 -->
|
||||||
|
<el-button type="primary" size="small" :disabled="disabledForm" @click="addMajor">
|
||||||
|
<i class="el-icon-plus mr-1"></i>新增专业
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表头 -->
|
||||||
|
<el-row :gutter="20" class="mb-3 font-medium text-gray-700">
|
||||||
|
<el-col :span="6" :xs="24" :sm="8">专业</el-col>
|
||||||
|
<el-col :span="9" :xs="24" :sm="8">设计人员(可多选)</el-col>
|
||||||
|
<el-col :span="9" :xs="24" :sm="8">校审人员(可多选)</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 分割线 -->
|
||||||
|
<el-divider class="my-4" />
|
||||||
|
|
||||||
|
<!-- 专业配置行:专业(左)+ 设计人员(中)+ 校审人员(右) 横向排列 -->
|
||||||
|
<div
|
||||||
|
v-for="(majorConfig, configIndex) in combinedConfigs"
|
||||||
|
:key="configIndex"
|
||||||
|
style="background: aliceblue; border-radius: 10px"
|
||||||
|
class="mb-5 animate-fadeIn"
|
||||||
|
>
|
||||||
|
<el-row :gutter="20" class="items-top">
|
||||||
|
<!-- 左侧:专业选择 -->
|
||||||
|
<el-col :span="6" :xs="24" :sm="8" class="mb-4 sm:mb-0" style="margin-top: 8px">
|
||||||
|
<el-form-item
|
||||||
|
:prop="`designers.${configIndex}.userMajor`"
|
||||||
|
:rules="{ required: true, message: '请选择专业', trigger: 'change' }"
|
||||||
|
class="mb-0"
|
||||||
|
label-width="80px"
|
||||||
|
label="专业"
|
||||||
|
>
|
||||||
|
<!-- 专业选择下拉框 -->
|
||||||
|
<el-select
|
||||||
|
v-model="form.designers[configIndex].userMajor"
|
||||||
|
placeholder="请选择专业"
|
||||||
|
class="w-full transition-all duration-300 border-gray-300"
|
||||||
|
@change="(val) => handleMajorChange(val, configIndex)"
|
||||||
|
>
|
||||||
|
<!-- 临时添加调试显示 -->
|
||||||
|
<template v-if="des_user_major && des_user_major.length > 0">
|
||||||
|
<el-option v-for="item in des_user_major" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-option label="无专业数据" value="" disabled />
|
||||||
|
</template>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<!-- 中间:设计人员 -->
|
||||||
|
<el-col :span="9" :xs="24" :sm="8" class="mb-4 sm:mb-0">
|
||||||
|
<div class="pl-0 sm:pl-4 border-l-0 sm:border-l-2 border-blue-200 py-0 sm:py-2">
|
||||||
|
<!-- 设计人员列表 -->
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div v-for="(person, personIndex) in majorConfig.designPersons" :key="personIndex" class="flex items-center">
|
||||||
|
<el-form-item
|
||||||
|
:prop="`designers.${configIndex}.persons.${personIndex}.userId`"
|
||||||
|
:rules="{ required: true, message: '请选择人员', trigger: 'change' }"
|
||||||
|
class="flex-1 mr-3 mb-0"
|
||||||
|
label="设计人员"
|
||||||
|
label-width="80px"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="person.userId"
|
||||||
|
placeholder="请选择设计人员"
|
||||||
|
class="w-full transition-all duration-300 border-gray-300"
|
||||||
|
@change="() => checkDuplicate(person, 'designers', configIndex, personIndex)"
|
||||||
|
>
|
||||||
|
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<div>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
size="small"
|
||||||
|
@click="removePerson('designers', configIndex, personIndex)"
|
||||||
|
class="transition-all duration-300 hover:bg-red-600"
|
||||||
|
:disabled="majorConfig.designPersons.length <= 1 || disabledForm"
|
||||||
|
>
|
||||||
|
<el-icon :size="16">
|
||||||
|
<Delete />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
size="small"
|
||||||
|
@click="addPerson('designers', configIndex)"
|
||||||
|
class="transition-all duration-300 transform hover:scale-105"
|
||||||
|
:disabled="!majorConfig.userMajor || disabledForm"
|
||||||
|
>
|
||||||
|
<el-icon :size="16">
|
||||||
|
<Plus />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 空状态提示 -->
|
||||||
|
<div
|
||||||
|
v-if="majorConfig.designPersons.length == 0"
|
||||||
|
class="text-gray-500 text-sm py-2 bg-gray-100 rounded-lg border border-dashed border-gray-200 mt-1"
|
||||||
|
>
|
||||||
|
暂无设计人员,请点击"添加设计人员"
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<!-- 右侧:校审人员 -->
|
||||||
|
<el-col :span="9" :xs="24" :sm="8">
|
||||||
|
<div class="pl-0 sm:pl-4 border-l-0 sm:border-l-2 border-green-200 py-0 sm:py-2">
|
||||||
|
<!-- 校审人员列表 -->
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div v-for="(person, personIndex) in majorConfig.reviewPersons" :key="personIndex" class="flex items-center">
|
||||||
|
<el-form-item
|
||||||
|
:prop="`reviewers.${configIndex}.persons.${personIndex}.userId`"
|
||||||
|
:rules="{ required: true, message: '请选择人员', trigger: 'change' }"
|
||||||
|
class="flex-1 mr-3 mb-0"
|
||||||
|
label="校审人员"
|
||||||
|
label-width="80px"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="person.userId"
|
||||||
|
placeholder="请选择校审人员"
|
||||||
|
class="w-full transition-all duration-300 border-gray-300"
|
||||||
|
@change="() => checkDuplicate(person, 'reviewers', configIndex, personIndex)"
|
||||||
|
>
|
||||||
|
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<div>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
size="small"
|
||||||
|
@click="removePerson('reviewers', configIndex, personIndex)"
|
||||||
|
class="transition-all duration-300 hover:bg-red-600"
|
||||||
|
:disabled="majorConfig.reviewPersons.length <= 1 || disabledForm"
|
||||||
|
>
|
||||||
|
<el-icon :size="16">
|
||||||
|
<Delete />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
size="small"
|
||||||
|
@click="addPerson('reviewers', configIndex)"
|
||||||
|
class="transition-all duration-300 transform hover:scale-105"
|
||||||
|
:disabled="!majorConfig.userMajor || disabledForm"
|
||||||
|
>
|
||||||
|
<el-icon :size="16">
|
||||||
|
<Plus />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 空状态提示 -->
|
||||||
|
<div
|
||||||
|
v-if="majorConfig.reviewPersons.length == 0"
|
||||||
|
class="text-gray-500 text-sm py-2 bg-gray-100 rounded-lg border border-dashed border-gray-200 mt-1"
|
||||||
|
>
|
||||||
|
暂无校审人员,请点击"添加校审人员"
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<!-- 删除专业配置行 -->
|
||||||
|
<el-row class="mt-2">
|
||||||
|
<el-col :span="24" class="text-right pr-4">
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
class="text-red-500 hover:text-red-700 transition-colors"
|
||||||
|
@click="removeMajor(configIndex)"
|
||||||
|
:disabled="combinedConfigs.length <= 1 || disabledForm"
|
||||||
|
>
|
||||||
|
<i class="el-icon-delete mr-1"></i>删除专业
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 提交按钮区域 -->
|
||||||
|
<div class="flex justify-center space-x-6 mt-8 pt-6 border-t border-gray-100">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
v-hasPermi="['design:user:batch']"
|
||||||
|
@click="submitForm"
|
||||||
|
class="px-8 py-2.5 transition-all duration-300 transform hover:scale-105 bg-blue-500 hover:bg-blue-600 text-white font-medium"
|
||||||
|
:disabled="disabledForm"
|
||||||
|
>
|
||||||
|
<i class="el-icon-check mr-2"></i>确认提交
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="large"
|
||||||
|
@click="resetForm"
|
||||||
|
class="px-8 py-2.5 transition-all duration-300 border-gray-300 hover:bg-gray-100 font-medium"
|
||||||
|
:disabled="disabledForm"
|
||||||
|
>
|
||||||
|
<i class="el-icon-refresh mr-2"></i>重置
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="PersonnelForm" lang="ts">
|
||||||
|
import { ref, reactive, computed, onMounted, toRefs, watch, WatchStopHandle } from 'vue';
|
||||||
|
import { getCurrentInstance } from 'vue';
|
||||||
|
import type { ComponentInternalInstance } from 'vue';
|
||||||
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
import { ElMessage, ElLoading } from 'element-plus';
|
||||||
|
import { Delete, Plus } from '@element-plus/icons-vue'; // 修复:添加Plus图标导入
|
||||||
|
import { designUserAdd, designUserList, systemUserList } from '@/api/design/appointment';
|
||||||
|
|
||||||
|
// 获取当前实例
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
// 获取用户 store
|
||||||
|
const userStore = useUserStoreHook();
|
||||||
|
// 从 store 中获取当前选中的项目
|
||||||
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
// 专业字典数据 - 增加默认空数组避免undefined
|
||||||
|
const { des_user_major = ref([]) } = toRefs<any>(proxy?.useDict('des_user_major') || {});
|
||||||
|
|
||||||
|
// 调试:打印专业数据
|
||||||
|
onMounted(() => {
|
||||||
|
console.log('专业数据:', des_user_major.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 表单数据:保持原有数据结构不变
|
||||||
|
interface MajorGroup {
|
||||||
|
userMajor: string | null; // 专业
|
||||||
|
persons: Array<{ userId: number | null }>; // 该专业下的多个人员
|
||||||
|
}
|
||||||
|
const form = reactive({
|
||||||
|
projectId: currentProject.value?.id,
|
||||||
|
designLeader: null, // 设计负责人
|
||||||
|
designers: [] as MajorGroup[], // 设计人员:按专业分组,每组含多个人员
|
||||||
|
reviewers: [] as MajorGroup[] // 校审人员:按专业分组,每组含多个人员
|
||||||
|
});
|
||||||
|
|
||||||
|
// 组合配置用于视图展示(专业+设计人员+校审人员)
|
||||||
|
const combinedConfigs = computed(() => {
|
||||||
|
// 确保designers和reviewers数组长度一致
|
||||||
|
const maxLength = Math.max(form.designers.length, form.reviewers.length);
|
||||||
|
while (form.designers.length < maxLength) {
|
||||||
|
form.designers.push(createEmptyMajorGroup());
|
||||||
|
}
|
||||||
|
while (form.reviewers.length < maxLength) {
|
||||||
|
form.reviewers.push(createEmptyMajorGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组合数据用于视图展示
|
||||||
|
return form.designers.map((designerGroup, index) => ({
|
||||||
|
userMajor: designerGroup.userMajor,
|
||||||
|
designPersons: designerGroup.persons,
|
||||||
|
reviewPersons: form.reviewers[index].persons
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const rules = reactive({
|
||||||
|
designLeader: [{ required: true, message: '请选择设计负责人', trigger: 'change' }]
|
||||||
|
});
|
||||||
|
|
||||||
|
// 用户列表
|
||||||
|
const userList = ref([]);
|
||||||
|
|
||||||
|
// 表单引用
|
||||||
|
const leaveFormRef = ref();
|
||||||
|
const disabledForm = ref(false); //控制提交按钮状态
|
||||||
|
|
||||||
|
/** 查询当前部门的所有用户 */
|
||||||
|
const getDeptAllUser = async (deptId: any) => {
|
||||||
|
try {
|
||||||
|
const res = await systemUserList({ deptId });
|
||||||
|
userList.value = res.rows;
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('获取用户列表失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 查询当前表单数据并回显 */
|
||||||
|
const designUser = async () => {
|
||||||
|
if (!currentProject.value?.id) return;
|
||||||
|
|
||||||
|
const loading = ElLoading.service({
|
||||||
|
lock: true,
|
||||||
|
text: '加载配置数据中...',
|
||||||
|
background: 'rgba(255, 255, 255, 0.7)'
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
const res = await designUserList({ projectId: currentProject.value?.id });
|
||||||
|
// 清空现有数据
|
||||||
|
form.designLeader = null;
|
||||||
|
form.designers = [];
|
||||||
|
form.reviewers = [];
|
||||||
|
|
||||||
|
if (res.code == 200 && res.rows && res.rows.length > 0) {
|
||||||
|
disabledForm.value = true;
|
||||||
|
// 1. 分类整理数据(按用户类型)
|
||||||
|
const designLeader = res.rows.find((item) => item.userType == 1);
|
||||||
|
const designerItems = res.rows.filter((item) => item.userType == 2);
|
||||||
|
const reviewerItems = res.rows.filter((item) => item.userType == 3);
|
||||||
|
|
||||||
|
// 2. 回显设计负责人
|
||||||
|
if (designLeader) form.designLeader = designLeader.userId;
|
||||||
|
|
||||||
|
// 3. 回显设计人员(按专业分组)
|
||||||
|
form.designers = groupPersonByMajor(designerItems);
|
||||||
|
// 4. 回显校审人员(按专业分组)
|
||||||
|
form.reviewers = groupPersonByMajor(reviewerItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 补全默认空项(至少1个专业分组,每组至少1个人员)
|
||||||
|
if (form.designers.length == 0) form.designers.push(createEmptyMajorGroup());
|
||||||
|
if (form.reviewers.length == 0) form.reviewers.push(createEmptyMajorGroup());
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('获取配置数据失败');
|
||||||
|
// 异常时初始化默认空项
|
||||||
|
form.designers = [createEmptyMajorGroup()];
|
||||||
|
form.reviewers = [createEmptyMajorGroup()];
|
||||||
|
} finally {
|
||||||
|
loading.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 辅助函数:创建空的专业分组(含1个空人员) */
|
||||||
|
const createEmptyMajorGroup = (): MajorGroup => ({
|
||||||
|
userMajor: null,
|
||||||
|
persons: [{ userId: null }]
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 辅助函数:按专业分组整理人员数据(用于回显) */
|
||||||
|
const groupPersonByMajor = (items: any[]): MajorGroup[] => {
|
||||||
|
const groupMap: Record<string, MajorGroup> = {};
|
||||||
|
items.forEach((item) => {
|
||||||
|
const major = item.userMajor || '未分类';
|
||||||
|
// 不存在该专业分组则创建
|
||||||
|
if (!groupMap[major]) {
|
||||||
|
groupMap[major] = { userMajor: item.userMajor, persons: [] };
|
||||||
|
}
|
||||||
|
// 添加当前人员到专业分组
|
||||||
|
groupMap[major].persons.push({ userId: item.userId });
|
||||||
|
});
|
||||||
|
// 处理空分组(确保每组至少1个人员)
|
||||||
|
Object.values(groupMap).forEach((group) => {
|
||||||
|
if (group.persons.length == 0) group.persons.push({ userId: null });
|
||||||
|
});
|
||||||
|
return Object.values(groupMap);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 新增专业配置行 */
|
||||||
|
const addMajor = () => {
|
||||||
|
form.designers.push(createEmptyMajorGroup());
|
||||||
|
form.reviewers.push(createEmptyMajorGroup());
|
||||||
|
|
||||||
|
// 滚动到新增的专业配置行
|
||||||
|
setTimeout(() => {
|
||||||
|
const groups = document.querySelectorAll(`[data-v-${proxy?.$options.__scopeId}] .animate-fadeIn`);
|
||||||
|
if (groups.length > 0) {
|
||||||
|
groups[groups.length - 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 删除专业配置行 */
|
||||||
|
const removeMajor = (configIndex: number) => {
|
||||||
|
if (form.designers.length <= 1) {
|
||||||
|
ElMessage.warning('至少保留一个专业配置');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
form.designers.splice(configIndex, 1);
|
||||||
|
form.reviewers.splice(configIndex, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 给指定专业配置行添加人员 */
|
||||||
|
const addPerson = (type: 'designers' | 'reviewers', configIndex: number) => {
|
||||||
|
form[type][configIndex].persons.push({ userId: null });
|
||||||
|
|
||||||
|
// 滚动到新增的人员选择框
|
||||||
|
setTimeout(() => {
|
||||||
|
const personSelects = document.querySelectorAll(`[data-v-${proxy?.$options.__scopeId}] .el-select`);
|
||||||
|
if (personSelects.length > 0) {
|
||||||
|
personSelects[personSelects.length - 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 从指定专业配置行删除人员 */
|
||||||
|
const removePerson = (type: 'designers' | 'reviewers', configIndex: number, personIndex: number) => {
|
||||||
|
const targetGroup = form[type][configIndex];
|
||||||
|
if (targetGroup.persons.length <= 1) {
|
||||||
|
ElMessage.warning(`该专业至少保留一个${type == 'designers' ? '设计' : '校审'}人员`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
targetGroup.persons.splice(personIndex, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 专业变更时:清空当前专业下的人员(避免专业与人员不匹配) */
|
||||||
|
const handleMajorChange = (newMajor: string, configIndex: number) => {
|
||||||
|
// 直接修改原始数据源,确保响应式生效
|
||||||
|
form.designers[configIndex].userMajor = newMajor;
|
||||||
|
form.reviewers[configIndex].userMajor = newMajor;
|
||||||
|
form.designers[configIndex].persons = [{ userId: null }];
|
||||||
|
form.reviewers[configIndex].persons = [{ userId: null }];
|
||||||
|
// ElMessage.info(`已重置「${getMajorLabel(newMajor)}」专业下的人员,请重新选择`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========== 核心:重复校验逻辑 ==========
|
||||||
|
/**
|
||||||
|
* 校验同一角色内(设计/校审)的「专业+人员」组合唯一性
|
||||||
|
*/
|
||||||
|
const checkDuplicate = (current: { userId: number | null }, role: 'designers' | 'reviewers', configIndex: number, personIndex: number) => {
|
||||||
|
console.log(`校验触发 - 角色: ${role}, 专业索引: ${configIndex}, 人员索引: ${personIndex}, 人员ID: ${current.userId}`);
|
||||||
|
console.log(form);
|
||||||
|
|
||||||
|
const currentGroup = form[role][configIndex];
|
||||||
|
// 未选专业/人员时不校验
|
||||||
|
if (!currentGroup.userMajor || !current.userId) return;
|
||||||
|
|
||||||
|
// 生成当前「专业+人员」唯一标识
|
||||||
|
const currentKey = `${currentGroup.userMajor}-${current.userId}`;
|
||||||
|
let duplicateItem = null;
|
||||||
|
|
||||||
|
// 1. 检查当前专业配置行内是否有重复人员
|
||||||
|
duplicateItem = currentGroup.persons.find((item, idx) => {
|
||||||
|
return idx !== personIndex && item.userId == current.userId;
|
||||||
|
});
|
||||||
|
if (duplicateItem) {
|
||||||
|
ElMessage.warning(`当前专业下「${getUserName(current.userId)}」已存在,请重新选择`);
|
||||||
|
current.userId = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 检查同一角色内其他专业配置行是否有重复(专业+人员唯一)
|
||||||
|
form[role].forEach((group, gIdx) => {
|
||||||
|
if (gIdx == configIndex) return; // 跳过当前配置行
|
||||||
|
group.persons.forEach((item) => {
|
||||||
|
if (`${group.userMajor}-${item.userId}` == currentKey) {
|
||||||
|
duplicateItem = item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (duplicateItem) {
|
||||||
|
ElMessage.warning(`「${getMajorLabel(currentGroup.userMajor)}+${getUserName(current.userId)}」组合已存在,请重新选择`);
|
||||||
|
current.userId = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 辅助函数:通过专业值获取专业名称 */
|
||||||
|
const getMajorLabel = (majorValue: string | null) => {
|
||||||
|
if (!majorValue || !des_user_major.value) return '';
|
||||||
|
const major = des_user_major.value.find((item: any) => item.value == majorValue);
|
||||||
|
return major ? major.label : majorValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 辅助函数:通过用户ID获取用户名 */
|
||||||
|
const getUserName = (userId: number | null) => {
|
||||||
|
if (!userId || !userList.value.length) return '';
|
||||||
|
const user = userList.value.find((item: any) => item.userId == userId);
|
||||||
|
return user ? user.nickName : userId;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 提交表单(保持原有数据结构) */
|
||||||
|
const submitForm = async () => {
|
||||||
|
if (!leaveFormRef.value) return;
|
||||||
|
try {
|
||||||
|
// 1. 基础表单验证
|
||||||
|
await leaveFormRef.value.validate();
|
||||||
|
// 2. 提交前二次校验:「专业+人员」组合唯一性
|
||||||
|
let hasDuplicate = false;
|
||||||
|
const allKeys: string[] = [];
|
||||||
|
|
||||||
|
// 收集所有「专业+人员」组合(设计+校审分开校验)
|
||||||
|
const collectKeys = (roleGroups: MajorGroup[], roleName: string) => {
|
||||||
|
roleGroups.forEach((group) => {
|
||||||
|
if (!group.userMajor) return;
|
||||||
|
group.persons.forEach((person) => {
|
||||||
|
if (!person.userId) return;
|
||||||
|
const key = `${group.userMajor}-${person.userId}`;
|
||||||
|
if (allKeys.includes(key)) {
|
||||||
|
hasDuplicate = true;
|
||||||
|
ElMessage.error(`${roleName}中存在重复的「专业+人员」组合,请检查`);
|
||||||
|
}
|
||||||
|
allKeys.push(key);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 校验设计人员
|
||||||
|
collectKeys(form.designers, '设计人员');
|
||||||
|
if (hasDuplicate) return;
|
||||||
|
|
||||||
|
// 清空临时数组,校验校审人员(不校验设计与校审之间)
|
||||||
|
allKeys.length = 0;
|
||||||
|
collectKeys(form.reviewers, '校审人员');
|
||||||
|
if (hasDuplicate) return;
|
||||||
|
|
||||||
|
// 3. 构建提交数据(适配后端原有数据格式)
|
||||||
|
const submitData = {
|
||||||
|
projectId: form.projectId,
|
||||||
|
personnel: [
|
||||||
|
// 设计负责人
|
||||||
|
{
|
||||||
|
userId: form.designLeader,
|
||||||
|
userType: 'designLeader',
|
||||||
|
userMajor: null
|
||||||
|
},
|
||||||
|
// 设计人员:展开专业分组,每个人员单独作为一条数据
|
||||||
|
...form.designers.flatMap((group) =>
|
||||||
|
group.persons.map((person) => ({
|
||||||
|
userId: person.userId,
|
||||||
|
userType: 'designer',
|
||||||
|
userMajor: group.userMajor
|
||||||
|
}))
|
||||||
|
),
|
||||||
|
// 校审人员:展开专业分组,每个人员单独作为一条数据
|
||||||
|
...form.reviewers.flatMap((group) =>
|
||||||
|
group.persons.map((person) => ({
|
||||||
|
userId: person.userId,
|
||||||
|
userType: 'reviewer',
|
||||||
|
userMajor: group.userMajor
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
// 4. 数据处理(保持原有逻辑不变)
|
||||||
|
const arr = [];
|
||||||
|
userList.value.forEach((item) => {
|
||||||
|
submitData.personnel.forEach((item1) => {
|
||||||
|
if (item1.userId == item.userId) {
|
||||||
|
let userType = 1;
|
||||||
|
if (item1.userType == 'designer') userType = 2;
|
||||||
|
else if (item1.userType == 'reviewer') userType = 3;
|
||||||
|
arr.push({
|
||||||
|
userName: item.nickName,
|
||||||
|
projectId: submitData.projectId,
|
||||||
|
userId: item1.userId,
|
||||||
|
userType: userType,
|
||||||
|
userMajor: item1.userMajor
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 5. 提交到后端(保持原有逻辑不变)
|
||||||
|
const loading = ElLoading.service({ text: '提交中...', background: 'rgba(255,255,255,0.7)' });
|
||||||
|
const res = await designUserAdd({
|
||||||
|
list: arr,
|
||||||
|
projectId: currentProject.value?.id
|
||||||
|
});
|
||||||
|
if (res.code == 200) {
|
||||||
|
disabledForm.value = true;
|
||||||
|
loading.close();
|
||||||
|
ElMessage.success('提交成功');
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg || '提交失败');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('请完善表单信息后再提交');
|
||||||
|
} finally {
|
||||||
|
// ElLoading.service().close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 重置表单(适配新数据结构) */
|
||||||
|
const resetForm = () => {
|
||||||
|
if (leaveFormRef.value) {
|
||||||
|
leaveFormRef.value.resetFields();
|
||||||
|
// 重置为默认空状态(1个专业分组,每组1个空人员)
|
||||||
|
form.designers = [createEmptyMajorGroup()];
|
||||||
|
form.reviewers = [createEmptyMajorGroup()];
|
||||||
|
ElMessage.info('表单已重置');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听项目ID刷新数据
|
||||||
|
const listeningProject: WatchStopHandle = watch(
|
||||||
|
() => currentProject.value?.id,
|
||||||
|
() => {
|
||||||
|
getDeptAllUser(userStore.deptId).then(() => {
|
||||||
|
designUser();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 页面生命周期
|
||||||
|
onUnmounted(() => {
|
||||||
|
listeningProject();
|
||||||
|
});
|
||||||
|
onMounted(() => {
|
||||||
|
getDeptAllUser(userStore.deptId).then(() => {
|
||||||
|
designUser();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.appointment {
|
||||||
|
width: 70vw;
|
||||||
|
max-width: 1600px;
|
||||||
|
|
||||||
|
.el-select__wrapper {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button--small {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fonts {
|
||||||
|
.el-form-item--default .el-form-item__label {
|
||||||
|
font-size: 18px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自定义动画
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(10px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fadeIn {
|
||||||
|
animation: fadeIn 0.3s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表单样式优化
|
||||||
|
::v-deep .el-form {
|
||||||
|
--el-form-item-margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-form-item {
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #4e5969;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-select {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.el-input__inner {
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .el-input__inner {
|
||||||
|
border-color: #66b1ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.el-select-focus .el-input__inner {
|
||||||
|
border-color: #409eff;
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-button {
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
|
||||||
|
&--primary {
|
||||||
|
background-color: #409eff;
|
||||||
|
border-color: #409eff;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #66b1ff;
|
||||||
|
border-color: #66b1ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--success {
|
||||||
|
background-color: #67c23a;
|
||||||
|
border-color: #67c23a;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #85ce61;
|
||||||
|
border-color: #85ce61;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background-color: #b3e099;
|
||||||
|
border-color: #b3e099;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--danger {
|
||||||
|
background-color: #f56c6c;
|
||||||
|
border-color: #f56c6c;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #f78989;
|
||||||
|
border-color: #f78989;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background-color: #ffcccc;
|
||||||
|
border-color: #ffbbbb;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--text {
|
||||||
|
color: #f56c6c;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #f78989;
|
||||||
|
background-color: rgba(245, 108, 108, 0.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应式网格布局
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-cols-1 {
|
||||||
|
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.md\:grid-cols-2 {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-4 {
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 适配小屏幕(小于768px时,垂直排列)
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.appWidth {
|
||||||
|
width: 95vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-form {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-form-item__label {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 小屏幕下各列上下间距
|
||||||
|
::v-deep .el-col-xs-24 + .el-col-xs-24 {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
File diff suppressed because it is too large
Load Diff
@ -44,7 +44,7 @@
|
|||||||
<el-table-column label="卷册号" align="center" prop="volumeNo" width="150" />
|
<el-table-column label="卷册号" align="center" prop="volumeNo" width="150" />
|
||||||
<el-table-column label="流程状态" align="center">
|
<el-table-column label="流程状态" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<dict-tag v-if="scope.row.fileId != null" :options="wf_business_status" :value="scope.row.status" />
|
<dict-tag v-if="scope.row.costEstimation > 0" :options="wf_business_status" :value="scope.row.status" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="变更文件" align="center" width="150">
|
<el-table-column label="变更文件" align="center" width="150">
|
||||||
@ -64,19 +64,16 @@
|
|||||||
<dict-tag :options="design_change_reason_type" :value="scope.row.changeReason ? scope.row.changeReason.split(',') : []" />
|
<dict-tag :options="design_change_reason_type" :value="scope.row.changeReason ? scope.row.changeReason.split(',') : []" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column label="图纸状态" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag v-if="scope.row.fileId != null" :options="wf_business_status" :value="scope.row.auditStatus" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="变更内容" align="center" prop="changeContent" width="150" />
|
<el-table-column label="变更内容" align="center" prop="changeContent" width="150" />
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="150" />
|
<el-table-column label="创建时间" align="center" prop="createTime" width="150" />
|
||||||
<el-table-column label="备注" align="center" prop="remark" width="200" />
|
<el-table-column label="备注" align="center" prop="remark" width="200" />
|
||||||
<el-table-column label="操作" align="center" fixed="right" width="300">
|
<el-table-column label="操作" align="center" fixed="right" width="300">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
link
|
|
||||||
icon="Upload"
|
|
||||||
@click="handleAddChange(scope.row)"
|
|
||||||
v-if="(scope.row.status == 'finish' || scope.row.costEstimation == '0') && scope.row.auditStatus == 'draft'"
|
|
||||||
>上传</el-button
|
|
||||||
>
|
|
||||||
<el-button
|
<el-button
|
||||||
type="success"
|
type="success"
|
||||||
link
|
link
|
||||||
@ -86,8 +83,31 @@
|
|||||||
@click="handleViewInfo(scope.row)"
|
@click="handleViewInfo(scope.row)"
|
||||||
>查看</el-button
|
>查看</el-button
|
||||||
>
|
>
|
||||||
<el-button type="success" link icon="View" v-hasPermi="['design:designChange:query']" @click="handleViewDetail(scope.row)"
|
<el-button
|
||||||
>通知单</el-button
|
type="primary"
|
||||||
|
v-if="scope.row.status == 'draft' && scope.row.costEstimation > 0"
|
||||||
|
link
|
||||||
|
icon="plus"
|
||||||
|
v-hasPermi="['design:designChange:query']"
|
||||||
|
@click="handleViewUpdate(scope.row)"
|
||||||
|
>审核通知单</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
v-if="scope.row.status != 'draft'"
|
||||||
|
type="success"
|
||||||
|
link
|
||||||
|
icon="View"
|
||||||
|
v-hasPermi="['design:designChange:query']"
|
||||||
|
@click="handleViewDetail(scope.row)"
|
||||||
|
>查看通知单</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
link
|
||||||
|
icon="Upload"
|
||||||
|
@click="handleAddChange(scope.row)"
|
||||||
|
v-if="(scope.row.status == 'finish' || scope.row.costEstimation == '0') && scope.row.auditStatus == 'draft'"
|
||||||
|
>上传图纸</el-button
|
||||||
>
|
>
|
||||||
<el-button
|
<el-button
|
||||||
type="warning"
|
type="warning"
|
||||||
@ -210,6 +230,17 @@ const handleAdd = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
/** 查看详情 */
|
/** 查看详情 */
|
||||||
|
const handleViewUpdate = (row) => {
|
||||||
|
proxy.$tab.closePage(proxy.$route);
|
||||||
|
proxy.$router.push({
|
||||||
|
path: `/approval/designChange/indexEdit`,
|
||||||
|
query: {
|
||||||
|
id: row.id,
|
||||||
|
type: 'update'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/** 查看详情 */
|
||||||
const handleViewDetail = (row) => {
|
const handleViewDetail = (row) => {
|
||||||
proxy.$tab.closePage(proxy.$route);
|
proxy.$tab.closePage(proxy.$route);
|
||||||
proxy.$router.push({
|
proxy.$router.push({
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="工程名称" prop="projectName">
|
<el-form-item label="工程名称" prop="projectName">
|
||||||
<el-input v-model="form.projectName" placeholder="请输入工程名称" /> </el-form-item
|
<el-input v-model="form.projectName" disabled placeholder="请输入工程名称" /> </el-form-item
|
||||||
></el-col>
|
></el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="原卷册号" prop="volumeNo">
|
<el-form-item label="原卷册号" prop="volumeNo">
|
||||||
@ -145,7 +145,7 @@
|
|||||||
></el-col>
|
></el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="费用" prop="costEstimation">
|
<el-form-item label="费用" prop="costEstimation">
|
||||||
<el-input v-model="form.costEstimation" type="number" placeholder="请输入费用" /> </el-form-item
|
<el-input min="0" v-model="form.costEstimation" type="number" placeholder="请输入费用" /> </el-form-item
|
||||||
></el-col>
|
></el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="变更费用估算表" label-width="110px" prop="costEstimationFile">
|
<el-form-item label="变更费用估算表" label-width="110px" prop="costEstimationFile">
|
||||||
@ -254,7 +254,7 @@ const initFormData = {
|
|||||||
id: undefined,
|
id: undefined,
|
||||||
projectId: currentProject.value?.id,
|
projectId: currentProject.value?.id,
|
||||||
formNo: undefined,
|
formNo: undefined,
|
||||||
projectName: undefined,
|
projectName: currentProject.value?.name,
|
||||||
submitUnit: undefined,
|
submitUnit: undefined,
|
||||||
specialty: undefined,
|
specialty: undefined,
|
||||||
specialtyName: undefined,
|
specialtyName: undefined,
|
||||||
@ -348,8 +348,11 @@ const getInfo = () => {
|
|||||||
loading.value = true;
|
loading.value = true;
|
||||||
buttonLoading.value = false;
|
buttonLoading.value = false;
|
||||||
nextTick(async () => {
|
nextTick(async () => {
|
||||||
const res = await getDesignChange(routeParams.value.id);
|
let id = routeParams.value.id.split('_')[0];
|
||||||
|
const res = await getDesignChange(id);
|
||||||
Object.assign(form.value, res.data);
|
Object.assign(form.value, res.data);
|
||||||
|
console.log(form.value);
|
||||||
|
|
||||||
if (form.value.changeReason.length > 0) {
|
if (form.value.changeReason.length > 0) {
|
||||||
form.value.changeReason = form.value.changeReason.split(',');
|
form.value.changeReason = form.value.changeReason.split(',');
|
||||||
}
|
}
|
||||||
@ -374,7 +377,6 @@ const submitForm = (status1: string) => {
|
|||||||
if (form.value.saveFile && form.value.saveFile.length > 0) {
|
if (form.value.saveFile && form.value.saveFile.length > 0) {
|
||||||
saveFile = form.value.saveFile.join(',');
|
saveFile = form.value.saveFile.join(',');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
leaveFormRef.value?.validate(async (valid: boolean) => {
|
leaveFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
@ -392,6 +394,9 @@ const submitForm = (status1: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
submit(status.value, form.value);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitFlow = async () => {
|
const submitFlow = async () => {
|
||||||
@ -429,14 +434,15 @@ const submitCallback = async () => {
|
|||||||
};
|
};
|
||||||
//审批
|
//审批
|
||||||
const approvalVerifyOpen = async () => {
|
const approvalVerifyOpen = async () => {
|
||||||
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
|
// submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
|
||||||
// submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||||
};
|
};
|
||||||
// 图纸上传成功之后 开始提交
|
// 图纸上传成功之后 开始提交
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const submit = async (status, data) => {
|
const submit = async (status, data) => {
|
||||||
form.value = data;
|
form.value = data;
|
||||||
|
form.value.id = form.value.id + '_audit';
|
||||||
if (status === 'draft') {
|
if (status === 'draft') {
|
||||||
buttonLoading.value = false;
|
buttonLoading.value = false;
|
||||||
proxy?.$modal.msgSuccess('暂存成功');
|
proxy?.$modal.msgSuccess('暂存成功');
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 提交组件 -->
|
<!-- 提交组件 -->
|
||||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
<submitVerify ref="submitVerifyRef" :businessId1="form.id" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||||
<!-- 流程选择对话框 -->
|
<!-- 流程选择对话框 -->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
@ -253,13 +253,16 @@ const submitCallback = async () => {
|
|||||||
};
|
};
|
||||||
//审批
|
//审批
|
||||||
const approvalVerifyOpen = async () => {
|
const approvalVerifyOpen = async () => {
|
||||||
|
// 判断是否还需要设计验证
|
||||||
|
if (form.value.isWindow) {
|
||||||
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
|
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
|
||||||
// submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
} else {
|
||||||
|
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// 图纸上传成功之后 开始提交
|
// 图纸上传成功之后 开始提交
|
||||||
const submit = async (status, data) => {
|
const submit = async (status, data) => {
|
||||||
form.value = data;
|
form.value = data;
|
||||||
form.value.id = routeParams.value.type == 'add' ? form.value.id + '_' : form.value.id.split('_')[0];
|
|
||||||
form.value.status = data.auditStatus ? data.auditStatus : data.status;
|
form.value.status = data.auditStatus ? data.auditStatus : data.status;
|
||||||
if (status === 'draft') {
|
if (status === 'draft') {
|
||||||
buttonLoading.value = false;
|
buttonLoading.value = false;
|
||||||
|
@ -11,12 +11,17 @@
|
|||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="编号" prop="num">
|
<el-form-item label="编号" prop="num">
|
||||||
<!-- prop="num" 需与 rules 中键名一致 -->
|
<!-- prop="num" 需与 rules 中键名一致 -->
|
||||||
<el-input v-model="formData.num" placeholder="请输入编号" />
|
<el-input v-model="formData.num" disabled placeholder="请输入编号" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="专业" prop="professional">
|
<el-form-item label="专业" prop="professionalName">
|
||||||
<el-input v-model="formData.professional" placeholder="请输入专业" />
|
<el-input v-model="formData.professionalName" disabled placeholder="请输入专业" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="卷册" prop="volume">
|
||||||
|
<el-input v-model="formData.volume" disabled placeholder="请输入卷册" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -24,14 +29,8 @@
|
|||||||
<el-input v-model="formData.stage" placeholder="请输入设计阶段" />
|
<el-input v-model="formData.stage" placeholder="请输入设计阶段" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="卷册" prop="volume">
|
|
||||||
<el-input v-model="formData.volume" placeholder="请输入卷册" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 项目信息区域 -->
|
<!-- 项目信息区域 -->
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
<div class="section-title">
|
<div class="section-title">
|
||||||
@ -54,7 +53,6 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 人员信息区域 -->
|
<!-- 人员信息区域 -->
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
<div class="section-title">
|
<div class="section-title">
|
||||||
@ -65,56 +63,77 @@
|
|||||||
<el-row :gutter="20" class="section-content">
|
<el-row :gutter="20" class="section-content">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="设计人" prop="designer">
|
<el-form-item label="设计人" prop="designer">
|
||||||
<el-input v-model="formData.designer" placeholder="请输入设计人" />
|
<el-input disabled v-model="formData.designerName" placeholder="请输入设计人" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12"></el-col>
|
<el-col :span="12"></el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="校审人员" prop="proofreading">
|
<el-form-item label="校审人员" prop="proofreading">
|
||||||
<el-input v-model="formData.proofreading" placeholder="请输入校审人员" />
|
<el-input disabled v-model="formData.proofreading" placeholder="请输入校审人员" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<!-- <el-col :span="12">
|
|
||||||
<el-form-item label="校审人员ID" prop="proofreadingId">
|
|
||||||
<el-input v-model="formData.proofreadingId" placeholder="请输入校审人员ID" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col> -->
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="校审时间" prop="proofreadingDate">
|
<el-form-item label="校审时间" prop="proofreadingDate">
|
||||||
<el-date-picker v-model="formData.proofreadingDate" type="date" placeholder="选择校审时间" format="YYYY-MM-DD"
|
<el-date-picker
|
||||||
value-format="YYYY-MM-DD" />
|
v-model="formData.proofreadingDate"
|
||||||
|
type="date"
|
||||||
|
disabled
|
||||||
|
placeholder="选择校审时间"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="审核人员" prop="audit">
|
<el-form-item label="审核人员" prop="audit">
|
||||||
<el-input v-model="formData.audit" placeholder="请输入审核人员" />
|
<el-input disabled v-model="formData.audit" placeholder="请输入审核人员" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<!-- <el-col :span="12">
|
|
||||||
<el-form-item label="审核人员ID" prop="auditId">
|
|
||||||
<el-input v-model="formData.auditId" placeholder="请输入审核人员ID" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col> -->
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="审核时间" prop="auditDate">
|
<el-form-item label="审核时间" prop="auditDate">
|
||||||
<el-date-picker v-model="formData.auditDate" type="date" placeholder="选择审核时间" format="YYYY-MM-DD"
|
<el-date-picker
|
||||||
value-format="YYYY-MM-DD" />
|
disabled
|
||||||
|
v-model="formData.auditDate"
|
||||||
|
type="date"
|
||||||
|
placeholder="选择审核时间"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="审定人员" prop="approve">
|
||||||
|
<el-input disabled v-model="formData.approve" placeholder="请输入审定人员" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="审定时间" prop="approveDate">
|
||||||
|
<el-date-picker
|
||||||
|
disabled
|
||||||
|
v-model="formData.approveDate"
|
||||||
|
type="date"
|
||||||
|
placeholder="选择审定时间"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="执行人员" prop="executor">
|
<el-form-item label="执行人员" prop="executor">
|
||||||
<el-input v-model="formData.executor" placeholder="请输入执行人员" />
|
<el-select
|
||||||
|
v-model="formData.executorId"
|
||||||
|
@change="changeExecutor"
|
||||||
|
placeholder="选择执行人员"
|
||||||
|
class="w-full transition-all duration-300 border-gray-300"
|
||||||
|
>
|
||||||
|
<el-option v-for="item in userList" :key="`user-${item.userId}`" :label="item.userName" :value="item.userId" />
|
||||||
|
</el-select>
|
||||||
|
<!-- <el-input v-model="formData.executor" placeholder="请输入执行人员" /> -->
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<!-- <el-col :span="12">
|
|
||||||
<el-form-item label="执行人员ID" prop="executorId">
|
|
||||||
<el-input v-model="formData.executorId" placeholder="请输入执行人员ID" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col> -->
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="执行时间" prop="executorDate">
|
<el-form-item label="执行时间" prop="executorDate">
|
||||||
<el-date-picker v-model="formData.executorDate" type="date" placeholder="选择执行时间" format="YYYY-MM-DD"
|
<el-date-picker v-model="formData.executorDate" type="date" placeholder="选择执行时间" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
|
||||||
value-format="YYYY-MM-DD" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -151,17 +170,20 @@
|
|||||||
<script setup name="ExamineForm" lang="ts">
|
<script setup name="ExamineForm" lang="ts">
|
||||||
import { ref, watch, reactive } from 'vue';
|
import { ref, watch, reactive } from 'vue';
|
||||||
import { fillOutTheDesignVerificationForm, drawingreviewReceipts } from '@/api/design/drawingreview';
|
import { fillOutTheDesignVerificationForm, drawingreviewReceipts } from '@/api/design/drawingreview';
|
||||||
import type { FormInstance, FormRules } from 'element-plus';
|
import { dayjs, type FormInstance, type FormRules } from 'element-plus';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { subProjectListAll } from '@/api/design/drawingreview';
|
import { subProjectListAll, getDrawingreviewReceipts } from '@/api/design/drawingreview';
|
||||||
|
import { desUserList } from '@/api/design/appointment';
|
||||||
|
|
||||||
// 获取用户 store
|
// 获取用户 store
|
||||||
const userStore = useUserStoreHook();
|
const userStore = useUserStoreHook();
|
||||||
|
const userList = ref([]);
|
||||||
|
const userMap = new Map();
|
||||||
// 从 store 中获取当前选中的项目
|
// 从 store 中获取当前选中的项目
|
||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
console.log(currentProject.value);
|
|
||||||
const subProjectList = ref([]);
|
const subProjectList = ref([]);
|
||||||
|
const Drawingreview = ref({});
|
||||||
let subProjectMap = new Map();
|
let subProjectMap = new Map();
|
||||||
// 定义表单数据类型
|
// 定义表单数据类型
|
||||||
interface FormData {
|
interface FormData {
|
||||||
@ -193,9 +215,9 @@ const rules: FormRules = {
|
|||||||
num: [{ required: true, message: '请输入编号', trigger: 'blur' }],
|
num: [{ required: true, message: '请输入编号', trigger: 'blur' }],
|
||||||
professional: [{ required: true, message: '请输入专业', trigger: 'blur' }]
|
professional: [{ required: true, message: '请输入专业', trigger: 'blur' }]
|
||||||
};
|
};
|
||||||
|
const userName = userStore.nickname;
|
||||||
// 表单数据 - 直接在组件内定义,不再通过Props接收
|
// 表单数据 - 直接在组件内定义,不再通过Props接收
|
||||||
const formData = reactive<FormData>({
|
const formData = ref({
|
||||||
num: '',
|
num: '',
|
||||||
professional: '',
|
professional: '',
|
||||||
stage: '',
|
stage: '',
|
||||||
@ -228,8 +250,8 @@ watch(
|
|||||||
(newVal) => {
|
(newVal) => {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
// 根据实际项目结构调整赋值字段
|
// 根据实际项目结构调整赋值字段
|
||||||
formData.projectId = newVal.id || '';
|
formData.value.projectId = newVal.id || '';
|
||||||
formData.projectName = newVal.name || '';
|
formData.value.projectName = newVal.name || '';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ immediate: true, deep: true }
|
{ immediate: true, deep: true }
|
||||||
@ -259,12 +281,12 @@ const resetFields = () => {
|
|||||||
|
|
||||||
// 获取表单数据
|
// 获取表单数据
|
||||||
const getFormData = (): FormData => {
|
const getFormData = (): FormData => {
|
||||||
return { ...formData };
|
return { ...formData.value };
|
||||||
};
|
};
|
||||||
|
|
||||||
// 设置表单数据
|
// 设置表单数据
|
||||||
const setFormData = (data: Partial<FormData>) => {
|
const setFormData = (data: Partial<FormData>) => {
|
||||||
Object.assign(formData, data);
|
Object.assign(formData.value, data);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 提交表单
|
// 提交表单
|
||||||
@ -279,12 +301,10 @@ const submit = async (businessId, cb) => {
|
|||||||
background: 'rgba(0, 0, 0, 0.7)'
|
background: 'rgba(0, 0, 0, 0.7)'
|
||||||
});
|
});
|
||||||
|
|
||||||
formData.subprojectName = subProjectMap.get(formData.subprojectId);
|
formData.value.subprojectName = subProjectMap.get(formData.value.subprojectId);
|
||||||
// formData.drawingreviewId = businessId;
|
|
||||||
console.log(businessId);
|
console.log(businessId);
|
||||||
// businessId 设置 如果有下滑线去掉后面及下划线
|
formData.value.drawingreviewId = businessId.replace(/_/g, '');
|
||||||
formData.drawingreviewId = businessId.replace(/_/g, '');
|
const res = await drawingreviewReceipts(formData.value);
|
||||||
const res = await drawingreviewReceipts(formData);
|
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
// 提交成功处理逻辑
|
// 提交成功处理逻辑
|
||||||
console.log('提交成功');
|
console.log('提交成功');
|
||||||
@ -292,6 +312,52 @@ const submit = async (businessId, cb) => {
|
|||||||
// 关闭
|
// 关闭
|
||||||
ElLoading.service().close();
|
ElLoading.service().close();
|
||||||
};
|
};
|
||||||
|
// 获取单据
|
||||||
|
const getInfo = async (id) => {
|
||||||
|
// 获取单据
|
||||||
|
console.log(id);
|
||||||
|
|
||||||
|
await getDeptAllUser();
|
||||||
|
let res = await getDrawingreviewReceipts(id);
|
||||||
|
console.log(res);
|
||||||
|
formData.value = res.data;
|
||||||
|
console.log(formData);
|
||||||
|
// 设计人 名称 designerName id:designer
|
||||||
|
// 校审人员 名称 proofreading id: proofreadingId 校审时间 proofreadingDate
|
||||||
|
// 审定人员 名称 approve id:approveId 审定时间 approveDate
|
||||||
|
// 审核人员 名称 audit id:auditId 审核时间 auditDate
|
||||||
|
// userStore.nickname //用户名
|
||||||
|
// userStore.userId //用户id
|
||||||
|
if (formData.value.approve) {
|
||||||
|
} else if (formData.value.audit) {
|
||||||
|
// 说明流程在第三步
|
||||||
|
formData.value.approve = userStore.nickname;
|
||||||
|
formData.value.approveId = userStore.userId;
|
||||||
|
formData.value.approveDate = dayjs().format('YYYY-MM-DD');
|
||||||
|
} else if (formData.value.proofreading) {
|
||||||
|
// 说明流程在第二步
|
||||||
|
formData.value.audit = userStore.nickname;
|
||||||
|
formData.value.auditId = userStore.userId;
|
||||||
|
formData.value.auditDate = dayjs().format('YYYY-MM-DD');
|
||||||
|
} else if (formData.value.designerName) {
|
||||||
|
// 说明流程在第一步
|
||||||
|
formData.value.proofreading = userStore.nickname;
|
||||||
|
formData.value.proofreadingId = userStore.userId;
|
||||||
|
formData.value.proofreadingDate = dayjs().format('YYYY-MM-DD');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/** 获取当前设计用户 */
|
||||||
|
const getDeptAllUser = async () => {
|
||||||
|
const res = await desUserList({ projectId: currentProject.value?.id, userType: '2' });
|
||||||
|
userList.value = res.data || [];
|
||||||
|
for (let i = 0; i < userList.value.length; i++) {
|
||||||
|
userMap.set(userList.value[i].userId, userList.value[i].userName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const changeExecutor = (val) => {
|
||||||
|
formData.value.executor = userMap.get(val);
|
||||||
|
formData.value.executorDate = dayjs().format('YYYY-MM-DD');
|
||||||
|
};
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getSubProject();
|
getSubProject();
|
||||||
});
|
});
|
||||||
@ -301,7 +367,8 @@ defineExpose({
|
|||||||
resetFields,
|
resetFields,
|
||||||
getFormData,
|
getFormData,
|
||||||
setFormData,
|
setFormData,
|
||||||
submit
|
submit,
|
||||||
|
getInfo
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -434,7 +434,7 @@ const onLoad = async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
proxy?.download('design/collect/exportWord', { id: form.id }, `收资清单_${new Date().getTime()}.zip`);
|
proxy?.download('design/collect/exportWord', { id: form.id }, `收资清单_${new Date().getTime()}.doc`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('导出失败,请重试');
|
ElMessage.error('导出失败,请重试');
|
||||||
console.error('文件导出错误:', error);
|
console.error('文件导出错误:', error);
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- 提交组件 -->
|
<!-- 提交组件 -->
|
||||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
<submitVerify ref="submitVerifyRef" :businessId1="form.id" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||||
<!-- 流程选择对话框 -->
|
<!-- 流程选择对话框 -->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
@ -202,8 +202,14 @@ const submitCallback = async () => {
|
|||||||
};
|
};
|
||||||
//审批
|
//审批
|
||||||
const approvalVerifyOpen = async () => {
|
const approvalVerifyOpen = async () => {
|
||||||
// 图纸评审验证
|
// 图纸评审验证 判断是否需要设计验证
|
||||||
|
if (form.value.isWindow) {
|
||||||
|
console.log(routeParams.value.businessId);
|
||||||
|
|
||||||
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
|
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
|
||||||
|
} else {
|
||||||
|
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const submit = async (status, data) => {
|
const submit = async (status, data) => {
|
||||||
form.value = data;
|
form.value = data;
|
||||||
|
@ -55,7 +55,9 @@
|
|||||||
<el-table-column label="子项名称" align="center" prop="designSubitem" />
|
<el-table-column label="子项名称" align="center" prop="designSubitem" />
|
||||||
<el-table-column label="设计状态" align="center" prop="designState">
|
<el-table-column label="设计状态" align="center" prop="designState">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<dict-tag :options="design_state" :value="scope.row.designState" />
|
<el-tag type="primary" v-if="scope.row.designState == '2'">未出图</el-tag>
|
||||||
|
<el-tag type="success" v-if="scope.row.designState == '1'">已出图</el-tag>
|
||||||
|
<!-- <dict-tag :options="design_state" :value="scope.row.designState" /> -->
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="专业" align="center" prop="specialtyName"> </el-table-column>
|
<el-table-column label="专业" align="center" prop="specialtyName"> </el-table-column>
|
||||||
@ -539,7 +541,6 @@ const onSubmit = async () => {
|
|||||||
buttonLoading.value = false;
|
buttonLoading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: VolumeCatalogVO) => {
|
const handleDelete = async (row?: VolumeCatalogVO) => {
|
||||||
const _ids = row?.design || ids.value;
|
const _ids = row?.design || ids.value;
|
||||||
|
@ -20,16 +20,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
<div class="grid grid-cols-1 gap-4">
|
<div class="grid grid-cols-1 gap-4">
|
||||||
<el-form
|
<el-form ref="leaveFormRef" :model="form" :rules="rules" label-width="100px" class="space-y-4">
|
||||||
ref="leaveFormRef"
|
|
||||||
:disabled="routeParams.type === 'view' || form.auditStatus == 'waiting'"
|
|
||||||
:model="form"
|
|
||||||
:rules="rules"
|
|
||||||
label-width="100px"
|
|
||||||
class="space-y-4"
|
|
||||||
>
|
|
||||||
<el-form-item label="图纸文件" prop="fileId" class="mb-2 md:col-span-2">
|
<el-form-item label="图纸文件" prop="fileId" class="mb-2 md:col-span-2">
|
||||||
<el-input v-model="form.fileName" disabled placeholder="图纸名称" />
|
<!-- <el-input v-model="form.fileName" disabled placeholder="图纸名称" /> -->
|
||||||
|
<el-link :href="form.fileUrl" target="_blank" type="primary" :underline="false">
|
||||||
|
{{ form.fileName }}
|
||||||
|
</el-link>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
@ -199,7 +195,7 @@ const submitCallback = async () => {
|
|||||||
//审批
|
//审批
|
||||||
const approvalVerifyOpen = async () => {
|
const approvalVerifyOpen = async () => {
|
||||||
// 图纸评审验证
|
// 图纸评审验证
|
||||||
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
|
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||||
};
|
};
|
||||||
const submit = async (status, data) => {
|
const submit = async (status, data) => {
|
||||||
form.value = data;
|
form.value = data;
|
||||||
|
@ -48,6 +48,20 @@
|
|||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['formalities:listOfFormalities:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['formalities:listOfFormalities:add']">新增</el-button>
|
||||||
|
<span style="margin-left: 10px"
|
||||||
|
><el-tooltip class="box-item" effect="dark" content="从原有模板列表选择新增" placement="top">
|
||||||
|
<el-icon color="#409efc"><WarningFilled /></el-icon> </el-tooltip
|
||||||
|
></span>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="primary" plain icon="Plus" @click="addTemplate()" v-hasPermi="['formalities:formalitiesAreConsolidated:addFormalities']"
|
||||||
|
>新增数据</el-button
|
||||||
|
>
|
||||||
|
<span style="margin-left: 10px">
|
||||||
|
<el-tooltip class="box-item" effect="dark" content="创建新模板并添加数据" placement="top">
|
||||||
|
<el-icon color="#409efc"><WarningFilled /></el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button
|
<el-button
|
||||||
@ -67,7 +81,7 @@
|
|||||||
<el-table v-loading="loading" :data="formalitiesAreConsolidatedList" @selection-change="handleSelectionChange" row-key="id" default-expand-all>
|
<el-table v-loading="loading" :data="formalitiesAreConsolidatedList" @selection-change="handleSelectionChange" row-key="id" default-expand-all>
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<!-- <el-table-column label="手续办理清单模板父级" align="center" prop="formalitiesPname" /> -->
|
<!-- <el-table-column label="手续办理清单模板父级" align="center" prop="formalitiesPname" /> -->
|
||||||
<el-table-column label="手续办理清单模板" align="center" prop="formalitiesName" />
|
<el-table-column label="手续办理清单" align="center" prop="formalitiesName" />
|
||||||
<el-table-column label="计划开始时间" align="center" prop="planTheStartTime" width="180">
|
<el-table-column label="计划开始时间" align="center" prop="planTheStartTime" width="180">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span>{{ parseTime(scope.row.planTheStartTime, '{y}-{m}-{d}') }}</span>
|
<span>{{ parseTime(scope.row.planTheStartTime, '{y}-{m}-{d}') }}</span>
|
||||||
@ -230,6 +244,11 @@
|
|||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
|
<div style="margin-left: 10px; display: flex; justify-content: center; align-items: center">
|
||||||
|
<el-tooltip class="box-item" effect="dark" content="列表上已选择得模版不可再选" placement="top">
|
||||||
|
<el-icon><WarningFilled /></el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span>
|
<span>
|
||||||
@ -238,6 +257,27 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 添加或修改手续办理清单模板对话框 -->
|
||||||
|
<el-dialog title="添加手续办理清单" v-model="tempDialogVisible" width="500px" append-to-body @close="templateCancel">
|
||||||
|
<el-form ref="listOfFormalitiesFormRef" :model="formTemplate" label-width="80px">
|
||||||
|
<el-form-item label="父级" prop="formalitiesPid" :rules="[{ required: true, message: '请选择父级', trigger: 'blur' }]">
|
||||||
|
<el-select v-model="formTemplate.formalitiesPid" placeholder="请选择父级">
|
||||||
|
<el-option label="根目录" value="0" />
|
||||||
|
<el-option v-for="item in listOfFormalitiesList" :label="item.name" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="名称" prop="formalitiesName" :rules="[{ required: true, message: '请输入名称', trigger: 'blur' }]">
|
||||||
|
<el-input v-model="formTemplate.formalitiesName" placeholder="请输入名称" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button :loading="buttonLoading" type="primary" @click="submitFormTemplate">确 定</el-button>
|
||||||
|
<el-button @click="templateCancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -253,12 +293,15 @@ import {
|
|||||||
editStatus,
|
editStatus,
|
||||||
getTemplateTreeList
|
getTemplateTreeList
|
||||||
} from '@/api/formalities/formalitiesAreConsolidated';
|
} from '@/api/formalities/formalitiesAreConsolidated';
|
||||||
|
import { listListOfFormalities, addFormalities } from '@/api/formalities/listOfFormalities';
|
||||||
import {
|
import {
|
||||||
FormalitiesAreConsolidatedVO,
|
FormalitiesAreConsolidatedVO,
|
||||||
FormalitiesAreConsolidatedQuery,
|
FormalitiesAreConsolidatedQuery,
|
||||||
FormalitiesAreConsolidatedForm
|
FormalitiesAreConsolidatedForm
|
||||||
} from '@/api/formalities/formalitiesAreConsolidated/types';
|
} from '@/api/formalities/formalitiesAreConsolidated/types';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
import { WarningFilled } from '@element-plus/icons-vue';
|
||||||
|
|
||||||
const fileVisible = ref(false);
|
const fileVisible = ref(false);
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
// 获取用户 store
|
// 获取用户 store
|
||||||
@ -287,6 +330,7 @@ const dialog = reactive<DialogOption>({
|
|||||||
visible: false,
|
visible: false,
|
||||||
title: ''
|
title: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
const file = ref(null);
|
const file = ref(null);
|
||||||
const fileParams = reactive({
|
const fileParams = reactive({
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
@ -404,7 +448,39 @@ const handleAdd = async () => {
|
|||||||
tempTreeList.value = res.data;
|
tempTreeList.value = res.data;
|
||||||
templateVisbile.value = true;
|
templateVisbile.value = true;
|
||||||
};
|
};
|
||||||
|
const tempDialogVisible = ref(false);
|
||||||
|
const formTemplate: any = ref({
|
||||||
|
formalitiesPid: '',
|
||||||
|
formalitiesName: ''
|
||||||
|
});
|
||||||
|
const listOfFormalitiesList: any = ref([]);
|
||||||
|
//新增模版
|
||||||
|
const addTemplate = async () => {
|
||||||
|
tempDialogVisible.value = true;
|
||||||
|
const res = await listListOfFormalities();
|
||||||
|
listOfFormalitiesList.value = res.data;
|
||||||
|
};
|
||||||
|
//确定信息
|
||||||
|
const submitFormTemplate = async () => {
|
||||||
|
const params = {
|
||||||
|
projectId: currentProject.value.id,
|
||||||
|
addBusFormalitiesAreConsolidatedBo: {
|
||||||
|
...formTemplate.value
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const res = await addFormalities(params);
|
||||||
|
if (res.code == 200) {
|
||||||
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
|
templateCancel();
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//取消
|
||||||
|
const templateCancel = () => {
|
||||||
|
tempDialogVisible.value = false;
|
||||||
|
formTemplate.value.formalitiesPid = '';
|
||||||
|
formTemplate.value.formalitiesName = '';
|
||||||
|
};
|
||||||
// 选择模板
|
// 选择模板
|
||||||
const setTemp = async () => {
|
const setTemp = async () => {
|
||||||
// form.value.formalitiesPid = tempValue.value[tempValue.value.length - 1];
|
// form.value.formalitiesPid = tempValue.value[tempValue.value.length - 1];
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<formalitiesAreConsolidated ref="formalitiesAreConsolidatedRef" class="overlay" v-if="showFormalitiesAreConsolidated" />
|
<formalitiesAreConsolidated ref="formalitiesAreConsolidatedRef" class="overlay" v-if="showFormalitiesAreConsolidated" />
|
||||||
|
|
||||||
<div class="p-2" v-else>
|
<div class="p-2" v-else>
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
|
@ -86,6 +86,7 @@ import { LoginData, TenantVO } from '@/api/types';
|
|||||||
import { to } from 'await-to-js';
|
import { to } from 'await-to-js';
|
||||||
import { HttpStatus } from '@/enums/RespEnum';
|
import { HttpStatus } from '@/enums/RespEnum';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { getAllRouters } from '@/api/system/menu';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
@ -153,6 +154,7 @@ const handleLogin = () => {
|
|||||||
if (!err) {
|
if (!err) {
|
||||||
const redirectUrl = redirect.value || '/';
|
const redirectUrl = redirect.value || '/';
|
||||||
await router.push(redirectUrl);
|
await router.push(redirectUrl);
|
||||||
|
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
} else {
|
} else {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5" :offset="0"
|
<el-col :span="1.5" :offset="0">
|
||||||
><el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:add']"
|
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:add']"
|
||||||
size="default"
|
size="default"
|
||||||
@ -15,10 +15,10 @@
|
|||||||
icon="FolderAdd"
|
icon="FolderAdd"
|
||||||
plain
|
plain
|
||||||
>新增</el-button
|
>新增</el-button
|
||||||
></el-col
|
|
||||||
>
|
>
|
||||||
<el-col :span="1.5" :offset="0"
|
</el-col>
|
||||||
><el-button
|
<el-col :span="1.5" :offset="0">
|
||||||
|
<el-button
|
||||||
type="danger"
|
type="danger"
|
||||||
size="default"
|
size="default"
|
||||||
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:remove']"
|
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:remove']"
|
||||||
@ -27,8 +27,8 @@
|
|||||||
icon="FolderDelete"
|
icon="FolderDelete"
|
||||||
plain
|
plain
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
></el-col
|
|
||||||
>
|
>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -70,19 +70,17 @@
|
|||||||
>修改</el-button
|
>修改</el-button
|
||||||
>
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5" v-if="form.mrpBaseBo.status == 'draft'">
|
||||||
<el-button plain type="warning" icon="Finished" @click="handleAudit()" v-hasPermi="['cailiaoshebei:materialbatchdemandplan:query']"
|
<el-button plain type="primary" icon="Finished" @click="handleAudit()">审核</el-button>
|
||||||
>审核</el-button
|
</el-col>
|
||||||
>
|
<el-col :span="1.5" v-if="form.mrpBaseBo.status != 'draft'">
|
||||||
|
<el-button type="warning" icon="View" @click="handleAudit()">查看流程</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="cailiaoshebeiList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="cailiaoshebeiList" @selection-change="handleSelectionChange">
|
||||||
<!-- <el-table-column type="selection" width="55" align="center" /> -->
|
|
||||||
<!-- <el-table-column label="供货商ID" align="center" prop="supplierId" /> -->
|
|
||||||
<el-table-column label="物资名称" align="center" prop="name" />
|
<el-table-column label="物资名称" align="center" prop="name" />
|
||||||
<el-table-column label="质量标准" align="center" prop="qs" />
|
<el-table-column label="质量标准" align="center" prop="qs" />
|
||||||
<el-table-column label="规格型号" align="center" prop="specification" />
|
<el-table-column label="规格型号" align="center" prop="specification" />
|
||||||
@ -103,7 +101,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!-- 添加或修改物资-材料设备对话框 -->
|
<!-- 添加或修改物资-材料设备对话框 -->
|
||||||
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="1300px" append-to-body>
|
<el-dialog :close-on-click-modal="false" draggable :title="dialog.title" v-model="dialog.visible" width="1500px" append-to-body>
|
||||||
<el-form :model="form" ref="cailiaoshebeiFormRef" :rules="rules" label-width="80px" :inline="false">
|
<el-form :model="form" ref="cailiaoshebeiFormRef" :rules="rules" label-width="80px" :inline="false">
|
||||||
<el-divider>基础信息</el-divider>
|
<el-divider>基础信息</el-divider>
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
@ -125,63 +123,93 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-divider>主要信息</el-divider>
|
<el-divider>主要信息</el-divider>
|
||||||
<el-table :data="form.planList">
|
<!-- 表格添加border属性,优化视觉体验 -->
|
||||||
<el-table-column prop="name" align="center" label="版本号 " width="150">
|
<el-table :data="form.planList" border>
|
||||||
|
<!-- 版本号列 -->
|
||||||
|
<el-table-column prop="batchNumber" align="center" label="版本号 " width="200">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-select v-model="scope.row.versions" placeholder="请选择" @change="(val) => selectNameVersion(val, scope.row)">
|
<el-select v-model="scope.row.batchNumber" placeholder="请选择" @change="(val) => selectNameVersion(val, scope.row, scope.$index)">
|
||||||
<el-option v-for="item in versionList" :key="item.versions" :label="item.versions" :value="item.versions" />
|
<el-option v-for="item in versionList" :key="item.versions" :label="item.versions" :value="item.versions" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="name" align="center" label="物资名称">
|
<!-- 物资名称列 -->
|
||||||
|
<el-table-column prop="name" align="center" label="物资名称" width="160">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row.name" v-if="scope.row.mrpBaseId" placeholder="请输入物资名称" disabled />
|
||||||
<el-select
|
<el-select
|
||||||
:disabled="!scope.row.versions"
|
v-else
|
||||||
|
:disabled="!scope.row.batchNumber"
|
||||||
v-model="scope.row.suppliespriceId"
|
v-model="scope.row.suppliespriceId"
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
@change="(val) => selectName(val, scope.row)"
|
@change="(val) => selectName(val, scope.row, scope.$index)"
|
||||||
>
|
>
|
||||||
<el-option v-for="item in nameList" :key="item.id" :label="item.name" :value="item.id" />
|
<el-option v-for="item in nameList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="specification" align="center" label="规格型号" width="150">
|
<!-- 剩余量列 -->
|
||||||
|
<el-table-column align="center" label="剩余量" width="80">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input v-model="scope.row.specification" placeholder="请输入规格型号" disabled />
|
<span>{{ scope.row.Remaining }}</span>
|
||||||
|
<!-- <el-input disabled v-model="scope.row.Remaining" placeholder="剩余量" /> -->
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="unit" align="center" label="单位" width="130">
|
<!-- 规格型号列 -->
|
||||||
|
<el-table-column prop="specification" align="center" label="规格型号" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input v-model="scope.row.unit" placeholder="请输入单位" disabled />
|
<span>{{ scope.row.specification }}</span>
|
||||||
|
<!-- <el-input v-model="scope.row.specification" placeholder="请输入规格型号" disabled /> -->
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="demandQuantity" align="center" label="数量" width="130">
|
<!-- 单位列 -->
|
||||||
|
<el-table-column prop="unit" align="center" label="单位" width="80">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input v-model="scope.row.demandQuantity" placeholder="请输入数量" type="number" min="0" disabled />
|
<span>{{ scope.row.unit }}</span>
|
||||||
|
<!-- <el-input v-model="scope.row.unit" placeholder="请输入单位" disabled /> -->
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="qs" align="center" label="质量标准" width="150">
|
<!-- 数量列(新增错误提示展示) -->
|
||||||
<template #header> <span class="text-red">*</span> 质量标准 </template>
|
<el-table-column prop="demandQuantity" align="center" label="数量" width="140">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input
|
||||||
|
v-model.number="scope.row.demandQuantity"
|
||||||
|
@input="validateDemandQuantity(scope.row, scope.$index)"
|
||||||
|
@blur="validateDemandQuantity(scope.row, scope.$index)"
|
||||||
|
:max="scope.row.Remaining"
|
||||||
|
placeholder="请输入数量"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
/>
|
||||||
|
<!-- 数量错误提示(红色小字体) -->
|
||||||
|
<div v-if="scope.row.quantityError" class="text-red-500 text-xs mt-1">{{ scope.row.quantityError }}</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<!-- 质量标准列 -->
|
||||||
|
<el-table-column prop="qs" align="center" label="质量标准" width="140">
|
||||||
|
<template #header> <span class="text-red-500">*</span> 质量标准 </template>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input v-model="scope.row.qs" placeholder="请输入质量标准" />
|
<el-input v-model="scope.row.qs" placeholder="请输入质量标准" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="arrivalTime" align="center" label="需求到货时间">
|
<!-- 需求到货时间列 -->
|
||||||
<template #header> <span class="text-red">*</span> 需求到货时间 </template>
|
<el-table-column prop="arrivalTime" align="center" label="需求到货时间" width="180">
|
||||||
|
<template #header> <span class="text-red-500">*</span> 需求到货时间 </template>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-date-picker v-model="scope.row.arrivalTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择" style="width: 140px" />
|
<el-date-picker v-model="scope.row.arrivalTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择" style="width: 140px" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="remark" align="center" label="备注" width="150">
|
<!-- 备注列 -->
|
||||||
|
<el-table-column prop="remark" align="center" label="备注">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input v-model="scope.row.remark" placeholder="请输入备注" disabled />
|
<el-input v-model="scope.row.remark" placeholder="请输入备注" disabled />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<!-- 操作列 -->
|
||||||
<el-table-column prop="remark" align="center" label="操作" width="150">
|
<el-table-column prop="remark" align="center" label="操作" width="150">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button @click="addRow" type="success" icon="Plus" circle size="small" />
|
<el-button @click="addRow" type="primary" icon="Plus" size="small" />
|
||||||
<el-button @click="delRow(scope.$index)" type="danger" icon="Delete" circle size="small" />
|
<el-button @click="delRow(scope.$index)" type="danger" icon="Delete" size="small" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -206,10 +234,48 @@ import {
|
|||||||
listSelectCailiaoshebei,
|
listSelectCailiaoshebei,
|
||||||
obtainTheVersion,
|
obtainTheVersion,
|
||||||
getDictList,
|
getDictList,
|
||||||
coryEngineeringList
|
coryEngineeringList,
|
||||||
|
mrpBaseRemaining
|
||||||
} from '@/api/materials/batchPlan';
|
} from '@/api/materials/batchPlan';
|
||||||
import { CailiaoshebeiVO, CailiaoshebeiQuery, CailiaoshebeiForm } from '@/api/materials/batchPlan/types';
|
import { CailiaoshebeiVO, CailiaoshebeiQuery, CailiaoshebeiForm } from '@/api/materials/batchPlan/types';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
import { getCurrentInstance, ComponentInternalInstance, watch, onMounted, onUnmounted } from 'vue';
|
||||||
|
import type { ElFormInstance } from 'element-plus';
|
||||||
|
|
||||||
|
// 类型定义补充
|
||||||
|
interface DialogOption {
|
||||||
|
visible: boolean;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PlanListItem {
|
||||||
|
id?: number | undefined;
|
||||||
|
name?: string | undefined;
|
||||||
|
specification?: string | undefined;
|
||||||
|
unit?: string | undefined;
|
||||||
|
suppliespriceId?: number | undefined;
|
||||||
|
demandQuantity?: number | undefined;
|
||||||
|
qs?: string | undefined;
|
||||||
|
arrivalTime?: string | undefined;
|
||||||
|
remark?: string | undefined;
|
||||||
|
Remaining: number; // 剩余量(必存在)
|
||||||
|
quantityError: string; // 数量错误提示
|
||||||
|
batchNumber?: string | undefined; // 版本号
|
||||||
|
duplicateError: string; // 重复错误提示
|
||||||
|
mrpBaseId?: number | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
mrpBaseBo: {
|
||||||
|
id?: number | undefined;
|
||||||
|
preparedDate?: string | undefined;
|
||||||
|
planCode?: string | undefined;
|
||||||
|
matCat?: string | undefined;
|
||||||
|
status?: string | undefined;
|
||||||
|
projectId?: number | undefined;
|
||||||
|
};
|
||||||
|
planList: PlanListItem[];
|
||||||
|
}
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
// 获取用户 store
|
// 获取用户 store
|
||||||
@ -227,17 +293,17 @@ const multiple = ref(true);
|
|||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const mainTotal = ref(0);
|
const mainTotal = ref(0);
|
||||||
const batchOptions = ref<any[]>([]);
|
const batchOptions = ref<any[]>([]);
|
||||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
|
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status') || {});
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const cailiaoshebeiFormRef = ref<ElFormInstance>();
|
const cailiaoshebeiFormRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
title: ''
|
title: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
const initFormData: any = {
|
// 初始化表单数据(补充版本号、重复错误提示字段)
|
||||||
|
const initFormData: FormData = {
|
||||||
mrpBaseBo: {
|
mrpBaseBo: {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
preparedDate: undefined,
|
preparedDate: undefined,
|
||||||
@ -246,7 +312,6 @@ const initFormData: any = {
|
|||||||
status: undefined,
|
status: undefined,
|
||||||
projectId: currentProject.value?.id
|
projectId: currentProject.value?.id
|
||||||
},
|
},
|
||||||
|
|
||||||
planList: [
|
planList: [
|
||||||
{
|
{
|
||||||
id: undefined,
|
id: undefined,
|
||||||
@ -257,18 +322,23 @@ const initFormData: any = {
|
|||||||
demandQuantity: undefined,
|
demandQuantity: undefined,
|
||||||
qs: undefined,
|
qs: undefined,
|
||||||
arrivalTime: undefined,
|
arrivalTime: undefined,
|
||||||
remark: undefined
|
remark: undefined,
|
||||||
|
Remaining: 0, // 初始化剩余量
|
||||||
|
quantityError: '', // 初始化数量错误提示
|
||||||
|
batchNumber: undefined, // 初始化版本号
|
||||||
|
duplicateError: '', // 初始化重复错误提示
|
||||||
|
mrpBaseId: undefined
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData } as FormData,
|
||||||
queryParams: {
|
queryParams: {
|
||||||
batchData: {
|
batchData: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
planCode: undefined,
|
planCode: undefined,
|
||||||
|
|
||||||
projectId: currentProject.value?.id
|
projectId: currentProject.value?.id
|
||||||
},
|
},
|
||||||
mainData: {
|
mainData: {
|
||||||
@ -285,77 +355,187 @@ const data = reactive({
|
|||||||
'mrpBaseBo.matCat': [{ required: true, message: '物资分类不能为空', trigger: 'blur' }]
|
'mrpBaseBo.matCat': [{ required: true, message: '物资分类不能为空', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const batchNumber = ref('');
|
const batchNumber = ref('');
|
||||||
const { queryParams, form, rules } = toRefs(data);
|
const { queryParams, form, rules } = toRefs(data);
|
||||||
const nameList = ref([]);
|
const nameList = ref<any[]>([]);
|
||||||
const versionList = ref([]);
|
const versionList = ref<any[]>([]);
|
||||||
|
|
||||||
/** 查询物资-材料设备列表 */
|
/** 查询物资-材料设备列表 */
|
||||||
const getList = async (type?: string) => {
|
const getList = async (type?: string) => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
try {
|
||||||
const res = await listBatch(queryParams.value.batchData);
|
const res = await listBatch(queryParams.value.batchData);
|
||||||
batchOptions.value = res.rows;
|
batchOptions.value = res.rows || [];
|
||||||
if (res.rows && res.rows.length > 0 && !queryParams.value.mainData.mrpBaseId) {
|
// 自动选中第一条数据(如果存在且未选中)
|
||||||
batchTreeRef.value.setCurrentKey(res.rows[0].id);
|
if (batchOptions.value.length > 0 && !queryParams.value.mainData.mrpBaseId) {
|
||||||
queryParams.value.mainData.mrpBaseId = res.rows[0].id;
|
batchTreeRef.value?.setCurrentKey(batchOptions.value[0].id);
|
||||||
form.value.mrpBaseBo.status = res.rows[0].status;
|
queryParams.value.mainData.mrpBaseId = batchOptions.value[0].id;
|
||||||
|
form.value.mrpBaseBo.status = batchOptions.value[0].status;
|
||||||
}
|
}
|
||||||
total.value = res.total;
|
total.value = res.total || 0;
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('获取批次列表失败');
|
||||||
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
if (type === 'search') return;
|
// 非搜索场景下同步加载主列表
|
||||||
|
if (type !== 'search') {
|
||||||
getMainList();
|
getMainList();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectName = (val: any, row: any) => {
|
/** 数量校验:必须≤剩余量,且为合法数字 */
|
||||||
const selected = nameList.value.find((item) => item.id === val);
|
const validateDemandQuantity = (row: PlanListItem, index: number) => {
|
||||||
|
// 1. 清除之前的错误信息
|
||||||
|
row.quantityError = '';
|
||||||
|
|
||||||
|
// 2. 处理空值(若需必填可补充:row.quantityError = '数量不能为空')
|
||||||
|
if (row.demandQuantity === null || row.demandQuantity === undefined || row.demandQuantity === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 处理非数字
|
||||||
|
if (typeof row.demandQuantity !== 'number' || isNaN(row.demandQuantity)) {
|
||||||
|
row.quantityError = '请输入合法数字';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 处理负数
|
||||||
|
if (row.demandQuantity < 0) {
|
||||||
|
row.quantityError = '数量不能为负数';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 核心校验:数量≤剩余量
|
||||||
|
if (row.demandQuantity > row.Remaining) {
|
||||||
|
row.quantityError = `数量不能超过剩余量${row.Remaining}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 获取剩余量 */
|
||||||
|
const getMrpBaseRemaining = async (suppliespriceId: number, row: PlanListItem) => {
|
||||||
|
try {
|
||||||
|
const res = await mrpBaseRemaining({ suppliespriceId });
|
||||||
|
row.Remaining = res.data || 0;
|
||||||
|
// 剩余量更新后,重新校验当前数量
|
||||||
|
validateDemandQuantity(row, 0);
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('获取剩余量失败');
|
||||||
|
row.Remaining = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 校验重复数据:版本号+物资名称不能重复 */
|
||||||
|
const checkDuplicate = () => {
|
||||||
|
const planList = form.value.planList;
|
||||||
|
let hasDuplicate = false;
|
||||||
|
|
||||||
|
// 1. 清除所有重复错误提示
|
||||||
|
planList.forEach((item) => {
|
||||||
|
item.duplicateError = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. 遍历校验重复(只校验版本号和物资名称都存在的行)
|
||||||
|
for (let i = 0; i < planList.length; i++) {
|
||||||
|
const current = planList[i];
|
||||||
|
// 跳过版本号或物资名称为空的行
|
||||||
|
if (!current.batchNumber || !current.suppliespriceId) continue;
|
||||||
|
|
||||||
|
for (let j = i + 1; j < planList.length; j++) {
|
||||||
|
const compare = planList[j];
|
||||||
|
if (!compare.batchNumber || !compare.suppliespriceId) continue;
|
||||||
|
|
||||||
|
// 版本号和物资ID都相同则判定为重复
|
||||||
|
if (current.batchNumber === compare.batchNumber && current.suppliespriceId === compare.suppliespriceId) {
|
||||||
|
current.duplicateError = `与第${j + 1}行重复(同版本+同物资)`;
|
||||||
|
compare.duplicateError = `与第${i + 1}行重复(同版本+同物资)`;
|
||||||
|
hasDuplicate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasDuplicate;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 选择物资名称触发(新增索引参数,用于触发重复校验) */
|
||||||
|
const selectName = (val: number, row: PlanListItem, index: number) => {
|
||||||
|
console.log(row);
|
||||||
|
|
||||||
|
// 1. 获取剩余量并更新基础信息
|
||||||
|
getMrpBaseRemaining(val, row).then(() => {
|
||||||
|
const selected = nameList.value.find((item: any) => item.id === val);
|
||||||
if (selected) {
|
if (selected) {
|
||||||
row.name = selected.name;
|
row.name = selected.name;
|
||||||
row.specification = selected.specification;
|
row.specification = selected.specification;
|
||||||
row.unit = selected.unit;
|
row.unit = selected.unit;
|
||||||
row.qs = selected.qs;
|
row.qs = selected.qs || '';
|
||||||
row.demandQuantity = selected.quantity;
|
row.remark = selected.remark || '';
|
||||||
row.remark = selected.remark;
|
row.arrivalTime = selected.arrivalTime || '';
|
||||||
row.arrivalTime = selected.arrivalTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. 触发重复校验
|
||||||
|
checkDuplicate();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 节点单击事件 */
|
/** 节点单击事件 */
|
||||||
const handleNodeClick = (data: any) => {
|
const handleNodeClick = (data: any) => {
|
||||||
queryParams.value.mainData.mrpBaseId = data.id;
|
queryParams.value.mainData.mrpBaseId = data.id;
|
||||||
form.value.mrpBaseBo.status = data.status;
|
form.value.mrpBaseBo.status = data.status;
|
||||||
|
|
||||||
getMainList();
|
getMainList();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 获取主列表数据 */
|
||||||
const getMainList = async () => {
|
const getMainList = async () => {
|
||||||
if (!queryParams.value.mainData.mrpBaseId) return;
|
if (!queryParams.value.mainData.mrpBaseId) return;
|
||||||
|
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
const res = await getBatch(queryParams.value.mainData);
|
const res = await getBatch(queryParams.value.mainData);
|
||||||
cailiaoshebeiList.value = res.rows;
|
cailiaoshebeiList.value = res.rows || [];
|
||||||
mainTotal.value = res.total;
|
mainTotal.value = res.total || 0;
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('获取物资列表失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 搜索批次列表 */
|
||||||
const searchBatchList = async () => {
|
const searchBatchList = async () => {
|
||||||
queryParams.value.batchData.planCode = batchNumber.value;
|
queryParams.value.batchData.planCode = batchNumber.value;
|
||||||
getList('search');
|
getList('search');
|
||||||
};
|
};
|
||||||
|
|
||||||
//删除
|
/** 删除表格行 */
|
||||||
const delRow = (index: number) => {
|
const delRow = (index: number) => {
|
||||||
if (form.value.planList.length <= 1) return proxy?.$modal.msgWarning('请至少保留一项');
|
if (form.value.planList.length <= 1) {
|
||||||
|
return proxy?.$modal.msgWarning('请至少保留一项物资数据');
|
||||||
|
}
|
||||||
form.value.planList.splice(index, 1);
|
form.value.planList.splice(index, 1);
|
||||||
|
// 删除后重新校验重复(避免删除重复行后错误提示残留)
|
||||||
|
checkDuplicate();
|
||||||
};
|
};
|
||||||
|
|
||||||
//新增
|
/** 新增表格行 */
|
||||||
const addRow = () => {
|
const addRow = () => {
|
||||||
form.value.planList.push({
|
const newRow: PlanListItem = {
|
||||||
name: undefined,
|
name: undefined,
|
||||||
specification: undefined,
|
specification: undefined,
|
||||||
unit: undefined,
|
unit: undefined,
|
||||||
|
suppliespriceId: undefined,
|
||||||
demandQuantity: undefined,
|
demandQuantity: undefined,
|
||||||
qs: undefined,
|
qs: undefined,
|
||||||
arrivalTime: undefined,
|
arrivalTime: undefined,
|
||||||
remark: undefined
|
remark: undefined,
|
||||||
});
|
Remaining: 0,
|
||||||
|
quantityError: '',
|
||||||
|
batchNumber: undefined,
|
||||||
|
duplicateError: '',
|
||||||
|
mrpBaseId: undefined
|
||||||
|
};
|
||||||
|
form.value.planList.push(newRow);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
@ -367,41 +547,22 @@ const cancel = () => {
|
|||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
const status = form.value.mrpBaseBo.status;
|
const status = form.value.mrpBaseBo.status;
|
||||||
form.value = { ...initFormData, status }; // 重置但保留
|
// 重置表单(保留状态字段)
|
||||||
|
form.value = {
|
||||||
|
...JSON.parse(JSON.stringify(initFormData)),
|
||||||
|
mrpBaseBo: { ...initFormData.mrpBaseBo, status }
|
||||||
|
};
|
||||||
|
// 重置表单验证状态
|
||||||
cailiaoshebeiFormRef.value?.resetFields();
|
cailiaoshebeiFormRef.value?.resetFields();
|
||||||
|
// 重置项目ID
|
||||||
form.value.mrpBaseBo.projectId = currentProject.value?.id;
|
form.value.mrpBaseBo.projectId = currentProject.value?.id;
|
||||||
form.value.planList = [
|
|
||||||
{
|
|
||||||
name: undefined,
|
|
||||||
specification: undefined,
|
|
||||||
unit: undefined,
|
|
||||||
suppliespriceId: undefined,
|
|
||||||
|
|
||||||
demandQuantity: undefined,
|
|
||||||
qs: undefined,
|
|
||||||
arrivalTime: undefined,
|
|
||||||
remark: undefined
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// /** 搜索按钮操作 */
|
|
||||||
// const handleQuery = () => {
|
|
||||||
// queryParams.value.pageNum = 1;
|
|
||||||
// getList();
|
|
||||||
// };
|
|
||||||
|
|
||||||
// /** 重置按钮操作 */
|
|
||||||
// const resetQuery = () => {
|
|
||||||
// queryFormRef.value?.resetFields();
|
|
||||||
// handleQuery();
|
|
||||||
// };
|
|
||||||
|
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: CailiaoshebeiVO[]) => {
|
const handleSelectionChange = (selection: CailiaoshebeiVO[]) => {
|
||||||
ids.value = selection.map((item) => item.id);
|
ids.value = selection.map((item) => item.id);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length !== 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = selection.length === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
@ -411,93 +572,157 @@ const handleAdd = () => {
|
|||||||
dialog.title = '新增物资-需求';
|
dialog.title = '新增物资-需求';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 修改按钮操作 */
|
||||||
const handleUpdata = () => {
|
const handleUpdata = () => {
|
||||||
|
if (!queryParams.value.mainData.mrpBaseId) {
|
||||||
|
return proxy?.$modal.msgError('请先选择批次');
|
||||||
|
}
|
||||||
|
// 1. 获取对应版本的物资列表
|
||||||
reset();
|
reset();
|
||||||
getCailiaoshebei(queryParams.value.mainData.mrpBaseId).then((res: any) => {
|
loading.value = true;
|
||||||
form.value.mrpBaseBo = res.data.mrpBaseBo;
|
getCailiaoshebei(queryParams.value.mainData.mrpBaseId)
|
||||||
const allowedKeys = Object.keys(initFormData.planList[0]);
|
.then((res: any) => {
|
||||||
form.value.planList = res.data.planList.map((item) => {
|
// 1. 更新基础信息
|
||||||
return allowedKeys.reduce((obj, key) => {
|
form.value.mrpBaseBo = res.data.mrpBaseBo || initFormData.mrpBaseBo;
|
||||||
obj[key] = item[key] ?? undefined;
|
|
||||||
return obj;
|
|
||||||
}, {});
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(form.value.planList);
|
// 2. 更新表格数据(补充缺失字段)
|
||||||
});
|
form.value.planList = (res.data.planList || []).map((item: any) => ({
|
||||||
|
id: item.id,
|
||||||
|
name: item.name,
|
||||||
|
specification: item.specification,
|
||||||
|
unit: item.unit,
|
||||||
|
suppliespriceId: item.suppliespriceId,
|
||||||
|
demandQuantity: item.demandQuantity,
|
||||||
|
qs: item.qs,
|
||||||
|
arrivalTime: item.arrivalTime,
|
||||||
|
remark: item.remark,
|
||||||
|
Remaining: Number(item.remaining) || 0,
|
||||||
|
// remaining:
|
||||||
|
quantityError: '',
|
||||||
|
batchNumber: item.batchNumber,
|
||||||
|
duplicateError: '',
|
||||||
|
mrpBaseId: item.mrpBaseId
|
||||||
|
}));
|
||||||
|
// 3. 打开对话框
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = '修改物资-需求';
|
dialog.title = '修改物资-需求';
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
proxy?.$modal.msgError('获取详情失败');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 提交数据 */
|
/** 提交数据(整合所有校验) */
|
||||||
const submitTransferForm = async () => {
|
const submitTransferForm = async () => {
|
||||||
const result = validateAndClean(form.value.planList);
|
// 1. 先校验重复数据
|
||||||
if (!result.valid) {
|
const hasDuplicate = checkDuplicate();
|
||||||
proxy?.$modal.msgError(result.message);
|
if (hasDuplicate) {
|
||||||
return;
|
return proxy?.$modal.msgError('存在重复的版本号+物资组合,请修正后提交');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. 校验数量合法性(检查是否有数量错误)
|
||||||
|
const hasQuantityError = form.value.planList.some((row) => row.quantityError);
|
||||||
|
if (hasQuantityError) {
|
||||||
|
return proxy?.$modal.msgError('存在非法数量,请修正后提交');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 执行表单基础验证
|
||||||
|
const result = validateAndClean(form.value.planList);
|
||||||
|
if (!result.valid) {
|
||||||
|
return proxy?.$modal.msgError(result.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 表单组件验证
|
||||||
cailiaoshebeiFormRef.value?.validate(async (valid: boolean) => {
|
cailiaoshebeiFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (!valid) return;
|
||||||
|
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
form.value.planList = result.data;
|
try {
|
||||||
await updateCailiaoshebei(form.value).finally(() => (buttonLoading.value = false));
|
// 5. 提交数据
|
||||||
|
await updateCailiaoshebei({
|
||||||
|
...form.value,
|
||||||
|
planList: result.data // 使用清洗后的数据
|
||||||
|
});
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
|
// 6. 刷新列表
|
||||||
await getList();
|
await getList();
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('操作失败,请重试');
|
||||||
|
} finally {
|
||||||
|
buttonLoading.value = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 删除批次 */
|
/** 删除批次 */
|
||||||
const handleDeleteBatch = async () => {
|
const handleDeleteBatch = async () => {
|
||||||
const _ids = batchTreeRef.value.getCurrentNode()?.id;
|
const _id = batchTreeRef.value?.getCurrentNode()?.id;
|
||||||
await proxy?.$modal.confirm('是否确认删除批次编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
if (!_id) {
|
||||||
await delBatch(_ids);
|
return proxy?.$modal.msgError('请先选择批次');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await proxy?.$modal.confirm('是否确认删除该批次?删除后不可恢复!');
|
||||||
|
await delBatch(_id);
|
||||||
proxy?.$modal.msgSuccess('删除成功');
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
|
// 重置选中状态并刷新列表
|
||||||
queryParams.value.mainData.mrpBaseId = undefined;
|
queryParams.value.mainData.mrpBaseId = undefined;
|
||||||
|
form.value.mrpBaseBo.status = undefined;
|
||||||
await getList();
|
await getList();
|
||||||
|
} catch (error) {
|
||||||
|
// 取消确认时不提示错误
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
proxy?.$modal.msgError('删除失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ValidateResult {
|
/** 数据清洗与基础校验 */
|
||||||
valid: boolean;
|
function validateAndClean(arr: PlanListItem[]) {
|
||||||
data: any[];
|
// 1. 过滤掉全空的数据项
|
||||||
errors: { index: number; field: string; message: string }[];
|
const cleanedArr = arr.filter((item) => !Object.values(item).every((v) => v === '' || v == null || v === undefined));
|
||||||
}
|
|
||||||
|
|
||||||
function validateAndClean(arr: any[]) {
|
let hasFullItem = false; // 是否有至少一条完整数据
|
||||||
// 过滤掉全空的数据项
|
|
||||||
const cleanedArr = arr.filter((item) => !Object.values(item).every((v) => v === '' || v == null));
|
|
||||||
|
|
||||||
let hasFullItem = false; // 是否有至少一条全填数据
|
|
||||||
|
|
||||||
|
// 2. 逐行校验必填项
|
||||||
for (let idx = 0; idx < cleanedArr.length; idx++) {
|
for (let idx = 0; idx < cleanedArr.length; idx++) {
|
||||||
const item = cleanedArr[idx];
|
const item = cleanedArr[idx];
|
||||||
const keys = Object.keys(item).filter((k) => k !== 'remark' && k !== 'id');
|
|
||||||
|
|
||||||
const allFilled = keys.every((k) => item[k] !== '' && item[k] != null);
|
// 校验版本号
|
||||||
const allEmpty = Object.values(item).every((v) => v === '' || v == null);
|
if (!item.batchNumber) {
|
||||||
|
return { valid: false, message: `第${idx + 1}行:版本号不能为空`, data: cleanedArr };
|
||||||
|
}
|
||||||
|
|
||||||
// 单独检查 qs 和 arrivalTime
|
// 校验物资选择
|
||||||
|
if (!item.suppliespriceId) {
|
||||||
|
return { valid: false, message: `第${idx + 1}行:请选择物资名称`, data: cleanedArr };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验质量标准
|
||||||
if (!item.qs) {
|
if (!item.qs) {
|
||||||
return { valid: false, message: `第${idx + 1}行:质量标准不能为空`, data: cleanedArr };
|
return { valid: false, message: `第${idx + 1}行:质量标准不能为空`, data: cleanedArr };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 校验需求到货时间
|
||||||
if (!item.arrivalTime) {
|
if (!item.arrivalTime) {
|
||||||
return { valid: false, message: `第${idx + 1}行:需求到货时间不能为空`, data: cleanedArr };
|
return { valid: false, message: `第${idx + 1}行:需求到货时间不能为空`, data: cleanedArr };
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查其他字段是否部分填
|
// 校验数量(必填且≥0)
|
||||||
if (!allFilled && !allEmpty) {
|
if (item.demandQuantity === null || item.demandQuantity === undefined || item.demandQuantity < 0) {
|
||||||
return { valid: false, message: `第${idx + 1}行:主要信息存在部分字段缺失的数据项`, data: cleanedArr };
|
return { valid: false, message: `第${idx + 1}行:请输入合法的需求数量`, data: cleanedArr };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allFilled) {
|
|
||||||
hasFullItem = true;
|
hasFullItem = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否至少有一条完整的数据
|
// 3. 检查是否至少有一条完整数据
|
||||||
if (!hasFullItem) {
|
if (!hasFullItem) {
|
||||||
return { valid: false, message: '至少需要一条完整的数据', data: cleanedArr };
|
return { valid: false, message: '至少需要填写一条完整的物资数据', data: cleanedArr };
|
||||||
}
|
}
|
||||||
|
|
||||||
return { valid: true, message: '', data: cleanedArr };
|
return { valid: true, message: '', data: cleanedArr };
|
||||||
@ -506,54 +731,96 @@ function validateAndClean(arr: any[]) {
|
|||||||
/** 审核按钮操作 */
|
/** 审核按钮操作 */
|
||||||
const handleAudit = async () => {
|
const handleAudit = async () => {
|
||||||
if (!form.value.mrpBaseBo.status) {
|
if (!form.value.mrpBaseBo.status) {
|
||||||
proxy?.$modal.msgError('请选择批次号');
|
return proxy?.$modal.msgError('请选择批次号');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
if (!queryParams.value.mainData.mrpBaseId) {
|
||||||
|
return proxy?.$modal.msgError('请选择批次号');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭当前页并打开审核页
|
||||||
proxy?.$tab.closePage(route);
|
proxy?.$tab.closePage(route);
|
||||||
proxy?.$tab.openPage('/approval/batchPlan/indexEdit', '审核物资设备批次需求计划', {
|
proxy?.$tab.openPage('/approval/batchPlan/indexEdit', '审核物资设备批次需求计划', {
|
||||||
id: queryParams.value.mainData.mrpBaseId,
|
id: queryParams.value.mainData.mrpBaseId,
|
||||||
status: form.value.mrpBaseBo.status + '_batchRequirements',
|
status: `${form.value.mrpBaseBo.status}_batchRequirements`,
|
||||||
type: 'update'
|
type: 'update'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getNameList = (versions) => {
|
/** 获取物资列表(按版本号筛选) */
|
||||||
coryEngineeringList({ projectId: currentProject.value?.id, versions }).then((res) => {
|
const getNameList = (versions: string) => {
|
||||||
nameList.value = res.data;
|
coryEngineeringList({
|
||||||
|
projectId: currentProject.value?.id,
|
||||||
|
versions
|
||||||
|
})
|
||||||
|
.then((res: any) => {
|
||||||
|
nameList.value = res.data || [];
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
nameList.value = [];
|
||||||
|
proxy?.$modal.msgError('获取物资列表失败');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 获取版本号
|
|
||||||
const getVersion = () => {
|
|
||||||
obtainTheVersion({ projectId: currentProject.value?.id }).then((res) => {
|
|
||||||
versionList.value = res.data;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const selectNameVersion = (val, row) => {
|
|
||||||
row.suppliespriceId = undefined;
|
|
||||||
getNameList(val);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
/** 获取版本号列表 */
|
||||||
|
const getVersion = () => {
|
||||||
|
obtainTheVersion({ projectId: currentProject.value?.id })
|
||||||
|
.then((res: any) => {
|
||||||
|
versionList.value = res.data || [];
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
versionList.value = [];
|
||||||
|
proxy?.$modal.msgError('获取版本号失败');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 选择版本号触发(新增索引参数,用于触发重复校验) */
|
||||||
|
const selectNameVersion = (val: string, row: PlanListItem, index: number) => {
|
||||||
|
row.batchNumber = val;
|
||||||
|
row.suppliespriceId = undefined; // 切换版本号时清空物资选择
|
||||||
|
row.name = undefined;
|
||||||
|
row.specification = undefined;
|
||||||
|
row.unit = undefined;
|
||||||
|
row.qs = undefined;
|
||||||
|
row.remark = undefined;
|
||||||
|
row.arrivalTime = undefined;
|
||||||
|
row.demandQuantity = undefined;
|
||||||
|
row.quantityError = '';
|
||||||
|
row.duplicateError = '';
|
||||||
|
row.mrpBaseId = '';
|
||||||
|
|
||||||
|
// 1. 获取对应版本的物资列表
|
||||||
|
getNameList(val);
|
||||||
|
|
||||||
|
// 2. 触发重复校验(清空物资后可能消除重复)
|
||||||
|
checkDuplicate();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 页面挂载时初始化 */
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
// getNameList();
|
|
||||||
getVersion();
|
getVersion();
|
||||||
});
|
});
|
||||||
|
|
||||||
//监听项目id刷新数据
|
/** 监听项目ID变化,刷新数据 */
|
||||||
const listeningProject = watch(
|
const listeningProject = watch(
|
||||||
() => currentProject.value?.id,
|
() => currentProject.value?.id,
|
||||||
(nid, oid) => {
|
(newId, oldId) => {
|
||||||
queryParams.value.mainData.projectId = nid;
|
if (newId !== oldId && newId) {
|
||||||
queryParams.value.batchData.projectId = nid;
|
queryParams.value.mainData.projectId = newId;
|
||||||
form.value.mrpBaseBo.projectId = nid;
|
queryParams.value.batchData.projectId = newId;
|
||||||
|
form.value.mrpBaseBo.projectId = newId;
|
||||||
getList();
|
getList();
|
||||||
|
getVersion(); // 重新获取对应项目的版本号
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** 页面卸载时清理监听 */
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
listeningProject();
|
listeningProject();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.custom-tree-node {
|
.custom-tree-node {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@ -563,4 +830,17 @@ onUnmounted(() => {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding-right: 8px;
|
padding-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 错误提示样式补充 */
|
||||||
|
.text-red-500 {
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-xs {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
<el-table-column label="操作" align="center" min-width="150" fixed="right">
|
<el-table-column label="操作" align="center" min-width="150" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['materials:materialIssue:query']">查看</el-button>
|
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['materials:materialIssue:query']">查看</el-button>
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materialIssue:edit']">修改</el-button>
|
<!-- <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materialIssue:edit']">修改</el-button> -->
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['materials:materialIssue:remove']"
|
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['materials:materialIssue:remove']"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
>
|
>
|
||||||
@ -85,9 +85,10 @@
|
|||||||
<el-input v-model="form.projectName" placeholder="请输入工程名称" />
|
<el-input v-model="form.projectName" placeholder="请输入工程名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="24">
|
||||||
|
<!-- 设备材料名称:从数量验收列表自动生成,禁用手动输入 -->
|
||||||
<el-form-item label="设备材料名称" prop="materialName">
|
<el-form-item label="设备材料名称" prop="materialName">
|
||||||
<el-input v-model="form.materialName" placeholder="请输入设备材料名称" />
|
<el-input v-model="form.materialName" placeholder="由数量验收列表中的名称自动生成" disabled style="cursor: not-allowed" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -129,8 +130,8 @@
|
|||||||
:prop="`itemList.${index}.name`"
|
:prop="`itemList.${index}.name`"
|
||||||
:rules="[{ required: true, message: '名称不能为空', trigger: 'blur' }]"
|
:rules="[{ required: true, message: '名称不能为空', trigger: 'blur' }]"
|
||||||
>
|
>
|
||||||
<el-select v-model="item.name" placeholder="请选择名称" @change="(value) => getNameChange(value, index, item)">
|
<el-select v-model="item.inventoryId" placeholder="请选择名称" @change="(value) => getNameChange(value, index, item)">
|
||||||
<el-option v-for="item in optionsName" :key="item.id" :label="item.materialsName" :value="item.id" />
|
<el-option v-for="opt in optionsName" :key="opt.id" :label="opt.materialsName" :value="opt.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -140,7 +141,7 @@
|
|||||||
:prop="`itemList.${index}.specification`"
|
:prop="`itemList.${index}.specification`"
|
||||||
:rules="[{ required: true, message: '规格不能为空', trigger: 'blur' }]"
|
:rules="[{ required: true, message: '规格不能为空', trigger: 'blur' }]"
|
||||||
>
|
>
|
||||||
<el-input v-model="item.specification" placeholder="请输入规格" />
|
<el-input disabled v-model="item.specification" placeholder="请输入规格" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -149,41 +150,51 @@
|
|||||||
:prop="`itemList.${index}.unit`"
|
:prop="`itemList.${index}.unit`"
|
||||||
:rules="[{ required: true, message: '单位不能为空', trigger: 'blur' }]"
|
:rules="[{ required: true, message: '单位不能为空', trigger: 'blur' }]"
|
||||||
>
|
>
|
||||||
<el-input v-model="item.unit" placeholder="请输入单位" />
|
<el-input disabled v-model="item.unit" placeholder="请输入单位" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<!-- <el-col :span="12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="库存"
|
label="库存"
|
||||||
:prop="`itemList.${index}.stockQuantity`"
|
:prop="`itemList.${index}.stockQuantity`"
|
||||||
:rules="[{ required: true, message: '库存不能为空', trigger: 'blur' }]"
|
:rules="[
|
||||||
|
{ required: true, message: '库存不能为空', trigger: 'blur' },
|
||||||
|
{ type: 'number', min: 0, message: '库存不能小于0', trigger: ['blur', 'change'] }
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
<el-input v-model="item.stockQuantity" placeholder="请输入库存" />
|
<el-input
|
||||||
|
v-model.number="item.stockQuantity"
|
||||||
|
placeholder="请输入库存"
|
||||||
|
@input="handleStockChange(index)"
|
||||||
|
@blur="handleStockChange(index)"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col> -->
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="领取" :prop="`itemList.${index}.issuedQuantity`">
|
||||||
|
<el-input
|
||||||
|
v-model.number="item.issuedQuantity"
|
||||||
|
disabled
|
||||||
|
placeholder="请输入领取数量"
|
||||||
|
@input="handleIssuedChange(index)"
|
||||||
|
@blur="handleIssuedChange(index)"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<!-- <el-col :span="12">
|
||||||
<el-form-item
|
|
||||||
label="领取"
|
|
||||||
:prop="`itemList.${index}.issuedQuantity`"
|
|
||||||
:rules="[{ required: true, message: '领取数量不能为空', trigger: 'blur' }]"
|
|
||||||
>
|
|
||||||
<el-input v-model="item.issuedQuantity" placeholder="请输入领取数量" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="剩余"
|
label="剩余"
|
||||||
:prop="`itemList.${index}.remainingQuantity`"
|
:prop="`itemList.${index}.remainingQuantity`"
|
||||||
:rules="[{ required: true, message: '剩余数量不能为空', trigger: 'blur' }]"
|
:rules="[{ required: true, message: '剩余数量不能为空', trigger: 'blur' }]"
|
||||||
>
|
>
|
||||||
<el-input v-model="item.remainingQuantity" placeholder="请输入剩余数量" />
|
<el-input v-model.number="item.remainingQuantity" placeholder="请输入剩余数量" readonly />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-form-item label="备注" :prop="`itemList.${index}.remark`">
|
||||||
<el-input v-model="item.remark" placeholder="请输入内容" />
|
<el-input v-model="item.remark" placeholder="请输入内容" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col> -->
|
||||||
<el-col :span="12" v-if="form.itemList.length > 1">
|
<el-col :span="12" v-if="form.itemList.length > 1">
|
||||||
<div class="item-actions">
|
<div class="item-actions">
|
||||||
<el-button type="danger" link @click="removeItem(index)" icon="Delete">删除</el-button>
|
<el-button type="danger" link @click="removeItem(index)" icon="Delete">删除</el-button>
|
||||||
@ -242,12 +253,16 @@ import {
|
|||||||
delMaterialIssue,
|
delMaterialIssue,
|
||||||
addMaterialIssue,
|
addMaterialIssue,
|
||||||
updateMaterialIssue,
|
updateMaterialIssue,
|
||||||
|
inventoryList,
|
||||||
getMaterialName
|
getMaterialName
|
||||||
} from '@/api/materials/materialIssue';
|
} from '@/api/materials/materialIssue';
|
||||||
|
|
||||||
import { MaterialIssueVO, MaterialIssueQuery, MaterialIssueForm } from '@/api/materials/materialIssue/types';
|
import { MaterialIssueVO, MaterialIssueQuery, MaterialIssueForm } from '@/api/materials/materialIssue/types';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import wordllssue from './word/index.vue';
|
import wordllssue from './word/index.vue';
|
||||||
|
import { watch, onMounted, onUnmounted, ref, reactive, computed, getCurrentInstance } from 'vue';
|
||||||
|
import type { ComponentInternalInstance, ElFormInstance, DialogOption } from 'element-plus';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
// 获取用户 store
|
// 获取用户 store
|
||||||
const userStore = useUserStoreHook();
|
const userStore = useUserStoreHook();
|
||||||
@ -265,6 +280,8 @@ const total = ref(0);
|
|||||||
const wordllssueRef = ref<InstanceType<typeof wordllssue>>();
|
const wordllssueRef = ref<InstanceType<typeof wordllssue>>();
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const materialIssueFormRef = ref<ElFormInstance>();
|
const materialIssueFormRef = ref<ElFormInstance>();
|
||||||
|
// 存储每个条目的watch停止函数
|
||||||
|
const itemWatchStopFns = ref<Array<() => void>>([]);
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
@ -279,7 +296,7 @@ const getInitFormData = () => {
|
|||||||
materialSource: '1',
|
materialSource: '1',
|
||||||
formCode: undefined,
|
formCode: undefined,
|
||||||
projectName: undefined,
|
projectName: undefined,
|
||||||
materialName: undefined,
|
materialName: '', // 初始化为空字符串
|
||||||
orderingUnit: undefined,
|
orderingUnit: undefined,
|
||||||
supplierUnit: undefined,
|
supplierUnit: undefined,
|
||||||
issueUnit: undefined,
|
issueUnit: undefined,
|
||||||
@ -302,13 +319,15 @@ const getInitFormData = () => {
|
|||||||
stockQuantity: undefined,
|
stockQuantity: undefined,
|
||||||
issuedQuantity: undefined,
|
issuedQuantity: undefined,
|
||||||
remainingQuantity: undefined,
|
remainingQuantity: undefined,
|
||||||
name: undefined,
|
name: undefined, // 数量验收的名称
|
||||||
remark: undefined
|
remark: undefined,
|
||||||
|
materialsId: undefined
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
const data = reactive<PageData<MaterialIssueForm, MaterialIssueQuery>>({
|
|
||||||
|
const data = reactive({
|
||||||
form: getInitFormData(),
|
form: getInitFormData(),
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
@ -326,43 +345,127 @@ const data = reactive<PageData<MaterialIssueForm, MaterialIssueQuery>>({
|
|||||||
params: {}
|
params: {}
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
id: [{ required: true, message: '主键id不能为空', trigger: 'blur' }]
|
formCode: [{ required: true, message: '请输入表单编号', trigger: 'blur' }],
|
||||||
|
projectName: [{ required: true, message: '请输入工程名称', trigger: 'blur' }],
|
||||||
|
materialName: [{ required: true, message: '请先在数量验收列表中选择名称', trigger: 'blur' }], // 确保有名称生成
|
||||||
|
orderingUnit: [{ required: true, message: '请输入订货单位', trigger: 'blur' }],
|
||||||
|
supplierUnit: [{ required: true, message: '请输入供货单位', trigger: 'blur' }],
|
||||||
|
issueUnit: [{ required: true, message: '请输入领料单位', trigger: 'blur' }],
|
||||||
|
storageUnit: [{ required: true, message: '请输入保管单位', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryParams, form, rules } = toRefs(data);
|
const { queryParams, form, rules } = toRefs(data);
|
||||||
|
const optionsName: any = ref([]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核心函数:从数量验收列表提取名称,用逗号拼接生成设备材料名称
|
||||||
|
*/
|
||||||
|
const computeMaterialName = () => {
|
||||||
|
if (!form.value.itemList || form.value.itemList.length === 0) {
|
||||||
|
form.value.materialName = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 过滤空名称,去重(可选,根据业务需求决定是否去重)
|
||||||
|
const validNames = form.value.itemList
|
||||||
|
.filter((item) => item.name && item.name.trim() !== '')
|
||||||
|
.map((item) => item.name.trim())
|
||||||
|
.filter((name, index, self) => self.indexOf(name) === index); // 去重(如需保留重复则删除这行)
|
||||||
|
|
||||||
|
form.value.materialName = validNames.join(',');
|
||||||
|
};
|
||||||
|
|
||||||
/** 查询物料领料单列表 */
|
/** 查询物料领料单列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
try {
|
||||||
const res = await listMaterialIssue(queryParams.value);
|
const res = await listMaterialIssue(queryParams.value);
|
||||||
materialIssueList.value = res.rows;
|
materialIssueList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
};
|
|
||||||
const optionsName: any = ref([]);
|
|
||||||
|
|
||||||
//获取一起名称
|
|
||||||
const getName = async () => {
|
|
||||||
const res = await getMaterialName(currentProject.value.id);
|
|
||||||
console.log(res);
|
|
||||||
if (res.code == 200) {
|
|
||||||
optionsName.value = res.data;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取材料名称列表
|
||||||
|
const getName = async () => {
|
||||||
|
try {
|
||||||
|
const res = await inventoryList(currentProject.value.id);
|
||||||
|
console.log(res);
|
||||||
|
|
||||||
|
if (res.code == 200) {
|
||||||
|
optionsName.value = res.data;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('获取材料名称失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 材料名称选择变化处理(修改select的value为名称,而非ID)
|
||||||
const getNameChange = (value, index, item) => {
|
const getNameChange = (value, index, item) => {
|
||||||
// 这里可以添加处理逻辑
|
const selected = optionsName.value.find((opt) => opt.id === value);
|
||||||
console.log(value);
|
if (selected) {
|
||||||
|
item.name = selected.materialsName; // 直接赋值名称
|
||||||
|
item.materialsId = selected.id; // 保留ID用于后端
|
||||||
|
item.specification = selected.typeSpecificationName;
|
||||||
|
item.unit = selected.weightId;
|
||||||
|
item.issuedQuantity = selected.number;
|
||||||
|
item.stockQuantity = Number(selected.inventoryNumber) || 0;
|
||||||
|
// calculateRemaining(index); // 计算剩余数量
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const data = optionsName.value.find((item) => item.id == value);
|
/** 验证领取数量不能超过库存 */
|
||||||
console.log(data);
|
const validateIssuedQuantity = (rule, value, callback, index) => {
|
||||||
|
const item = form.value.itemList[index];
|
||||||
|
const stock = Number(item.stockQuantity) || 0;
|
||||||
|
const issued = Number(value) || 0;
|
||||||
|
|
||||||
form.value.itemList[index].name = data.materialsName;
|
if (stock === 0) {
|
||||||
form.value.itemList[index].materialsId = data.id;
|
callback();
|
||||||
form.value.itemList[index].specification = data.typeSpecificationName;
|
return;
|
||||||
form.value.itemList[index].unit = data.weightId;
|
}
|
||||||
form.value.itemList[index].stockQuantity = data.inventoryNumber;
|
|
||||||
|
if (issued > stock) {
|
||||||
|
callback(new Error(`领取数量不能超过库存(${stock})`));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 计算剩余数量(库存 - 领取数量) */
|
||||||
|
const calculateRemaining = (index: number) => {
|
||||||
|
const item = form.value.itemList[index];
|
||||||
|
const stock = Number(item.stockQuantity) || 0;
|
||||||
|
const issued = Number(item.issuedQuantity) || 0;
|
||||||
|
|
||||||
|
// 确保领取数量不超过库存
|
||||||
|
if (issued > stock) {
|
||||||
|
item.issuedQuantity = stock;
|
||||||
|
proxy?.$modal.msgWarning(`领取数量不能超过库存(${stock}),已自动调整`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算剩余数量
|
||||||
|
item.remainingQuantity = stock - (item.issuedQuantity || 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 库存变化时重新计算剩余数量 */
|
||||||
|
const handleStockChange = (index: number) => {
|
||||||
|
calculateRemaining(index);
|
||||||
|
// 触发验证
|
||||||
|
if (materialIssueFormRef.value) {
|
||||||
|
materialIssueFormRef.value.validateField(`itemList.${index}.issuedQuantity`);
|
||||||
|
materialIssueFormRef.value.validateField(`itemList.${index}.remainingQuantity`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 领取数量变化时重新计算剩余数量 */
|
||||||
|
const handleIssuedChange = (index: number) => {
|
||||||
|
calculateRemaining(index);
|
||||||
|
// 触发验证
|
||||||
|
if (materialIssueFormRef.value) {
|
||||||
|
materialIssueFormRef.value.validateField(`itemList.${index}.remainingQuantity`);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
@ -373,8 +476,38 @@ const cancel = () => {
|
|||||||
|
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
|
// 停止所有监听
|
||||||
|
itemWatchStopFns.value.forEach((stop) => stop());
|
||||||
|
itemWatchStopFns.value = [];
|
||||||
|
|
||||||
form.value = getInitFormData();
|
form.value = getInitFormData();
|
||||||
materialIssueFormRef.value?.resetFields();
|
materialIssueFormRef.value?.resetFields();
|
||||||
|
|
||||||
|
// 重新监听初始条目
|
||||||
|
if (form.value.itemList.length > 0) {
|
||||||
|
watchItemChanges(0);
|
||||||
|
}
|
||||||
|
// 初始计算一次材料名称
|
||||||
|
computeMaterialName();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 监听条目变化,自动计算剩余数量 */
|
||||||
|
const watchItemChanges = (index: number) => {
|
||||||
|
// 停止已有监听
|
||||||
|
if (itemWatchStopFns.value[index]) {
|
||||||
|
itemWatchStopFns.value[index]();
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 监听库存和领取数量变化
|
||||||
|
// const stop = watch(
|
||||||
|
// () => [form.value.itemList[index].stockQuantity, form.value.itemList[index].issuedQuantity],
|
||||||
|
// () => {
|
||||||
|
// calculateRemaining(index);
|
||||||
|
// },
|
||||||
|
// { immediate: true }
|
||||||
|
// );
|
||||||
|
|
||||||
|
itemWatchStopFns.value[index] = stop;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
@ -401,16 +534,58 @@ const handleAdd = () => {
|
|||||||
reset();
|
reset();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = '添加物料领料单';
|
dialog.title = '添加物料领料单';
|
||||||
|
// 新增时初始计算材料名称
|
||||||
|
computeMaterialName();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: MaterialIssueVO) => {
|
const handleUpdate = async (row?: MaterialIssueVO) => {
|
||||||
reset();
|
reset();
|
||||||
const _id = row?.id || ids.value[0];
|
const _id = row?.id || ids.value[0];
|
||||||
|
try {
|
||||||
const res = await getMaterialIssue(_id);
|
const res = await getMaterialIssue(_id);
|
||||||
Object.assign(form.value, res.data);
|
Object.assign(form.value, res.data);
|
||||||
|
|
||||||
|
// 确保itemList存在且格式正确
|
||||||
|
if (!form.value.itemList) {
|
||||||
|
form.value.itemList = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换数据类型并计算剩余数量
|
||||||
|
form.value.itemList = form.value.itemList.map((item) => ({
|
||||||
|
...item,
|
||||||
|
stockQuantity: Number(item.stockQuantity) || 0,
|
||||||
|
issuedQuantity: Number(item.issuedQuantity) || 0,
|
||||||
|
remainingQuantity: Number(item.remainingQuantity) || 0,
|
||||||
|
name: item.name || '' // 确保名称不为undefined
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 为每个条目添加监听并强制计算剩余数量
|
||||||
|
form.value.itemList.forEach((_, index) => {
|
||||||
|
watchItemChanges(index);
|
||||||
|
calculateRemaining(index);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 关键:编辑时从itemList重新计算设备材料名称(覆盖后端返回的旧值)
|
||||||
|
computeMaterialName();
|
||||||
|
|
||||||
|
// 手动触发一次验证
|
||||||
|
setTimeout(() => {
|
||||||
|
if (materialIssueFormRef.value) {
|
||||||
|
form.value.itemList.forEach((_, index) => {
|
||||||
|
materialIssueFormRef.value.validateField(`itemList.${index}.issuedQuantity`);
|
||||||
|
materialIssueFormRef.value.validateField(`itemList.${index}.remainingQuantity`);
|
||||||
|
});
|
||||||
|
// 验证设备材料名称
|
||||||
|
materialIssueFormRef.value.validateField('materialName');
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = '修改物料领料单';
|
dialog.title = '修改物料领料单';
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('获取详情失败');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
@ -418,21 +593,38 @@ const submitForm = () => {
|
|||||||
materialIssueFormRef.value?.validate(async (valid: boolean) => {
|
materialIssueFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
|
try {
|
||||||
|
// 处理提交数据,确保数量为数字类型
|
||||||
|
const submitData = {
|
||||||
|
...form.value,
|
||||||
|
itemList: form.value.itemList.map((item) => ({
|
||||||
|
...item,
|
||||||
|
stockQuantity: Number(item.stockQuantity),
|
||||||
|
issuedQuantity: Number(item.issuedQuantity),
|
||||||
|
remainingQuantity: Number(item.remainingQuantity)
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
if (form.value.id) {
|
if (form.value.id) {
|
||||||
await updateMaterialIssue(form.value).finally(() => (buttonLoading.value = false));
|
await updateMaterialIssue(submitData);
|
||||||
} else {
|
} else {
|
||||||
await addMaterialIssue(form.value).finally(() => (buttonLoading.value = false));
|
await addMaterialIssue(submitData);
|
||||||
}
|
}
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('操作失败');
|
||||||
|
} finally {
|
||||||
|
buttonLoading.value = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 添加数量验收条目
|
// 添加数量验收条目
|
||||||
const addItem = () => {
|
const addItem = () => {
|
||||||
form.value.itemList.push({
|
const newItem = {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
specification: undefined,
|
specification: undefined,
|
||||||
unit: undefined,
|
unit: undefined,
|
||||||
@ -440,46 +632,81 @@ const addItem = () => {
|
|||||||
issuedQuantity: undefined,
|
issuedQuantity: undefined,
|
||||||
remainingQuantity: undefined,
|
remainingQuantity: undefined,
|
||||||
name: undefined,
|
name: undefined,
|
||||||
remark: undefined
|
remark: undefined,
|
||||||
});
|
materialsId: undefined
|
||||||
|
};
|
||||||
|
form.value.itemList.push(newItem);
|
||||||
|
// 监听新条目
|
||||||
|
watchItemChanges(form.value.itemList.length - 1);
|
||||||
|
// 添加后重新计算材料名称
|
||||||
|
computeMaterialName();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 删除数量验收条目
|
// 删除数量验收条目
|
||||||
const removeItem = (index: number) => {
|
const removeItem = (index: number) => {
|
||||||
if (form.value.itemList.length > 1) {
|
if (form.value.itemList.length > 1) {
|
||||||
|
// 停止该条目的监听
|
||||||
|
if (itemWatchStopFns.value[index]) {
|
||||||
|
itemWatchStopFns.value[index]();
|
||||||
|
}
|
||||||
form.value.itemList.splice(index, 1);
|
form.value.itemList.splice(index, 1);
|
||||||
|
itemWatchStopFns.value.splice(index, 1);
|
||||||
|
// 删除后重新计算材料名称
|
||||||
|
computeMaterialName();
|
||||||
} else {
|
} else {
|
||||||
proxy?.$modal.msgWarning('至少需要保留一条数量验收记录');
|
proxy?.$modal.msgWarning('至少需要保留一条数量验收记录');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: MaterialIssueVO) => {
|
const handleDelete = async (row?: MaterialIssueVO) => {
|
||||||
const _ids = row?.id || ids.value;
|
const _ids = row?.id || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除物料领料单编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
try {
|
||||||
|
await proxy?.$modal.confirm(`是否确认删除物料领料单编号为"${_ids}"的数据项?`);
|
||||||
await delMaterialIssue(_ids);
|
await delMaterialIssue(_ids);
|
||||||
proxy?.$modal.msgSuccess('删除成功');
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
await getList();
|
await getList();
|
||||||
|
} catch (error) {
|
||||||
|
// 取消删除不提示
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleView = (row) => {
|
const handleView = (row) => {
|
||||||
// 查看详情
|
// 查看详情
|
||||||
wordllssueRef.value?.openDialog(row);
|
wordllssueRef.value?.openDialog(row);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 关键:监听数量验收列表变化,实时更新设备材料名称
|
||||||
|
watch(
|
||||||
|
() => form.value.itemList,
|
||||||
|
() => {
|
||||||
|
computeMaterialName();
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true } // deep监听数组内部变化,immediate初始执行
|
||||||
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
getName();
|
getName();
|
||||||
});
|
});
|
||||||
//监听项目id刷新数据
|
|
||||||
|
// 监听项目id刷新数据
|
||||||
const listeningProject = watch(
|
const listeningProject = watch(
|
||||||
() => currentProject.value?.id,
|
() => currentProject.value?.id,
|
||||||
(nid, oid) => {
|
(nid) => {
|
||||||
queryParams.value.projectId = nid;
|
queryParams.value.projectId = nid;
|
||||||
form.value.projectId = nid;
|
form.value.projectId = nid;
|
||||||
getList();
|
getList();
|
||||||
|
getName();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
listeningProject();
|
listeningProject();
|
||||||
|
// 清理所有监听
|
||||||
|
itemWatchStopFns.value.forEach((stop) => stop());
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
@ -57,16 +57,15 @@
|
|||||||
<el-table-column label="备注" align="center" prop="remark" />
|
<el-table-column label="备注" align="center" prop="remark" />
|
||||||
<el-table-column label="操作" align="center" min-width="120" fixed="right">
|
<el-table-column label="操作" align="center" min-width="120" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="查看" placement="top">
|
<!-- <el-button link type="primary" icon="edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materialReceive:edit']"
|
||||||
|
>修改</el-button
|
||||||
|
> -->
|
||||||
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['materials:materialReceive:query']"
|
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['materials:materialReceive:query']"
|
||||||
>查看</el-button
|
>查看</el-button
|
||||||
>
|
>
|
||||||
</el-tooltip>
|
|
||||||
<el-tooltip content="删除" placement="top">
|
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['materials:materialReceive:remove']"
|
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['materials:materialReceive:remove']"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
>
|
>
|
||||||
</el-tooltip>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -74,7 +73,15 @@
|
|||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 添加或修改物料接收单对话框 -->
|
<!-- 添加或修改物料接收单对话框 -->
|
||||||
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
|
<el-dialog
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
draggable
|
||||||
|
:title="dialog.title"
|
||||||
|
v-model="dialog.visible"
|
||||||
|
width="800px"
|
||||||
|
append-to-body
|
||||||
|
>
|
||||||
<el-form ref="materialReceiveFormRef" :model="form" :rules="rules" label-width="110px">
|
<el-form ref="materialReceiveFormRef" :model="form" :rules="rules" label-width="110px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -122,7 +129,6 @@
|
|||||||
:value="item.contractCode"
|
:value="item.contractCode"
|
||||||
></el-option>
|
></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
<!-- <el-input v-model="form.contractName" placeholder="请输入合同名称" /> -->
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
@ -131,14 +137,13 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<!-- 数量验收区域(修复v-for key问题) -->
|
<!-- 数量验收区域 -->
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
<div class="detail-header">
|
<div class="detail-header">
|
||||||
<span>数量验收</span>
|
<span>数量验收</span>
|
||||||
<el-button type="primary" v-if="form.materialSource == '1'" link @click="addItem" icon="Plus">添加数量验收</el-button>
|
<el-button type="primary" v-if="form.materialSource == '1'" link @click="addItem" icon="Plus">添加数量验收</el-button>
|
||||||
</div>
|
</div>
|
||||||
<!-- 关键修复:v-for key改为item.id(唯一标识),而非index -->
|
|
||||||
<div v-for="(item, index) in form.itemList" :key="item.id" class="detail-item">
|
<div v-for="(item, index) in form.itemList" :key="item.id" class="detail-item">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -161,21 +166,27 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item
|
<el-form-item label="数量" :prop="`itemList.${index}.quantity`" :rules="rules.quantityRule" ref="quantityFormItemRefs[index]">
|
||||||
label="数量"
|
<el-input
|
||||||
:prop="`itemList.${index}.quantity`"
|
:disabled="form.materialSource == '2'"
|
||||||
:rules="{ required: true, message: '数量不能为空', trigger: 'blur' }"
|
type="number"
|
||||||
>
|
v-model.number="item.quantity"
|
||||||
<el-input :disabled="form.materialSource == '2'" type="number" v-model="item.quantity" placeholder="请输入数量" />
|
placeholder="请输入数量"
|
||||||
|
min="0"
|
||||||
|
@input="handleQuantityInput(index)"
|
||||||
|
@blur="handleQuantityBlur(index)"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item
|
<el-form-item label="验收" :prop="`itemList.${index}.acceptedQuantity`" :rules="rules.acceptedQuantityRule">
|
||||||
label="验收"
|
<el-input
|
||||||
:prop="`itemList.${index}.acceptedQuantity`"
|
type="number"
|
||||||
:rules="{ required: true, message: '验收数量不能为空', trigger: 'blur' }"
|
v-model.number="item.acceptedQuantity"
|
||||||
>
|
placeholder="请输入验收"
|
||||||
<el-input type="number" v-model="item.acceptedQuantity" placeholder="请输入验收" />
|
min="0"
|
||||||
|
@input="handleAcceptedInput(index)"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -184,13 +195,13 @@
|
|||||||
:prop="`itemList.${index}.shortageQuantity`"
|
:prop="`itemList.${index}.shortageQuantity`"
|
||||||
:rules="{ required: true, message: '缺件数量不能为空', trigger: 'blur' }"
|
:rules="{ required: true, message: '缺件数量不能为空', trigger: 'blur' }"
|
||||||
>
|
>
|
||||||
<el-input type="number" v-model="item.shortageQuantity" placeholder="自动计算(数量-验收数量)" readonly />
|
<el-input type="number" min="0" v-model="item.shortageQuantity" placeholder="自动计算" readonly />
|
||||||
<span class="tips">*自动计算(数量-验收数量)</span>
|
<span class="tips">*自动计算(数量-验收数量)</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="24">
|
||||||
<el-form-item label="备注" :prop="`itemList.${index}.remark`">
|
<el-form-item label="备注" :prop="`itemList.${index}.remark`">
|
||||||
<el-input v-model="item.remark" placeholder="请输入备注" />
|
<el-input v-model="item.remark" type="textarea" placeholder="请输入备注" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" v-if="form.itemList.length > 1 && form.materialSource == '1'">
|
<el-col :span="12" v-if="form.itemList.length > 1 && form.materialSource == '1'">
|
||||||
@ -205,26 +216,26 @@
|
|||||||
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="合格证文件" prop="certCountFileId">
|
<el-form-item label="合格证文件" prop="certCountFileId">
|
||||||
<file-upload :isShowTip="false" v-model="form.certCountFileId" />
|
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.certCountFileId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="出厂报告文件" prop="reportCountFileId">
|
<el-form-item label="出厂报告文件" prop="reportCountFileId">
|
||||||
<file-upload :isShowTip="false" v-model="form.reportCountFileId" />
|
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.reportCountFileId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="技术资料文件" prop="techDocCountFileId">
|
<el-form-item label="技术资料文件" prop="techDocCountFileId">
|
||||||
<file-upload :isShowTip="false" v-model="form.techDocCountFileId" />
|
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.techDocCountFileId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="厂家资质文件" prop="licenseCountFileId">
|
<el-form-item label="厂家资质文件" prop="licenseCountFileId">
|
||||||
<file-upload :isShowTip="false" v-model="form.licenseCountFileId" />
|
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.licenseCountFileId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<span style="color: #ff0000ab; margin-bottom: 10px; display: block">注意:请上传doc/xls/ppt/txt/pdf/png/jpg/jpeg/zip格式文件</span>
|
<span style="color: #ff0000ab; margin-bottom: 10px; display: block">注意:pdf/png/jpg/jpeg格式文件</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-form-item label="备注" prop="remark">
|
||||||
@ -258,7 +269,7 @@ import { useUserStoreHook } from '@/store/modules/user';
|
|||||||
import wordllReceive from './word/index.vue';
|
import wordllReceive from './word/index.vue';
|
||||||
import { listPurchaseDoc, purchaseDocPlanList } from '@/api/materials/purchaseDoc';
|
import { listPurchaseDoc, purchaseDocPlanList } from '@/api/materials/purchaseDoc';
|
||||||
import { watch, onMounted, onUnmounted, ref, reactive, computed, toRefs, getCurrentInstance } from 'vue';
|
import { watch, onMounted, onUnmounted, ref, reactive, computed, toRefs, getCurrentInstance } from 'vue';
|
||||||
import type { ComponentInternalInstance, ElFormInstance, DialogOption } from 'element-plus';
|
import type { ComponentInternalInstance, ElFormInstance, DialogOption, ElFormItem } from 'element-plus';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { storage_type } = toRefs<any>(proxy?.useDict('storage_type'));
|
const { storage_type } = toRefs<any>(proxy?.useDict('storage_type'));
|
||||||
@ -266,8 +277,10 @@ const userStore = useUserStoreHook();
|
|||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
const wordllReceiveRef = ref<InstanceType<typeof wordllReceive>>();
|
const wordllReceiveRef = ref<InstanceType<typeof wordllReceive>>();
|
||||||
|
|
||||||
// 核心修复1:存储每个验收条目的watch停止函数,避免内存泄漏
|
// 存储每个验收条目的watch停止函数
|
||||||
const itemWatchStopFns = ref<Array<() => void>>([]);
|
const itemWatchStopFns = ref<Array<() => void>>([]);
|
||||||
|
// 存储数量表单项的引用,用于手动触发验证
|
||||||
|
const quantityFormItemRefs = ref<(ElFormItem | null)[]>([]);
|
||||||
|
|
||||||
// 列表数据
|
// 列表数据
|
||||||
const materialReceiveList = ref<MaterialReceiveVO[]>([]);
|
const materialReceiveList = ref<MaterialReceiveVO[]>([]);
|
||||||
@ -285,18 +298,19 @@ const materialReceiveFormRef = ref<ElFormInstance>();
|
|||||||
const purchaseDocList = ref([]); // 物资采购单列表
|
const purchaseDocList = ref([]); // 物资采购单列表
|
||||||
const purchaseMap = new Map(); // 采购单映射(id -> 采购单对象)
|
const purchaseMap = new Map(); // 采购单映射(id -> 采购单对象)
|
||||||
const contractNameList = ref([]); //合同列表
|
const contractNameList = ref([]); //合同列表
|
||||||
|
|
||||||
// 对话框配置
|
// 对话框配置
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
title: ''
|
title: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
// 生成验收条目唯一ID(用于v-for key)
|
// 生成验收条目唯一ID
|
||||||
const generateItemId = () => {
|
const generateItemId = () => {
|
||||||
return Date.now() + Math.random().toString(36).substr(2, 9);
|
return Date.now() + Math.random().toString(36).substr(2, 9);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化表单数据(修复:给验收条目添加唯一ID)
|
// 初始化表单数据
|
||||||
const getInitFormData = (): MaterialReceiveForm => {
|
const getInitFormData = (): MaterialReceiveForm => {
|
||||||
return {
|
return {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
@ -323,7 +337,7 @@ const getInitFormData = (): MaterialReceiveForm => {
|
|||||||
docCode: undefined,
|
docCode: undefined,
|
||||||
itemList: [
|
itemList: [
|
||||||
{
|
{
|
||||||
id: generateItemId(), // 新增:唯一ID,解决v-for渲染问题
|
id: generateItemId(),
|
||||||
name: undefined,
|
name: undefined,
|
||||||
specification: undefined,
|
specification: undefined,
|
||||||
unit: undefined,
|
unit: undefined,
|
||||||
@ -357,7 +371,38 @@ const data = reactive({
|
|||||||
formCode: [{ required: true, message: '请输入表单编号', trigger: 'blur' }],
|
formCode: [{ required: true, message: '请输入表单编号', trigger: 'blur' }],
|
||||||
docId: [{ required: true, message: '请选择物资采购单', trigger: 'change' }],
|
docId: [{ required: true, message: '请选择物资采购单', trigger: 'change' }],
|
||||||
supplierUnit: [{ required: true, message: '请输入供货单位', trigger: 'blur' }],
|
supplierUnit: [{ required: true, message: '请输入供货单位', trigger: 'blur' }],
|
||||||
orderingUnit: [{ required: true, message: '请输入订货单位', trigger: 'blur' }]
|
orderingUnit: [{ required: true, message: '请输入订货单位', trigger: 'blur' }],
|
||||||
|
// 数量校验规则:确保触发时机包含change,且类型为number
|
||||||
|
quantityRule: [
|
||||||
|
{ required: true, message: '数量不能为空', trigger: ['blur', 'change'] },
|
||||||
|
{ type: 'number', min: 0, message: '数量不能小于0', trigger: ['blur', 'change'] }
|
||||||
|
],
|
||||||
|
// 验收数量规则(允许≤数量)
|
||||||
|
acceptedQuantityRule: [
|
||||||
|
{ required: true, message: '验收数量不能为空', trigger: ['blur', 'change'] },
|
||||||
|
{ type: 'number', min: 0, message: '验收数量不能小于0', trigger: ['blur', 'change'] },
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
const prop = rule.field;
|
||||||
|
const index = Number(prop.split('.')[1]);
|
||||||
|
const quantity = Number(form.value.itemList[index].quantity) || 0;
|
||||||
|
|
||||||
|
// 数量未填写时不验证大小关系;数量有值但验收数量未填时也不阻断(由required规则处理)
|
||||||
|
if (form.value.itemList[index].quantity === undefined || form.value.itemList[index].quantity === null) {
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 处理value为undefined/null的情况(避免Number(undefined)转为NaN)
|
||||||
|
const acceptedVal = Number(value) || 0;
|
||||||
|
if (acceptedVal > quantity) {
|
||||||
|
callback(new Error('验收数量必须小于等于数量'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: ['blur', 'change']
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -374,25 +419,29 @@ const getList = async () => {
|
|||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取合同列表数据
|
// 获取合同列表数据
|
||||||
const getContractList = async () => {
|
const getContractList = async () => {
|
||||||
let res = await getContractNameList(currentProject.value?.id);
|
let res = await getContractNameList(currentProject.value?.id);
|
||||||
contractNameList.value = res.rows;
|
contractNameList.value = res.rows;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 表单重置(修复:清理验收条目监听) */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
// 停止所有验收条目的watch监听
|
// 停止所有验收条目的watch监听
|
||||||
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
||||||
itemWatchStopFns.value = [];
|
itemWatchStopFns.value = [];
|
||||||
|
|
||||||
form.value = getInitFormData();
|
form.value = getInitFormData();
|
||||||
materialReceiveFormRef.value?.resetFields();
|
if (materialReceiveFormRef.value) {
|
||||||
|
materialReceiveFormRef.value.resetFields();
|
||||||
|
}
|
||||||
|
|
||||||
// 重新监听初始条目
|
// 重新监听初始条目
|
||||||
if (form.value.itemList.length > 0) {
|
if (form.value.itemList.length > 0) {
|
||||||
@ -408,7 +457,9 @@ const handleQuery = () => {
|
|||||||
|
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
if (queryFormRef.value) {
|
||||||
|
queryFormRef.value.resetFields();
|
||||||
|
}
|
||||||
handleQuery();
|
handleQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -427,24 +478,35 @@ const handleAdd = () => {
|
|||||||
form.value.projectName = currentProject.value?.name;
|
form.value.projectName = currentProject.value?.name;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 修改按钮操作(修复:清理旧监听+添加唯一ID) */
|
/** 修改按钮操作(核心修复:赋值后主动触发验证+数据类型转换) */
|
||||||
const handleUpdate = async (row?: MaterialReceiveVO) => {
|
const handleUpdate = async (row?: MaterialReceiveVO) => {
|
||||||
reset();
|
reset();
|
||||||
const _id = row?.id || ids.value[0];
|
const _id = row?.id || ids.value[0];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await getMaterialReceive(_id);
|
const res = await getMaterialReceive(_id);
|
||||||
// 给验收条目补充唯一ID(避免后端返回无ID)
|
|
||||||
const formData = res.data;
|
const formData = res.data;
|
||||||
|
|
||||||
|
// 修复1:处理itemList数据类型,确保数量/验收数量为数字(避免字符串与number规则冲突)
|
||||||
formData.itemList = formData.itemList.map((item) => ({
|
formData.itemList = formData.itemList.map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
id: item.id || generateItemId()
|
id: item.id || generateItemId(),
|
||||||
|
quantity: item.quantity !== undefined ? Number(item.quantity) : undefined, // 转为数字
|
||||||
|
acceptedQuantity: item.acceptedQuantity !== undefined ? Number(item.acceptedQuantity) : undefined, // 转为数字
|
||||||
|
shortageQuantity: item.shortageQuantity !== undefined ? Number(item.shortageQuantity) : undefined // 转为数字
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Object.assign(form.value, formData);
|
Object.assign(form.value, formData);
|
||||||
|
|
||||||
// 重新监听所有条目
|
// 修复2:重新监听所有条目,并主动触发每个条目的验证(更新验证状态)
|
||||||
form.value.itemList.forEach((_, index) => {
|
form.value.itemList.forEach((_, index) => {
|
||||||
watchItemChanges(index);
|
watchItemChanges(index);
|
||||||
|
// 手动触发当前条目的数量、验收数量、缺件数量验证
|
||||||
|
if (materialReceiveFormRef.value) {
|
||||||
|
materialReceiveFormRef.value.validateField(`itemList.${index}.quantity`, () => {});
|
||||||
|
materialReceiveFormRef.value.validateField(`itemList.${index}.acceptedQuantity`, () => {});
|
||||||
|
materialReceiveFormRef.value.validateField(`itemList.${index}.shortageQuantity`, () => {});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
@ -460,13 +522,24 @@ const submitForm = () => {
|
|||||||
if (valid) {
|
if (valid) {
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
try {
|
try {
|
||||||
|
// 提交前确保数据类型正确(数字)
|
||||||
|
const submitForm = {
|
||||||
|
...form.value,
|
||||||
|
itemList: form.value.itemList.map((item) => ({
|
||||||
|
...item,
|
||||||
|
quantity: Number(item.quantity),
|
||||||
|
acceptedQuantity: Number(item.acceptedQuantity),
|
||||||
|
shortageQuantity: Number(item.shortageQuantity)
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
if (form.value.id) {
|
if (form.value.id) {
|
||||||
await updateMaterialReceive({ ...form.value });
|
await updateMaterialReceive(submitForm);
|
||||||
} else {
|
} else {
|
||||||
form.value.itemList.forEach((item) => {
|
submitForm.itemList.forEach((item) => {
|
||||||
delete item.id;
|
delete item.id;
|
||||||
});
|
});
|
||||||
await addMaterialReceive({ ...form.value });
|
await addMaterialReceive(submitForm);
|
||||||
}
|
}
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
@ -495,10 +568,10 @@ const handleDelete = async (row?: MaterialReceiveVO) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 添加数量验收条目(修复:添加唯一ID+监听) */
|
/** 添加数量验收条目 */
|
||||||
const addItem = () => {
|
const addItem = () => {
|
||||||
const newItem = {
|
const newItem = {
|
||||||
id: generateItemId(), // 唯一ID
|
id: generateItemId(),
|
||||||
name: undefined,
|
name: undefined,
|
||||||
specification: undefined,
|
specification: undefined,
|
||||||
unit: undefined,
|
unit: undefined,
|
||||||
@ -508,33 +581,79 @@ const addItem = () => {
|
|||||||
remark: undefined
|
remark: undefined
|
||||||
};
|
};
|
||||||
form.value.itemList.push(newItem);
|
form.value.itemList.push(newItem);
|
||||||
// 监听新条目变化
|
// 监听新条目变化并触发初始验证
|
||||||
watchItemChanges(form.value.itemList.length - 1);
|
watchItemChanges(form.value.itemList.length - 1);
|
||||||
|
validateQuantityField(form.value.itemList.length - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 监听验收条目变化,自动计算缺件数量(修复:存储停止函数) */
|
// 数量输入事件处理
|
||||||
|
const handleQuantityInput = (index: number) => {
|
||||||
|
// 确保值为数字类型
|
||||||
|
if (form.value.itemList[index].quantity !== undefined) {
|
||||||
|
form.value.itemList[index].quantity = Number(form.value.itemList[index].quantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动触发验证
|
||||||
|
validateQuantityField(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 数量失焦事件
|
||||||
|
const handleQuantityBlur = (index: number) => {
|
||||||
|
validateQuantityField(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 验收数量输入事件
|
||||||
|
const handleAcceptedInput = (index: number) => {
|
||||||
|
// 确保值为数字类型
|
||||||
|
if (form.value.itemList[index].acceptedQuantity !== undefined) {
|
||||||
|
form.value.itemList[index].acceptedQuantity = Number(form.value.itemList[index].acceptedQuantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动触发相关字段验证
|
||||||
|
validateQuantityField(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 手动验证数量和验收数量字段
|
||||||
|
const validateQuantityField = (index: number) => {
|
||||||
|
if (materialReceiveFormRef.value) {
|
||||||
|
materialReceiveFormRef.value.validateField(`itemList.${index}.quantity`, () => {});
|
||||||
|
materialReceiveFormRef.value.validateField(`itemList.${index}.acceptedQuantity`, () => {});
|
||||||
|
materialReceiveFormRef.value.validateField(`itemList.${index}.shortageQuantity`, () => {});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听条目变化,自动计算缺件数量(修复:计算后触发验证)
|
||||||
const watchItemChanges = (index: number) => {
|
const watchItemChanges = (index: number) => {
|
||||||
// 停止该索引已有的监听(避免重复监听)
|
|
||||||
if (itemWatchStopFns.value[index]) {
|
if (itemWatchStopFns.value[index]) {
|
||||||
itemWatchStopFns.value[index]();
|
itemWatchStopFns.value[index]();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听数量和验收数量变化
|
|
||||||
const stopFn = watch(
|
const stopFn = watch(
|
||||||
() => [form.value.itemList[index].quantity, form.value.itemList[index].acceptedQuantity],
|
() => [form.value.itemList[index].quantity, form.value.itemList[index].acceptedQuantity],
|
||||||
([quantity, acceptedQuantity]) => {
|
([quantity, acceptedQuantity]) => {
|
||||||
const qty = Number(quantity) || 0;
|
const qty = Number(quantity) || 0;
|
||||||
const acceptedQty = Number(acceptedQuantity) || 0;
|
let acceptedQty = Number(acceptedQuantity) || 0;
|
||||||
|
|
||||||
|
// 仅当验收数量>数量时才修正(允许等于)
|
||||||
|
if (acceptedQty > qty && qty > 0) {
|
||||||
|
acceptedQty = qty; // 修正为数量值(最大合法值)
|
||||||
|
form.value.itemList[index].acceptedQuantity = acceptedQty;
|
||||||
|
proxy?.$modal.msgWarning(`验收数量不能大于数量,已自动修正为${acceptedQty}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算缺件数量(允许为0)
|
||||||
form.value.itemList[index].shortageQuantity = qty - acceptedQty;
|
form.value.itemList[index].shortageQuantity = qty - acceptedQty;
|
||||||
|
|
||||||
|
// 修复3:计算后触发当前条目的验证,确保缺件数量状态更新
|
||||||
|
validateQuantityField(index);
|
||||||
},
|
},
|
||||||
{ immediate: true } // 初始时立即计算
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
// 存储停止函数,用于后续删除时清理
|
|
||||||
itemWatchStopFns.value[index] = stopFn;
|
itemWatchStopFns.value[index] = stopFn;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 删除数量验收条目(修复:清理监听+删除条目) */
|
/** 删除数量验收条目 */
|
||||||
const removeItem = (index: number) => {
|
const removeItem = (index: number) => {
|
||||||
if (form.value.itemList.length <= 1) {
|
if (form.value.itemList.length <= 1) {
|
||||||
proxy?.$modal.msgWarning('至少需要保留一条数量验收记录');
|
proxy?.$modal.msgWarning('至少需要保留一条数量验收记录');
|
||||||
@ -549,6 +668,7 @@ const removeItem = (index: number) => {
|
|||||||
// 删除条目和对应的停止函数
|
// 删除条目和对应的停止函数
|
||||||
form.value.itemList.splice(index, 1);
|
form.value.itemList.splice(index, 1);
|
||||||
itemWatchStopFns.value.splice(index, 1);
|
itemWatchStopFns.value.splice(index, 1);
|
||||||
|
quantityFormItemRefs.value.splice(index, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 查看详情 */
|
/** 查看详情 */
|
||||||
@ -564,7 +684,6 @@ const getlistPurchase = async () => {
|
|||||||
status: 'finish'
|
status: 'finish'
|
||||||
});
|
});
|
||||||
purchaseDocList.value = res.rows;
|
purchaseDocList.value = res.rows;
|
||||||
// 构建采购单映射
|
|
||||||
purchaseDocList.value.forEach((item) => {
|
purchaseDocList.value.forEach((item) => {
|
||||||
purchaseMap.set(item.id, item);
|
purchaseMap.set(item.id, item);
|
||||||
});
|
});
|
||||||
@ -573,7 +692,7 @@ const getlistPurchase = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 通过采购单获取需求信息(修复:清理旧监听+添加新监听) */
|
/** 通过采购单获取需求信息(修复:数据类型转换) */
|
||||||
const getdemandInfo = async (docId: string) => {
|
const getdemandInfo = async (docId: string) => {
|
||||||
if (!docId) return;
|
if (!docId) return;
|
||||||
|
|
||||||
@ -583,25 +702,25 @@ const getdemandInfo = async (docId: string) => {
|
|||||||
// 清空旧监听和条目
|
// 清空旧监听和条目
|
||||||
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
||||||
itemWatchStopFns.value = [];
|
itemWatchStopFns.value = [];
|
||||||
|
quantityFormItemRefs.value = [];
|
||||||
form.value.itemList = [];
|
form.value.itemList = [];
|
||||||
|
|
||||||
// 赋值需求数据并添加监听
|
// 赋值需求数据并添加监听(确保数量为数字)
|
||||||
res.data.forEach((item, index) => {
|
res.data.forEach((item, index) => {
|
||||||
const qty = Number(item.demandQuantity) || 0;
|
const qty = Number(item.demandQuantity) || 0;
|
||||||
const newItem = {
|
const newItem = {
|
||||||
id: generateItemId(), // 唯一ID
|
id: generateItemId(),
|
||||||
name: item.name,
|
name: item.name,
|
||||||
specification: item.specification,
|
specification: item.specification,
|
||||||
unit: item.unit,
|
unit: item.unit,
|
||||||
quantity: qty,
|
quantity: qty, // 确保数字类型
|
||||||
acceptedQuantity: 0,
|
acceptedQuantity: 0, // 初始值为0(数字)
|
||||||
shortageQuantity: qty, // 初始缺件=总数量
|
shortageQuantity: qty, // 初始缺件=数量(数字)
|
||||||
remark: item.remark,
|
remark: item.remark,
|
||||||
planId: item.id,
|
planId: item.id,
|
||||||
id: null // 保留后端需要的空id字段
|
id: null
|
||||||
};
|
};
|
||||||
form.value.itemList.push(newItem);
|
form.value.itemList.push(newItem);
|
||||||
// 监听当前条目
|
|
||||||
watchItemChanges(index);
|
watchItemChanges(index);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -621,21 +740,25 @@ const handleSelect = (val: string) => {
|
|||||||
form.value.materialName = obj.name || '';
|
form.value.materialName = obj.name || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取采购单对应的需求信息
|
|
||||||
getdemandInfo(val);
|
getdemandInfo(val);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 核心修复2:监听材料来源变化,重置数量验收列表 */
|
/** 监听材料来源变化,重置数量验收列表 */
|
||||||
watch(
|
watch(
|
||||||
() => form.value.materialSource,
|
() => form.value.materialSource,
|
||||||
(newSource, oldSource) => {
|
(newSource, oldSource) => {
|
||||||
if (newSource === oldSource) return;
|
if (newSource === oldSource) return;
|
||||||
|
|
||||||
// 1. 停止所有验收条目的监听
|
// 停止所有验收条目的监听
|
||||||
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
||||||
itemWatchStopFns.value = [];
|
itemWatchStopFns.value = [];
|
||||||
|
quantityFormItemRefs.value = [];
|
||||||
// 2. 重置数量验收列表为初始状态(1条空记录)
|
// 清空所有文件上传字段的值
|
||||||
|
form.value.certCountFileId = undefined; // 合格证文件
|
||||||
|
form.value.reportCountFileId = undefined; // 出厂报告文件
|
||||||
|
form.value.techDocCountFileId = undefined; // 技术资料文件
|
||||||
|
form.value.licenseCountFileId = undefined; // 厂家资质文件
|
||||||
|
// 重置数量验收列表为初始状态
|
||||||
form.value.itemList = [
|
form.value.itemList = [
|
||||||
{
|
{
|
||||||
id: generateItemId(),
|
id: generateItemId(),
|
||||||
@ -649,10 +772,11 @@ watch(
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
// 3. 重新监听初始条目
|
// 重新监听初始条目并触发验证
|
||||||
watchItemChanges(0);
|
watchItemChanges(0);
|
||||||
|
validateQuantityField(0);
|
||||||
|
|
||||||
// 4. 切换到乙供时,清空采购单相关数据
|
// 切换到乙供时,清空采购单相关数据
|
||||||
if (newSource === '2') {
|
if (newSource === '2') {
|
||||||
form.value.docId = undefined;
|
form.value.docId = undefined;
|
||||||
form.value.supplierUnit = undefined;
|
form.value.supplierUnit = undefined;
|
||||||
@ -668,9 +792,10 @@ onMounted(() => {
|
|||||||
getContractList();
|
getContractList();
|
||||||
getList();
|
getList();
|
||||||
getlistPurchase();
|
getlistPurchase();
|
||||||
// 监听初始验收条目
|
// 监听初始验收条目并触发验证
|
||||||
if (form.value.itemList.length > 0) {
|
if (form.value.itemList.length > 0) {
|
||||||
watchItemChanges(0);
|
watchItemChanges(0);
|
||||||
|
validateQuantityField(0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -689,7 +814,6 @@ const listeningProject = watch(
|
|||||||
/** 页面卸载时清理监听 */
|
/** 页面卸载时清理监听 */
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
listeningProject();
|
listeningProject();
|
||||||
// 清理验收条目监听
|
|
||||||
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -116,6 +116,9 @@
|
|||||||
<el-button link type="primary" icon="View" @click="handleDetail(scope.row)" v-hasPermi="['cailiaoshebei:purchaseDoc:remove']"
|
<el-button link type="primary" icon="View" @click="handleDetail(scope.row)" v-hasPermi="['cailiaoshebei:purchaseDoc:remove']"
|
||||||
>详情</el-button
|
>详情</el-button
|
||||||
>
|
>
|
||||||
|
<el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-hasPermi="['cailiaoshebei:purchaseDoc:downloadWord']"
|
||||||
|
>下载</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -130,8 +133,8 @@
|
|||||||
></el-col>
|
></el-col>
|
||||||
<el-col :span="12" :offset="0"
|
<el-col :span="12" :offset="0"
|
||||||
><el-form-item label="供应商" prop="supplier">
|
><el-form-item label="供应商" prop="supplier">
|
||||||
<el-select v-model="form.supplier" value-key="id" placeholder="请选择供应商" clearable filterable @change="">
|
<el-select v-model="form.supplierId" value-key="id" placeholder="请选择供应商" clearable filterable @change="">
|
||||||
<el-option v-for="item in supplierOptions" :key="item.id" :label="item.name" :value="item.name"> </el-option>
|
<el-option v-for="item in supplierOptions" :key="item.id" :label="item.supplierName" :value="item.id"> </el-option>
|
||||||
</el-select> </el-form-item
|
</el-select> </el-form-item
|
||||||
></el-col>
|
></el-col>
|
||||||
<el-col :span="12" :offset="0"
|
<el-col :span="12" :offset="0"
|
||||||
@ -265,6 +268,7 @@ import { useUserStoreHook } from '@/store/modules/user';
|
|||||||
import { getToken } from '@/utils/auth';
|
import { getToken } from '@/utils/auth';
|
||||||
import logisticsDetail from './comm/logisticsDetail.vue';
|
import logisticsDetail from './comm/logisticsDetail.vue';
|
||||||
import { FormRules } from 'element-plus';
|
import { FormRules } from 'element-plus';
|
||||||
|
import { listSupplierInput } from '@/api/supplierInput/supplierInput';
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -304,6 +308,8 @@ const initFormData: any = {
|
|||||||
docCode: undefined,
|
docCode: undefined,
|
||||||
supplier: undefined,
|
supplier: undefined,
|
||||||
reason: undefined,
|
reason: undefined,
|
||||||
|
supplierId: undefined,
|
||||||
|
|
||||||
name: undefined,
|
name: undefined,
|
||||||
arrivalDate: undefined,
|
arrivalDate: undefined,
|
||||||
designDirectorTel: undefined,
|
designDirectorTel: undefined,
|
||||||
@ -379,6 +385,15 @@ const cancel = () => {
|
|||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
};
|
};
|
||||||
|
const handleDownload = async (row) => {
|
||||||
|
proxy?.download(
|
||||||
|
'/cailiaoshebei/purchaseDoc/export/word',
|
||||||
|
{
|
||||||
|
id: row.id
|
||||||
|
},
|
||||||
|
`${row.docCode}.doc`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const handleDetail = async (row?: PurchaseDocVO) => {
|
const handleDetail = async (row?: PurchaseDocVO) => {
|
||||||
proxy?.$modal.loading('加载中');
|
proxy?.$modal.loading('加载中');
|
||||||
@ -467,6 +482,7 @@ const submitForm = () => {
|
|||||||
form.value.associationList = form.value.planId?.map((item: any) => ({
|
form.value.associationList = form.value.planId?.map((item: any) => ({
|
||||||
planId: item
|
planId: item
|
||||||
}));
|
}));
|
||||||
|
form.value.supplier = supplierOptions.value.find((item) => item.id == form.value.supplierId)?.supplierName;
|
||||||
|
|
||||||
if (form.value.id) {
|
if (form.value.id) {
|
||||||
await updatePurchaseDoc(form.value).finally(() => (buttonLoading.value = false));
|
await updatePurchaseDoc(form.value).finally(() => (buttonLoading.value = false));
|
||||||
@ -502,10 +518,10 @@ const getBatchList = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getSupplierList = async () => {
|
const getSupplierList = async () => {
|
||||||
const res = await listContractor({
|
const res = await listSupplierInput({
|
||||||
projectId: currentProject.value?.id,
|
projectId: currentProject.value?.id,
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
contractorType: 4,
|
state: 'finish',
|
||||||
pageSize: 10000
|
pageSize: 10000
|
||||||
});
|
});
|
||||||
supplierOptions.value = res.rows;
|
supplierOptions.value = res.rows;
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
<el-table v-loading="loading" :data="tableData" v-if="activeTab == '3'">
|
<el-table v-loading="loading" :data="tableData" v-if="activeTab == '3'">
|
||||||
<el-table-column label="项目" align="center" prop="projectName" />
|
<el-table-column label="项目" align="center" prop="projectName" />
|
||||||
<el-table-column label="累计完工产值" align="center" prop="totalCompletionOutputValue" />
|
<!-- <el-table-column label="累计完工产值" align="center" prop="totalCompletionOutputValue" /> -->
|
||||||
<el-table-column label="分包累计结算产值" align="center" prop="subTotalSettlementOutputValue" />
|
<el-table-column label="分包累计结算产值" align="center" prop="subTotalSettlementOutputValue" />
|
||||||
<el-table-column label="业主累计结算产值" align="center" prop="ownerTotalSettlementOutputValue" />
|
<el-table-column label="业主累计结算产值" align="center" prop="ownerTotalSettlementOutputValue" />
|
||||||
<el-table-column label="差额" align="center" prop="differenceValue" />
|
<el-table-column label="差额" align="center" prop="differenceValue" />
|
||||||
|
@ -23,9 +23,9 @@
|
|||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['patch:master:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['patch:master:add']">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<!-- <el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['patch:master:export']">导出</el-button>
|
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['patch:master:export']">导出</el-button>
|
||||||
</el-col>
|
</el-col> -->
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
@ -64,32 +64,32 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="计量单位" align="center" prop="unit">
|
<el-table-column label="计量单位" align="center" prop="unit">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.parentId == 0 ? '' : row.unit }}
|
{{ row.unitType == 0 ? '' : row.unit }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="综合单价(业主)" align="center" prop="ownerPrice">
|
<el-table-column label="综合单价(业主)" align="center" prop="ownerPrice">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.parentId == 0 ? '' : row.ownerPrice }}
|
{{ row.unitType == 0 ? '' : row.ownerPrice }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="综合单价(分包)" align="center" prop="constructionPrice">
|
<el-table-column label="综合单价(分包)" align="center" prop="constructionPrice">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.parentId == 0 ? '' : row.constructionPrice }}
|
{{ row.unitType == 0 ? '' : row.constructionPrice }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="产值金额(业主)" align="center" prop="ownerOutputValue">
|
<el-table-column label="产值金额(业主)" align="center" prop="ownerOutputValue">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.parentId == 0 ? '' : row.ownerOutputValue }}
|
{{ row.unitType == 0 ? '' : row.ownerOutputValue }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="产值金额(分包)" align="center" prop="constructionOutputValue">
|
<el-table-column label="产值金额(分包)" align="center" prop="constructionOutputValue">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.parentId == 0 ? '' : row.constructionOutputValue }}
|
{{ row.unitType == 0 ? '' : row.constructionOutputValue }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="总数量" align="center" prop="total">
|
<el-table-column label="总数量" align="center" prop="total">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.parentId == 0 ? '' : row.total }}
|
{{ row.unitType == 0 ? '' : row.total }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="关联结构" align="center" prop="relevancyStructure" width="100">
|
<el-table-column label="关联结构" align="center" prop="relevancyStructure" width="100">
|
||||||
@ -128,7 +128,7 @@
|
|||||||
check-strictly
|
check-strictly
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="计量方式" prop="unitType" v-if="!form.workType">
|
<el-form-item label="计量方式" prop="unitType" v-if="!form.workType && form.unitType != '0'">
|
||||||
<el-select v-model="form.unitType" placeholder="请选择关联数据">
|
<el-select v-model="form.unitType" placeholder="请选择关联数据">
|
||||||
<el-option v-for="dict in progress_unit_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
<el-option v-for="dict in progress_unit_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
@ -153,12 +153,12 @@
|
|||||||
<el-option v-for="dict in progress_work_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
<el-option v-for="dict in progress_work_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="关联结构" prop="relevancyStructure">
|
<!-- <el-form-item label="关联结构" prop="relevancyStructure">
|
||||||
<el-select v-model="form.relevancyStructure" value-key="" placeholder="请选择关联结构" clearable filterable @change="">
|
<el-select v-model="form.relevancyStructure" value-key="" placeholder="请选择关联结构" clearable filterable @change="">
|
||||||
<el-option label="子项目" value="1"></el-option>
|
<el-option label="子项目" value="1"></el-option>
|
||||||
<el-option label="方阵" value="2"></el-option>
|
<el-option label="方阵" value="2"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
<el-form-item label="备注" prop="remark" v-if="!form.id">
|
<el-form-item label="备注" prop="remark" v-if="!form.id">
|
||||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -433,12 +433,12 @@ const handleUpdate = async (row: ProgressCategoryVO) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleExport = async () => {
|
const handleExport = async () => {
|
||||||
const ids = treeRef.value.getCheckedNodes()[0].pathNodes[0].childrenData.map((item) => item.matrixId);
|
const ids = queryParams.value.projectId;
|
||||||
const fileName = treeRef.value.getCheckedNodes()[0].pathNodes[0].label;
|
const fileName = matrixOptions.value.find((item) => item.projectId == ids)?.name || currentProject.value?.name || '工程项目';
|
||||||
proxy?.download(
|
proxy?.download(
|
||||||
'/progress/progressCategory/export',
|
'/progress/progressCategory/export',
|
||||||
{
|
{
|
||||||
ids: ids
|
projectId: ids
|
||||||
},
|
},
|
||||||
`${fileName}分项工程单价导入.xlsx`,
|
`${fileName}分项工程单价导入.xlsx`,
|
||||||
true
|
true
|
||||||
|
@ -81,6 +81,11 @@
|
|||||||
<el-form-item label="公司名称" prop="name">
|
<el-form-item label="公司名称" prop="name">
|
||||||
<el-input v-model="form.name" placeholder="请输入公司名称" />
|
<el-input v-model="form.name" placeholder="请输入公司名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="供应商" prop="supplier">
|
||||||
|
<el-select v-model="form.supplierId" value-key="id" placeholder="请选择供应商" clearable filterable @change="">
|
||||||
|
<el-option v-for="item in supplierOptions" :key="item.id" :label="item.supplierName" :value="item.id"> </el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="负责人" prop="principal">
|
<el-form-item label="负责人" prop="principal">
|
||||||
<el-input v-model="form.principal" placeholder="请输入负责人" />
|
<el-input v-model="form.principal" placeholder="请输入负责人" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -121,6 +126,7 @@ import { ContractorForm, ContractorQuery, ContractorVO } from '@/api/project/con
|
|||||||
import ContractorFileDialog from '@/views/project/contractor/component/ContractorFileDialog.vue';
|
import ContractorFileDialog from '@/views/project/contractor/component/ContractorFileDialog.vue';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import { getDicts, listData } from '@/api/system/dict/data';
|
import { getDicts, listData } from '@/api/system/dict/data';
|
||||||
|
import { listSupplierInput } from '@/api/supplierInput/supplierInput';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
@ -152,6 +158,8 @@ const initFormData: ContractorForm = {
|
|||||||
principalPhone: undefined,
|
principalPhone: undefined,
|
||||||
custodian: undefined,
|
custodian: undefined,
|
||||||
custodianPhone: undefined,
|
custodianPhone: undefined,
|
||||||
|
supplierId: undefined,
|
||||||
|
supplier: undefined,
|
||||||
contractorType: undefined,
|
contractorType: undefined,
|
||||||
fileMap: undefined,
|
fileMap: undefined,
|
||||||
remark: undefined,
|
remark: undefined,
|
||||||
@ -257,6 +265,8 @@ const submitForm = () => {
|
|||||||
if (valid) {
|
if (valid) {
|
||||||
form.value.projectId = currentProject.value?.id;
|
form.value.projectId = currentProject.value?.id;
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
|
form.value.supplier = supplierOptions.value.find((item) => item.id == form.value.supplierId)?.supplierName;
|
||||||
|
|
||||||
if (form.value.id) {
|
if (form.value.id) {
|
||||||
await updateContractor(form.value).finally(() => (buttonLoading.value = false));
|
await updateContractor(form.value).finally(() => (buttonLoading.value = false));
|
||||||
} else {
|
} else {
|
||||||
@ -278,15 +288,16 @@ const handleDelete = async (row?: ContractorVO) => {
|
|||||||
await getList();
|
await getList();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 导出按钮操作 */
|
/** 获取供应商 */
|
||||||
const handleExport = () => {
|
const supplierOptions = ref([]);
|
||||||
proxy?.download(
|
const getSupplierList = async () => {
|
||||||
'project/contractor/export',
|
const res = await listSupplierInput({
|
||||||
{
|
projectId: currentProject.value?.id,
|
||||||
...queryParams.value
|
pageNum: 1,
|
||||||
},
|
state: 'finish',
|
||||||
`contractor_${new Date().getTime()}.xlsx`
|
pageSize: 10000
|
||||||
);
|
});
|
||||||
|
supplierOptions.value = res.rows;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 文件操作 **/
|
/** 文件操作 **/
|
||||||
@ -304,6 +315,7 @@ const listeningProject = watch(
|
|||||||
queryParams.value.projectId = nid;
|
queryParams.value.projectId = nid;
|
||||||
form.value.projectId = nid;
|
form.value.projectId = nid;
|
||||||
console.log('监听项目id', queryParams.value.projectId, form.value.projectId);
|
console.log('监听项目id', queryParams.value.projectId, form.value.projectId);
|
||||||
|
getSupplierList();
|
||||||
getList();
|
getList();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -314,5 +326,6 @@ onUnmounted(() => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getDictList();
|
getDictList();
|
||||||
getList();
|
getList();
|
||||||
|
getSupplierList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -46,16 +46,11 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['land:landBlock:remove']"
|
|
||||||
>删除</el-button
|
|
||||||
>
|
|
||||||
</el-col>
|
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
<el-table draggable v-loading="loading" :data="landBlockList" @selection-change="handleSelectionChange">
|
<el-table draggable v-loading="loading" :data="landBlockList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="index" label="序号" width="55" align="center" />
|
||||||
<el-table-column label="地块编号" align="center" prop="landCode" />
|
<el-table-column label="地块编号" align="center" prop="landCode" />
|
||||||
<el-table-column label="地块名称" align="center" prop="landName" />
|
<el-table-column label="地块名称" align="center" prop="landName" />
|
||||||
<el-table-column label="方阵" align="center" prop="unit" />
|
<el-table-column label="方阵" align="center" prop="unit" />
|
||||||
@ -80,11 +75,9 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
|
<!-- 地块表单弹窗 -->
|
||||||
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||||
<el-form ref="landBlockFormRef" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="landBlockFormRef" :model="form" :rules="rules" label-width="100px">
|
||||||
<!-- <el-form-item label="地块编号" prop="landCode">
|
|
||||||
<el-input v-model="form.landCode" placeholder="请输入地块编号" />
|
|
||||||
</el-form-item> -->
|
|
||||||
<el-form-item label="地块名称" prop="landName">
|
<el-form-item label="地块名称" prop="landName">
|
||||||
<el-input v-model="form.landName" placeholder="请输入地块名称" />
|
<el-input v-model="form.landName" placeholder="请输入地块名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -111,15 +104,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog draggable :title="dialogMatrix.title" v-model="dialogMatrix.visible" width="800px" append-to-body>
|
<!-- 关联方阵弹窗(核心修改区域) -->
|
||||||
|
<el-dialog draggable :title="dialogMatrix.title" v-model="dialogMatrix.visible" width="900px" append-to-body>
|
||||||
<el-button type="primary" plain icon="Plus" @click="addUnitBoItem" style="margin-bottom: 15px">添加</el-button>
|
<el-button type="primary" plain icon="Plus" @click="addUnitBoItem" style="margin-bottom: 15px">添加</el-button>
|
||||||
<el-form ref="landBlockFormMatrixRef" :model="formM" :rules="rules" label-width="100px">
|
<!-- 方阵表单:绑定unitBoList的索引,实现动态校验 -->
|
||||||
<el-row v-for="(item, i) of unitBoList" :key="i">
|
<el-form ref="landBlockFormMatrixRef" :model="formM" label-width="100px">
|
||||||
<el-col :span="9">
|
<el-row v-for="(item, i) of unitBoList" :key="i" class="mb-4">
|
||||||
<el-form-item label="方阵" prop="matrixId">
|
<!-- 方阵选择:必填校验 -->
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item
|
||||||
|
label="方阵"
|
||||||
|
:prop="`unitBoList[${i}].unitProjectId`"
|
||||||
|
:rules="[
|
||||||
|
{ required: true, message: '请选择方阵', trigger: 'change' },
|
||||||
|
{ type: 'array', min: 2, message: '请选择完整的方阵层级', trigger: 'change' }
|
||||||
|
]"
|
||||||
|
>
|
||||||
<el-cascader
|
<el-cascader
|
||||||
:options="fangzhenList"
|
:options="fangzhenList"
|
||||||
placeholder="请选择"
|
placeholder="请选择方阵"
|
||||||
filterable
|
filterable
|
||||||
:props="{ value: 'matrixId', label: 'name' }"
|
:props="{ value: 'matrixId', label: 'name' }"
|
||||||
v-model="item.unitProjectId"
|
v-model="item.unitProjectId"
|
||||||
@ -127,18 +130,28 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="7">
|
<!-- 所属工区:必填校验 -->
|
||||||
<el-form-item label="所属工区" prop="unitProjectArea">
|
<el-col :span="8">
|
||||||
|
<el-form-item
|
||||||
|
label="所属工区"
|
||||||
|
:prop="`unitBoList[${i}].unitProjectArea`"
|
||||||
|
:rules="{ required: true, message: '请输入所属工区', trigger: 'blur' }"
|
||||||
|
>
|
||||||
<el-input v-model="item.unitProjectArea" placeholder="请输入所属工区" />
|
<el-input v-model="item.unitProjectArea" placeholder="请输入所属工区" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<!-- 方阵状态:必填校验 -->
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-form-item label="方阵状态" prop="unitProjectStatus">
|
<el-form-item
|
||||||
|
label="方阵状态"
|
||||||
|
:prop="`unitBoList[${i}].unitProjectStatus`"
|
||||||
|
:rules="{ required: true, message: '请输入方阵状态', trigger: 'blur' }"
|
||||||
|
>
|
||||||
<el-input v-model="item.unitProjectStatus" placeholder="请输入方阵状态" />
|
<el-input v-model="item.unitProjectStatus" placeholder="请输入方阵状态" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1" style="margin-left: 15px">
|
<el-col :span="1" style="margin-left: 15px; display: flex; align-items: flex-end">
|
||||||
<el-button type="danger" icon="Delete" @click="removeUnitBoItem(i)"></el-button>
|
<el-button style="margin-bottom: 18px" type="danger" icon="Delete" @click="removeUnitBoItem(i)"></el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
@ -153,44 +166,65 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="LandBlock" lang="ts">
|
<script setup name="LandBlock" lang="ts">
|
||||||
import { listLandBlock, getLandBlock, delLandBlock, LandUnit, addLandBlock, updateLandBlock, subMatrix,importLandBlock } from '@/api/system/landTransfer/landBlock';
|
import {
|
||||||
|
listLandBlock,
|
||||||
|
getLandBlock,
|
||||||
|
delLandBlock,
|
||||||
|
LandUnit,
|
||||||
|
addLandBlock,
|
||||||
|
updateLandBlock,
|
||||||
|
subMatrix,
|
||||||
|
importLandBlock
|
||||||
|
} from '@/api/system/landTransfer/landBlock';
|
||||||
import { LandBlockVO, LandBlockQuery, LandBlockForm } from '@/api/system/landTransfer/landBlock/types';
|
import { LandBlockVO, LandBlockQuery, LandBlockForm } from '@/api/system/landTransfer/landBlock/types';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
import { getCurrentInstance, ComponentInternalInstance, onMounted, onUnmounted, watch } from 'vue';
|
||||||
|
import { ElFormInstance, ElMessage } from 'element-plus';
|
||||||
|
|
||||||
|
// 类型定义补充(避免any)
|
||||||
|
interface DialogOption {
|
||||||
|
visible: boolean;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UnitBoItem {
|
||||||
|
unitProjectArea: string;
|
||||||
|
unitProjectStatus: string;
|
||||||
|
unitProjectId: (string | number)[]; // 级联选择值(数组)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基础实例与Store
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
// 获取用户 store
|
|
||||||
const userStore = useUserStoreHook();
|
const userStore = useUserStoreHook();
|
||||||
// 从 store 中获取项目列表和当前选中的项目
|
|
||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
const landBlockList = ref<LandBlockVO[]>([]);
|
const landBlockList = ref<LandBlockVO[]>([]);
|
||||||
const fangzhenList = ref([]); //方阵列表数据
|
const fangzhenList = ref<any[]>([]); // 方阵列表(实际项目建议定义具体类型)
|
||||||
const buttonLoading = ref(false);
|
const buttonLoading = ref(false);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const showSearch = ref(true);
|
const showSearch = ref(true);
|
||||||
const unitBoList = ref([
|
const uploadRef = ref<any>(null); // upload组件ref
|
||||||
{
|
|
||||||
unitProjectArea: '1',
|
// 方阵表单数据(核心修改:初始值为空,避免默认填充无效数据)
|
||||||
unitProjectStatus: '1',
|
const unitBoList = ref<UnitBoItem[]>([{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }]);
|
||||||
unitProjectId: []
|
|
||||||
}
|
// 表格选择相关
|
||||||
]);
|
|
||||||
const ids = ref<Array<string | number>>([]);
|
const ids = ref<Array<string | number>>([]);
|
||||||
const single = ref(true);
|
const single = ref(true);
|
||||||
const multiple = ref(true);
|
const multiple = ref(true);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
|
|
||||||
|
// 表单Ref
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const landBlockFormRef = ref<ElFormInstance>();
|
const landBlockFormRef = ref<ElFormInstance>();
|
||||||
const landBlockFormMatrixRef = ref<ElFormInstance>();
|
const landBlockFormMatrixRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
// 弹窗配置
|
||||||
visible: false,
|
const dialog = reactive<DialogOption>({ visible: false, title: '' });
|
||||||
title: ''
|
const dialogMatrix = reactive<DialogOption>({ visible: false, title: '选择方阵' });
|
||||||
});
|
|
||||||
|
|
||||||
const dialogMatrix = reactive<DialogOption>({
|
|
||||||
visible: false,
|
|
||||||
title: '选择方阵'
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// 初始表单数据
|
||||||
const initFormData: LandBlockForm = {
|
const initFormData: LandBlockForm = {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
projectId: currentProject.value?.id,
|
projectId: currentProject.value?.id,
|
||||||
@ -202,11 +236,11 @@ const initFormData: LandBlockForm = {
|
|||||||
farmerCount: undefined,
|
farmerCount: undefined,
|
||||||
remark: undefined
|
remark: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 核心数据(含表单规则)
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
formM: {
|
formM: { landId: undefined }, // 方阵关联表单(仅存地块ID)
|
||||||
landId: undefined
|
|
||||||
},
|
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@ -219,6 +253,7 @@ const data = reactive({
|
|||||||
farmerCount: undefined,
|
farmerCount: undefined,
|
||||||
params: {}
|
params: {}
|
||||||
},
|
},
|
||||||
|
// 地块表单规则(原有规则保留)
|
||||||
rules: {
|
rules: {
|
||||||
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
||||||
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
||||||
@ -229,216 +264,285 @@ const data = reactive({
|
|||||||
|
|
||||||
const { queryParams, form, rules, formM } = toRefs(data);
|
const { queryParams, form, rules, formM } = toRefs(data);
|
||||||
|
|
||||||
/** 查询地块信息列表 */
|
/** 查询地块列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
try {
|
||||||
const res = await listLandBlock(queryParams.value);
|
const res = await listLandBlock(queryParams.value);
|
||||||
landBlockList.value = res.rows;
|
landBlockList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
|
} catch (err) {
|
||||||
|
proxy?.$modal.msgError('获取地块列表失败');
|
||||||
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 地块表单取消 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 表单重置 */
|
/** 地块表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
landBlockFormRef.value?.resetFields();
|
landBlockFormRef.value?.resetFields();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索提交 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 重置按钮操作 */
|
/** 搜索重置 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 多选框选中数据 */
|
/** 表格选择变化 */
|
||||||
const handleSelectionChange = (selection: LandBlockVO[]) => {
|
const handleSelectionChange = (selection: LandBlockVO[]) => {
|
||||||
ids.value = selection.map((item) => item.id);
|
ids.value = selection.map((item) => item.id);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length !== 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = selection.length === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增地块 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = '添加地块信息';
|
dialog.title = '添加地块信息';
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 编辑地块 */
|
||||||
const handleUpdate = async (row?: LandBlockVO) => {
|
const handleUpdate = async (row?: LandBlockVO) => {
|
||||||
reset();
|
reset();
|
||||||
const _id = row?.id || ids.value[0];
|
const _id = row?.id || ids.value[0];
|
||||||
|
if (!_id) return proxy?.$modal.msgWarning('请选择要编辑的地块');
|
||||||
|
|
||||||
|
try {
|
||||||
const res = await getLandBlock(_id);
|
const res = await getLandBlock(_id);
|
||||||
Object.assign(form.value, res.data);
|
Object.assign(form.value, res.data);
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = '修改地块信息';
|
dialog.title = '修改地块信息';
|
||||||
|
} catch (err) {
|
||||||
|
proxy?.$modal.msgError('获取地块详情失败');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交地块表单 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
landBlockFormRef.value?.validate(async (valid: boolean) => {
|
landBlockFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (!valid) return;
|
||||||
|
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
|
try {
|
||||||
if (form.value.id) {
|
if (form.value.id) {
|
||||||
await updateLandBlock(form.value).finally(() => (buttonLoading.value = false));
|
await updateLandBlock(form.value);
|
||||||
} else {
|
} else {
|
||||||
await addLandBlock(form.value).finally(() => (buttonLoading.value = false));
|
await addLandBlock(form.value);
|
||||||
}
|
}
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
|
} catch (err) {
|
||||||
|
proxy?.$modal.msgError(form.value.id ? '修改失败' : '新增失败');
|
||||||
|
} finally {
|
||||||
|
buttonLoading.value = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除地块 */
|
||||||
const handleDelete = async (row?: LandBlockVO) => {
|
const handleDelete = async (row?: LandBlockVO) => {
|
||||||
const _ids = row?.id || ids.value;
|
const _ids = row?.id || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除地块信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
if (!_ids.length) return proxy?.$modal.msgWarning('请选择要删除的地块');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await proxy?.$modal.confirm(`是否确认删除地块信息编号为"${_ids}"的数据项?`);
|
||||||
await delLandBlock(_ids);
|
await delLandBlock(_ids);
|
||||||
proxy?.$modal.msgSuccess('删除成功');
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
await getList();
|
await getList();
|
||||||
|
} catch (err) {
|
||||||
|
// 取消确认时不提示错误
|
||||||
|
if (err !== 'cancel') proxy?.$modal.msgError('删除失败');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取方阵列表
|
/** 获取方阵列表 */
|
||||||
const getfangzhenList = async () => {
|
const getfangzhenList = async () => {
|
||||||
|
if (!currentProject.value?.id) return;
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await subMatrix(currentProject.value?.id);
|
try {
|
||||||
res.data.forEach((item) => {
|
const res = await subMatrix(currentProject.value.id);
|
||||||
item.children.forEach((item2) => {
|
// 处理方阵数据(级联选择需父子结构,此处保留原有逻辑)
|
||||||
item2.matrixId = item2.name + '_' + item2.matrixId;
|
res.data.forEach((item: any) => {
|
||||||
|
item.children?.forEach((item2: any) => {
|
||||||
|
item2.matrixId = `${item2.name}_${item2.matrixId}`; // 拼接名称+ID,便于后续拆分
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
fangzhenList.value = res.data;
|
fangzhenList.value = res.data;
|
||||||
|
} catch (err) {
|
||||||
|
proxy?.$modal.msgError('获取方阵列表失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleView = async (row) => {
|
/** 关联方阵(核心修改:打开弹窗前强制重置表单) */
|
||||||
// 关联方阵
|
const handleView = async (row: LandBlockVO) => {
|
||||||
|
if (!row?.id) return proxy?.$modal.msgWarning('请选择有效的地块');
|
||||||
|
|
||||||
|
// 1. 重置方阵表单(清空历史数据)
|
||||||
|
resetMatrix();
|
||||||
|
// 2. 绑定当前地块ID
|
||||||
|
formM.value.landId = row.id;
|
||||||
|
// 3. 打开弹窗
|
||||||
dialogMatrix.visible = true;
|
dialogMatrix.visible = true;
|
||||||
dialogMatrix.title = '关联方阵';
|
dialogMatrix.title = `关联方阵(地块:${row.landName || row.landCode})`;
|
||||||
data.formM.landId = row.id;
|
|
||||||
};
|
};
|
||||||
// 动态添加unitBoList项
|
|
||||||
|
/** 新增方阵表单项 */
|
||||||
const addUnitBoItem = () => {
|
const addUnitBoItem = () => {
|
||||||
unitBoList.value.push({
|
unitBoList.value.push({
|
||||||
unitProjectArea: '',
|
unitProjectArea: '',
|
||||||
unitProjectStatus: '',
|
unitProjectStatus: '',
|
||||||
unitProjectId: []
|
unitProjectId: [] // 级联选择初始为空数组
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 移除unitBoList项
|
/** 删除方阵表单项 */
|
||||||
const removeUnitBoItem = (index: number) => {
|
const removeUnitBoItem = (index: number) => {
|
||||||
if (unitBoList.value.length > 1) {
|
if (unitBoList.value.length <= 1) {
|
||||||
unitBoList.value.splice(index, 1);
|
return proxy?.$modal.msgWarning('至少保留一项方阵配置');
|
||||||
} else {
|
|
||||||
proxy?.$modal.msgWarning('至少保留一项');
|
|
||||||
}
|
}
|
||||||
|
unitBoList.value.splice(index, 1);
|
||||||
|
// 重置表单校验状态(避免删除后残留校验提示)
|
||||||
|
landBlockFormMatrixRef.value?.clearValidate();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 提交方阵关联表单 */
|
||||||
const submitFormMatrix = () => {
|
const submitFormMatrix = () => {
|
||||||
landBlockFormMatrixRef.value?.validate(async (valid: boolean) => {
|
landBlockFormMatrixRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (!valid) return;
|
||||||
var arr = [];
|
if (!formM.value.landId) return proxy?.$modal.msgWarning('地块ID异常,请重新选择地块');
|
||||||
unitBoList.value.forEach((item) => {
|
|
||||||
let str = item.unitProjectId[1].split('_');
|
try {
|
||||||
arr.push({
|
// 处理方阵数据(拆分名称+ID)
|
||||||
unitProjectArea: item.unitProjectArea,
|
const unitBoListParams = unitBoList.value.map((item) => {
|
||||||
unitProjectStatus: item.unitProjectStatus,
|
const [unitProjectName, unitProjectId] = item.unitProjectId[1]?.split('_') || [];
|
||||||
unitProjectId: str[1],
|
if (!unitProjectId) throw new Error('方阵ID解析失败,请重新选择方阵');
|
||||||
unitProjectName: str[0]
|
|
||||||
|
return {
|
||||||
|
unitProjectArea: item.unitProjectArea.trim(),
|
||||||
|
unitProjectStatus: item.unitProjectStatus.trim(),
|
||||||
|
unitProjectId: unitProjectId, // 纯ID(后端需要)
|
||||||
|
unitProjectName: unitProjectName // 名称(可选,用于显示)
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 调用关联接口
|
||||||
|
const res = await LandUnit({
|
||||||
|
landId: formM.value.landId,
|
||||||
|
unitBoList: unitBoListParams
|
||||||
});
|
});
|
||||||
var res = await LandUnit({ ...formM.value, unitBoList: arr });
|
|
||||||
if (res.code == 200) {
|
if (res.code === 200) {
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
proxy?.$modal.msgSuccess('关联方阵成功');
|
||||||
dialogMatrix.visible = false;
|
dialogMatrix.visible = false;
|
||||||
await getList();
|
await getList(); // 刷新地块列表
|
||||||
} else {
|
} else {
|
||||||
proxy?.$modal.msgError(res.msg);
|
proxy?.$modal.msgError(res.msg || '关联失败');
|
||||||
}
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
proxy?.$modal.msgError(err.msg || '关联过程异常');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
/** 取消按钮 */
|
|
||||||
|
/** 方阵表单取消 */
|
||||||
const cancelMatrix = () => {
|
const cancelMatrix = () => {
|
||||||
resetMatrix();
|
resetMatrix();
|
||||||
dialogMatrix.visible = false;
|
dialogMatrix.visible = false;
|
||||||
};
|
};
|
||||||
/** 表单重置 */
|
|
||||||
|
/** 方阵表单重置(核心修改:清空所有数据+重置校验) */
|
||||||
const resetMatrix = () => {
|
const resetMatrix = () => {
|
||||||
data.formM.landId = '';
|
// 1. 清空地块ID
|
||||||
unitBoList.value = [
|
formM.value.landId = undefined;
|
||||||
{
|
// 2. 重置方阵列表(仅保留一个空项)
|
||||||
unitProjectArea: '1',
|
unitBoList.value = [{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }];
|
||||||
unitProjectStatus: '1',
|
// 3. 重置表单校验状态
|
||||||
unitProjectId: []
|
if (landBlockFormMatrixRef.value) {
|
||||||
|
landBlockFormMatrixRef.value.resetFields();
|
||||||
|
landBlockFormMatrixRef.value.clearValidate();
|
||||||
}
|
}
|
||||||
];
|
|
||||||
landBlockFormMatrixRef.value?.resetFields();
|
|
||||||
};
|
};
|
||||||
//监听项目id刷新数据
|
|
||||||
|
/** 监听项目变化,刷新数据 */
|
||||||
const listeningProject = watch(
|
const listeningProject = watch(
|
||||||
() => currentProject.value?.id,
|
() => currentProject.value?.id,
|
||||||
(nid, oid) => {
|
(newId) => {
|
||||||
queryParams.value.projectId = nid;
|
if (newId) {
|
||||||
getfangzhenList();
|
queryParams.value.projectId = newId;
|
||||||
getList();
|
getfangzhenList(); // 刷新方阵列表
|
||||||
|
getList(); // 刷新地块列表
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true } // 初始加载时执行一次
|
||||||
);
|
);
|
||||||
|
|
||||||
// 导入文件
|
/** 导入Excel */
|
||||||
const handleImport = (options:any) => {
|
const handleImport = (options: { file: File }) => {
|
||||||
|
if (!currentProject.value?.id) return proxy?.$modal.msgWarning('请先选择项目');
|
||||||
|
if (!options.file) return proxy?.$modal.msgWarning('请选择Excel文件');
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
let formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', options.file);
|
formData.append('file', options.file);
|
||||||
importLandBlock(currentProject.value?.id,formData).then((res) => {
|
|
||||||
if (res.code == 200) {
|
importLandBlock(currentProject.value.id, formData)
|
||||||
proxy.$modal.msgSuccess(res.msg || '导入成功');
|
.then((res) => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
proxy?.$modal.msgSuccess(res.msg || '导入成功');
|
||||||
getList();
|
getList();
|
||||||
getfangzhenList();
|
getfangzhenList();
|
||||||
|
} else {
|
||||||
|
proxy?.$modal.msgError(res.msg || '导入失败');
|
||||||
}
|
}
|
||||||
}).catch((err) => {
|
})
|
||||||
proxy.$modal.msgError(err.msg || '导入失败');
|
.catch((err) => {
|
||||||
}).finally(() => {
|
proxy?.$modal.msgError(err.msg || '导入接口异常');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 下载模板
|
/** 下载导入模板 */
|
||||||
const downloadTemplate = () => {
|
const downloadTemplate = () => {
|
||||||
// 导出模版文件
|
|
||||||
try {
|
try {
|
||||||
// 创建a标签
|
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
// 设置PDF文件路径 - 相对于public目录
|
link.href = '/landBlock.xlsx'; // 模板路径(需确保public目录下存在该文件)
|
||||||
link.href = '/landBlock.xlsx';
|
link.download = '地块信息导入模板.xlsx'; // 下载后文件名
|
||||||
// 设置下载后的文件名
|
|
||||||
link.download = '地块信息导入模板.xlsx';
|
|
||||||
// 触发点击
|
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click(); // 触发下载
|
||||||
// 清理
|
} catch (err) {
|
||||||
document.body.removeChild(link);
|
proxy?.$modal.msgError('模板下载失败,请重试');
|
||||||
} catch (error) {
|
} finally {
|
||||||
alert('下载失败,请重试');
|
document.body.removeChild(link); // 清理DOM
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 生命周期:组件卸载时清理监听 */
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
listeningProject();
|
listeningProject();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** 生命周期:组件挂载时初始化数据 */
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
getfangzhenList();
|
getfangzhenList();
|
||||||
|
@ -1,8 +1,37 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2 detailbox">
|
||||||
|
<div class="box1">
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<span>设计面积</span>
|
||||||
|
<span>{{ detailInfo.designArea }} 亩</span>
|
||||||
|
</div>
|
||||||
|
<el-icon :size="50" color="#3176ff">
|
||||||
|
<Postcard />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<span>已流转面积</span>
|
||||||
|
<span>{{ detailInfo.transferAea }} 亩</span>
|
||||||
|
</div>
|
||||||
|
<el-icon :size="50" color="#3176ff">
|
||||||
|
<Postcard />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<span>租金</span>
|
||||||
|
<span>{{ detailInfo.landRent / 1000 }} 万元</span>
|
||||||
|
</div>
|
||||||
|
<el-icon :size="50" color="#3176ff">
|
||||||
|
<Postcard />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="never">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="110px">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="110px">
|
||||||
<el-form-item label="对应地块" prop="landBlockId">
|
<el-form-item label="对应地块" prop="landBlockId">
|
||||||
<el-select v-model="queryParams.landBlockId" clearable placeholder="请选择对应地块">
|
<el-select v-model="queryParams.landBlockId" clearable placeholder="请选择对应地块">
|
||||||
@ -12,8 +41,9 @@
|
|||||||
<el-form-item label="流转台账状态" prop="transferStatus">
|
<el-form-item label="流转台账状态" prop="transferStatus">
|
||||||
<el-select v-model="queryParams.transferStatus" placeholder="请选择流转台账状态" clearable>
|
<el-select v-model="queryParams.transferStatus" placeholder="请选择流转台账状态" clearable>
|
||||||
<el-option label="待流转" :value="0"></el-option>
|
<el-option label="待流转" :value="0"></el-option>
|
||||||
<el-option label="已流转" :value="1"></el-option> </el-select
|
<el-option label="已流转" :value="1"></el-option>
|
||||||
></el-form-item>
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="责任人" prop="responsiblePerson">
|
<el-form-item label="责任人" prop="responsiblePerson">
|
||||||
<el-input v-model="queryParams.responsiblePerson" placeholder="请输入责任人" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.responsiblePerson" placeholder="请输入责任人" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -31,15 +61,7 @@
|
|||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['land:landTransferLedger:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['land:landTransferLedger:add']">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="6"></el-col>
|
||||||
<el-tag size="large" type="primary">设计面积:{{ detailInfo.designArea }}亩</el-tag>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-tag size="large" type="success">已流转面积:{{ detailInfo.transferAea }}亩</el-tag>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-tag size="large" type="warning">租金:{{ detailInfo.landRent / 1000 }}万元</el-tag>
|
|
||||||
</el-col>
|
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
@ -81,90 +103,107 @@
|
|||||||
<el-form-item label="对应地块" prop="landBlockId">
|
<el-form-item label="对应地块" prop="landBlockId">
|
||||||
<el-select v-model="form.landBlockId" clearable placeholder="请选择对应地块" @change="handleLandBlockChange">
|
<el-select v-model="form.landBlockId" clearable placeholder="请选择对应地块" @change="handleLandBlockChange">
|
||||||
<el-option v-for="item in landBlockList" :key="item.id" :label="item.landName" :value="item.id" />
|
<el-option v-for="item in landBlockList" :key="item.id" :label="item.landName" :value="item.id" />
|
||||||
</el-select> </el-form-item
|
</el-select>
|
||||||
></el-col>
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="进场道路" prop="enterRoadId">
|
<el-form-item label="进场道路" prop="enterRoadId">
|
||||||
<el-select v-model="form.enterRoadId" clearable placeholder="请选择对应地块">
|
<el-select v-model="form.enterRoadId" clearable placeholder="请选择对应地块">
|
||||||
<el-option v-for="item in enterRoadList" :key="item.id" :label="item.roadName" :value="item.id" />
|
<el-option v-for="item in enterRoadList" :key="item.id" :label="item.roadName" :value="item.id" />
|
||||||
</el-select> </el-form-item
|
</el-select>
|
||||||
></el-col>
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="土地类型" prop="landType">
|
<el-form-item label="土地类型" prop="landType">
|
||||||
<el-select v-model="form.landType" placeholder="请选择土地类型" clearable>
|
<el-select v-model="form.landType" placeholder="请选择土地类型" clearable>
|
||||||
<el-option v-for="dict in land_type" :key="dict.value" :label="dict.label" :value="dict.value" /> </el-select></el-form-item
|
<el-option v-for="dict in land_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
></el-col>
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="流转台账状态" prop="transferStatus">
|
<el-form-item label="流转台账状态" prop="transferStatus">
|
||||||
<el-select v-model="form.transferStatus" :disabled="!form.id" placeholder="请选择流转台账状态" clearable>
|
<el-select v-model="form.transferStatus" :disabled="!form.id" placeholder="请选择流转台账状态" clearable @change="calcTransferRatio">
|
||||||
<el-option
|
<el-option v-for="dict in land_transfer_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
v-for="dict in land_transfer_status"
|
</el-select>
|
||||||
:key="dict.value"
|
</el-form-item>
|
||||||
:label="dict.label"
|
</el-col>
|
||||||
:value="dict.value"
|
|
||||||
/> </el-select></el-form-item
|
|
||||||
></el-col>
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="设计面积(亩)" prop="designArea">
|
<el-form-item label="设计面积(亩)" prop="designArea">
|
||||||
<el-input type="number" v-model="form.designArea" placeholder="请输入设计面积" /> </el-form-item
|
<el-input type="number" v-model="form.designArea" placeholder="请输入设计面积" @input="calcTransferRatio" />
|
||||||
></el-col>
|
</el-form-item>
|
||||||
<el-col :span="12"
|
</el-col>
|
||||||
><el-form-item label="责任人" prop="responsiblePerson">
|
<el-col :span="12">
|
||||||
<el-input v-model="form.responsiblePerson" placeholder="请输入责任人" /> </el-form-item
|
<el-form-item label="责任人" prop="responsiblePerson">
|
||||||
></el-col>
|
<el-input v-model="form.responsiblePerson" placeholder="请输入责任人" />
|
||||||
<el-col v-if="form.transferStatus != '2'" :span="12"
|
</el-form-item>
|
||||||
><el-form-item label="预计完成日期" prop="expectedFinishDate">
|
</el-col>
|
||||||
|
<el-col v-if="form.transferStatus != '2'" :span="12">
|
||||||
|
<el-form-item label="预计完成日期" prop="expectedFinishDate">
|
||||||
<el-date-picker clearable v-model="form.expectedFinishDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择预计完成时间">
|
<el-date-picker clearable v-model="form.expectedFinishDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择预计完成时间">
|
||||||
</el-date-picker> </el-form-item
|
</el-date-picker>
|
||||||
></el-col>
|
</el-form-item>
|
||||||
<el-col v-if="form.transferStatus == '1'" :span="12"
|
</el-col>
|
||||||
><el-form-item label="已流转面积(亩)" prop="transferAea">
|
<el-col v-if="form.transferStatus == '1'" :span="12">
|
||||||
<el-input v-model="form.transferAea" type="number" placeholder="请输入已流转面积" /> </el-form-item
|
<el-form-item label="已流转面积(亩)" prop="transferAea">
|
||||||
></el-col>
|
<el-input v-model="form.transferAea" type="number" placeholder="请输入已流转面积" @input="calcTransferRatio" />
|
||||||
<el-col v-if="form.transferStatus == '1'" :span="12"
|
</el-form-item>
|
||||||
><el-form-item label="流转比例(%)" prop="transferRatio">
|
</el-col>
|
||||||
<el-input v-model="form.transferRatio" type="number" placeholder="请输入流转比例" /> </el-form-item
|
<!-- 流转比例:改为禁用输入,自动计算展示 -->
|
||||||
></el-col>
|
<el-col v-if="form.transferStatus == '1'" :span="12">
|
||||||
|
<el-form-item label="流转比例(%)" prop="transferRatio">
|
||||||
|
<el-input v-model="form.transferRatio" type="text" :disabled="true" placeholder="自动计算中..." />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col v-if="form.transferStatus == '1'" :span="12">
|
<el-col v-if="form.transferStatus == '1'" :span="12">
|
||||||
<el-form-item label="土地租金(元)" prop="landRent">
|
<el-form-item label="土地租金(元)" prop="landRent">
|
||||||
<el-input type="number" v-model="form.landRent" placeholder="请输入土地租金" /> </el-form-item
|
<el-input type="number" v-model="form.landRent" placeholder="请输入土地租金" />
|
||||||
></el-col>
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col v-if="form.transferStatus == '1'" :span="12">
|
<el-col v-if="form.transferStatus == '1'" :span="12">
|
||||||
<el-form-item label="青苗赔偿(元)" prop="seedlingCompensation">
|
<el-form-item label="青苗赔偿(元)" prop="seedlingCompensation">
|
||||||
<el-input v-model="form.seedlingCompensation" type="number" placeholder="请输入青苗赔偿" /> </el-form-item
|
<el-input v-model="form.seedlingCompensation" type="number" placeholder="请输入青苗赔偿" />
|
||||||
></el-col>
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col v-if="form.transferStatus == '1'" :span="12">
|
<el-col v-if="form.transferStatus == '1'" :span="12">
|
||||||
<el-form-item label="总金额(元)" prop="totalAmount">
|
<el-form-item label="总金额(元)" prop="totalAmount">
|
||||||
<el-input type="number" v-model="form.totalAmount" placeholder="请输入总金额" /> </el-form-item
|
<el-input type="number" v-model="form.totalAmount" placeholder="请输入总金额" />
|
||||||
></el-col>
|
</el-form-item>
|
||||||
<el-col v-if="form.transferStatus == '2'" :span="12"
|
</el-col>
|
||||||
><el-form-item label="不签合同面积(亩)" prop="noContractArea">
|
<el-col v-if="form.transferStatus == '2'" :span="12">
|
||||||
<el-input v-model="form.noContractArea" type="number" placeholder="请输入不签合同面积" /> </el-form-item
|
<el-form-item label="不签合同面积(亩)" prop="noContractArea">
|
||||||
></el-col>
|
<el-input v-model="form.noContractArea" type="number" placeholder="请输入不签合同面积" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col v-if="form.transferStatus == '2'" :span="12">
|
<el-col v-if="form.transferStatus == '2'" :span="12">
|
||||||
<el-form-item label="不测量面积(亩)" prop="noSurveyArea">
|
<el-form-item label="不测量面积(亩)" prop="noSurveyArea">
|
||||||
<el-input v-model="form.noSurveyArea" type="number" placeholder="请输入不测量面积" /> </el-form-item
|
<el-input v-model="form.noSurveyArea" type="number" placeholder="请输入不测量面积" />
|
||||||
></el-col>
|
</el-form-item>
|
||||||
<el-col v-if="form.transferStatus == '2'" :span="24"
|
</el-col>
|
||||||
><el-form-item label="不签合同原因" prop="noContractReason">
|
<el-col v-if="form.transferStatus == '2'" :span="24">
|
||||||
<el-input v-model="form.noContractReason" type="textarea" placeholder="请输入内容" /> </el-form-item
|
<el-form-item label="不签合同原因" prop="noContractReason">
|
||||||
></el-col>
|
<el-input v-model="form.noContractReason" type="textarea" placeholder="请输入内容" />
|
||||||
<el-col v-if="form.transferStatus == '2'" :span="24"
|
</el-form-item>
|
||||||
><el-form-item label="不流转原因" prop="nonTransferReason">
|
</el-col>
|
||||||
<el-input v-model="form.nonTransferReason" type="textarea" placeholder="请输入内容" /> </el-form-item
|
<el-col v-if="form.transferStatus == '2'" :span="24">
|
||||||
></el-col>
|
<el-form-item label="不流转原因" prop="nonTransferReason">
|
||||||
<el-col v-if="form.transferStatus == '1'" :span="24"
|
<el-input v-model="form.nonTransferReason" type="textarea" placeholder="请输入内容" />
|
||||||
><el-form-item label="状态说明" prop="statusDescription">
|
</el-form-item>
|
||||||
<el-input v-model="form.statusDescription" type="textarea" placeholder="请输入内容" /> </el-form-item
|
</el-col>
|
||||||
></el-col>
|
<el-col v-if="form.transferStatus == '1'" :span="24">
|
||||||
<el-col v-if="form.transferStatus == '1'" :span="24"
|
<el-form-item label="状态说明" prop="statusDescription">
|
||||||
><el-form-item label="问题总结" prop="issueSummary">
|
<el-input v-model="form.statusDescription" type="textarea" placeholder="请输入内容" />
|
||||||
<el-input v-model="form.issueSummary" type="textarea" placeholder="请输入内容" /> </el-form-item
|
</el-form-item>
|
||||||
></el-col>
|
</el-col>
|
||||||
|
<el-col v-if="form.transferStatus == '1'" :span="24">
|
||||||
|
<el-form-item label="问题总结" prop="issueSummary">
|
||||||
|
<el-input v-model="form.issueSummary" type="textarea" placeholder="请输入内容" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col v-if="form.transferStatus == '1'" :span="24">
|
<el-col v-if="form.transferStatus == '1'" :span="24">
|
||||||
<el-form-item label="下一步策略" prop="nextStrategy">
|
<el-form-item label="下一步策略" prop="nextStrategy">
|
||||||
<el-input v-model="form.nextStrategy" type="textarea" placeholder="请输入内容" /> </el-form-item
|
<el-input v-model="form.nextStrategy" type="textarea" placeholder="请输入内容" />
|
||||||
></el-col>
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -190,6 +229,20 @@ import { listEnterRoad } from '@/api/system/landTransfer/enterRoad';
|
|||||||
import { LandTransferLedgerVO, LandTransferLedgerQuery, LandTransferLedgerForm } from '@/api/system/landTransfer/landTransferLedger/types';
|
import { LandTransferLedgerVO, LandTransferLedgerQuery, LandTransferLedgerForm } from '@/api/system/landTransfer/landTransferLedger/types';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import { listLandBlock } from '@/api/system/landTransfer/landBlock';
|
import { listLandBlock } from '@/api/system/landTransfer/landBlock';
|
||||||
|
import { getCurrentInstance, ComponentInternalInstance, watch, onUnmounted, onMounted } from 'vue';
|
||||||
|
import { ElFormInstance } from 'element-plus';
|
||||||
|
|
||||||
|
// 类型定义补充
|
||||||
|
interface DialogOption {
|
||||||
|
visible: boolean;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
interface PageData<T, Q> {
|
||||||
|
form: T;
|
||||||
|
queryParams: Q;
|
||||||
|
rules: Record<string, any[]>;
|
||||||
|
}
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
// 获取用户 store
|
// 获取用户 store
|
||||||
const userStore = useUserStoreHook();
|
const userStore = useUserStoreHook();
|
||||||
@ -207,6 +260,7 @@ const landBlockList = ref([]);
|
|||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const landTransferLedgerFormRef = ref<ElFormInstance>();
|
const landTransferLedgerFormRef = ref<ElFormInstance>();
|
||||||
const enterRoadList = ref([]);
|
const enterRoadList = ref([]);
|
||||||
|
// 字典数据
|
||||||
const { land_type, land_transfer_status } = toRefs<any>(proxy?.useDict('land_type', 'land_transfer_status'));
|
const { land_type, land_transfer_status } = toRefs<any>(proxy?.useDict('land_type', 'land_transfer_status'));
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
@ -214,7 +268,8 @@ const dialog = reactive<DialogOption>({
|
|||||||
title: ''
|
title: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
const initFormData = {
|
// 表单初始数据
|
||||||
|
const initFormData: LandTransferLedgerForm = {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
projectId: currentProject.value?.id,
|
projectId: currentProject.value?.id,
|
||||||
landType: undefined,
|
landType: undefined,
|
||||||
@ -237,6 +292,8 @@ const initFormData = {
|
|||||||
noSurveyArea: undefined,
|
noSurveyArea: undefined,
|
||||||
nonTransferReason: undefined
|
nonTransferReason: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 核心数据响应式对象
|
||||||
const data = reactive<PageData<LandTransferLedgerForm, LandTransferLedgerQuery>>({
|
const data = reactive<PageData<LandTransferLedgerForm, LandTransferLedgerQuery>>({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
@ -264,9 +321,40 @@ const data = reactive<PageData<LandTransferLedgerForm, LandTransferLedgerQuery>>
|
|||||||
rules: {
|
rules: {
|
||||||
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
||||||
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
||||||
landType: [{ required: true, message: '土地类型不能为空', trigger: 'change' }]
|
landType: [{ required: true, message: '土地类型不能为空', trigger: 'change' }],
|
||||||
|
transferRatio: [
|
||||||
|
// 动态校验:仅已流转状态下必填
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '流转比例不能为空',
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (data.form.transferStatus !== '1') {
|
||||||
|
callback(); // 非已流转状态跳过校验
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (value === undefined || value === null || value === '') {
|
||||||
|
callback(new Error('流转比例不能为空'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 比例范围校验(0-100)
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (value < 0 || value > 100) {
|
||||||
|
callback(new Error('流转比例必须在 0-100 之间'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const detailInfo = ref({
|
const detailInfo = ref({
|
||||||
transferAea: 0,
|
transferAea: 0,
|
||||||
transferRatio: 0,
|
transferRatio: 0,
|
||||||
@ -274,18 +362,53 @@ const detailInfo = ref({
|
|||||||
});
|
});
|
||||||
const { queryParams, form, rules } = toRefs(data);
|
const { queryParams, form, rules } = toRefs(data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动计算流转比例:(已流转面积 / 设计面积) × 100,保留2位小数,最大100%
|
||||||
|
*/
|
||||||
|
const calcTransferRatio = () => {
|
||||||
|
// 仅已流转状态下计算
|
||||||
|
if (form.value.transferStatus !== '1') {
|
||||||
|
form.value.transferRatio = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换为数字(避免字符串计算)
|
||||||
|
const designArea = Number(form.value.designArea) || 0;
|
||||||
|
const transferAea = Number(form.value.transferAea) || 0;
|
||||||
|
|
||||||
|
// 边界处理:设计面积为0时避免报错
|
||||||
|
if (designArea === 0) {
|
||||||
|
form.value.transferRatio = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 核心计算:限制最大100%,保留2位小数
|
||||||
|
const ratio = Math.min((transferAea / designArea) * 100, 100);
|
||||||
|
form.value.transferRatio = Number(ratio.toFixed(2));
|
||||||
|
};
|
||||||
|
|
||||||
/** 查询项目土地流转台账列表 */
|
/** 查询项目土地流转台账列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
try {
|
||||||
const res = await listLandTransferLedger(queryParams.value);
|
const res = await listLandTransferLedger(queryParams.value);
|
||||||
landTransferLedgerList.value = res.rows;
|
landTransferLedgerList.value = res.rows;
|
||||||
total.value = res.total;
|
total.value = res.total;
|
||||||
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 获取地块统计信息 */
|
||||||
const getLandBlockList = async () => {
|
const getLandBlockList = async () => {
|
||||||
let res = await landTransferLedgerCount(currentProject.value?.id);
|
try {
|
||||||
|
const res = await landTransferLedgerCount(currentProject.value?.id);
|
||||||
detailInfo.value = res.data;
|
detailInfo.value = res.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取地块统计信息失败:', error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
@ -313,92 +436,176 @@ const resetQuery = () => {
|
|||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: LandTransferLedgerVO[]) => {
|
const handleSelectionChange = (selection: LandTransferLedgerVO[]) => {
|
||||||
ids.value = selection.map((item) => item.id);
|
ids.value = selection.map((item) => item.id);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length !== 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = selection.length === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
reset();
|
||||||
form.value.transferStatus = '0';
|
form.value.transferStatus = '0'; // 默认待流转
|
||||||
dialog.visible = true;
|
|
||||||
enterRoadList.value = [];
|
enterRoadList.value = [];
|
||||||
dialog.title = '添加项目土地流转台账';
|
dialog.title = '添加项目土地流转台账';
|
||||||
|
dialog.visible = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: LandTransferLedgerVO) => {
|
const handleUpdate = async (row?: LandTransferLedgerVO) => {
|
||||||
reset();
|
reset();
|
||||||
form.value.landBlockId = row?.landBlockId;
|
|
||||||
getListRoad();
|
|
||||||
const _id = row?.id || ids.value[0];
|
const _id = row?.id || ids.value[0];
|
||||||
|
if (!_id) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 获取编辑数据
|
||||||
const res = await getLandTransferLedger(_id);
|
const res = await getLandTransferLedger(_id);
|
||||||
Object.assign(form.value, res.data);
|
Object.assign(form.value, res.data);
|
||||||
console.log(form.value);
|
// 回显地块对应的道路列表
|
||||||
|
form.value.landBlockId = row?.landBlockId;
|
||||||
dialog.visible = true;
|
await getListRoad();
|
||||||
|
// 初始化计算流转比例
|
||||||
|
calcTransferRatio();
|
||||||
|
// 打开弹窗
|
||||||
dialog.title = '修改项目土地流转台账';
|
dialog.title = '修改项目土地流转台账';
|
||||||
|
dialog.visible = true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取编辑数据失败:', error);
|
||||||
|
proxy?.$modal.msgError('加载数据失败,请重试');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
landTransferLedgerFormRef.value?.validate(async (valid: boolean) => {
|
landTransferLedgerFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (!valid) return;
|
||||||
|
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
|
try {
|
||||||
if (form.value.id) {
|
if (form.value.id) {
|
||||||
await updateLandTransferLedger(form.value).finally(() => (buttonLoading.value = false));
|
await updateLandTransferLedger(form.value);
|
||||||
} else {
|
} else {
|
||||||
await addLandTransferLedger(form.value).finally(() => (buttonLoading.value = false));
|
await addLandTransferLedger(form.value);
|
||||||
}
|
}
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
|
await getLandBlockList(); // 刷新统计信息
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('操作失败,请重试');
|
||||||
|
console.error('提交表单失败:', error);
|
||||||
|
} finally {
|
||||||
|
buttonLoading.value = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: LandTransferLedgerVO) => {
|
const handleDelete = async (row?: LandTransferLedgerVO) => {
|
||||||
const _ids = row?.id || ids.value;
|
const _ids = row?.id || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除项目土地流转台账编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
if (!_ids.length) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await proxy?.$modal.confirm(`是否确认删除项目土地流转台账编号为"${_ids}"的数据项?`);
|
||||||
await delLandTransferLedger(_ids);
|
await delLandTransferLedger(_ids);
|
||||||
proxy?.$modal.msgSuccess('删除成功');
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
await getList();
|
await getList();
|
||||||
|
await getLandBlockList(); // 刷新统计信息
|
||||||
|
} catch (error) {
|
||||||
|
console.error('删除数据失败:', error);
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
// 排除用户取消确认的情况
|
||||||
|
proxy?.$modal.msgError('删除失败,请重试');
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// 选择地块
|
|
||||||
const handleLandBlockChange = (val) => {
|
/** 选择地块后加载对应道路 */
|
||||||
getListRoad();
|
const handleLandBlockChange = async () => {
|
||||||
|
await getListRoad();
|
||||||
};
|
};
|
||||||
/** 查询地块信息列表 */
|
|
||||||
|
/** 查询地块列表 */
|
||||||
const getListLand = async () => {
|
const getListLand = async () => {
|
||||||
|
try {
|
||||||
const res = await listLandBlock({
|
const res = await listLandBlock({
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10000,
|
pageSize: 10000,
|
||||||
projectId: currentProject.value?.id
|
projectId: currentProject.value?.id
|
||||||
});
|
});
|
||||||
landBlockList.value = res.rows;
|
landBlockList.value = res.rows;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取地块列表失败:', error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
/** 查询进场道路信息列表 */
|
|
||||||
|
/** 查询进场道路列表(按地块筛选) */
|
||||||
const getListRoad = async () => {
|
const getListRoad = async () => {
|
||||||
const res = await listEnterRoad({ pageNum: 1, pageSize: 10000, projectId: currentProject.value?.id, landBlockId: form.value.landBlockId });
|
try {
|
||||||
|
const res = await listEnterRoad({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10000,
|
||||||
|
projectId: currentProject.value?.id,
|
||||||
|
landBlockId: form.value.landBlockId
|
||||||
|
});
|
||||||
enterRoadList.value = res.rows;
|
enterRoadList.value = res.rows;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取进场道路列表失败:', error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
//监听项目id刷新数据
|
|
||||||
|
/** 监听项目切换,刷新数据 */
|
||||||
const listeningProject = watch(
|
const listeningProject = watch(
|
||||||
() => currentProject.value?.id,
|
() => currentProject.value?.id,
|
||||||
(nid, oid) => {
|
async (newId) => {
|
||||||
queryParams.value.projectId = nid;
|
if (newId) {
|
||||||
getLandBlockList();
|
queryParams.value.projectId = newId;
|
||||||
getListLand();
|
await Promise.all([getLandBlockList(), getListLand(), getList()]);
|
||||||
getList();
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true } // 初始加载时触发
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** 组件卸载时清理监听 */
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
listeningProject();
|
listeningProject();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** 组件挂载时初始化数据 */
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getLandBlockList();
|
Promise.all([getLandBlockList(), getListLand(), getList()]);
|
||||||
getList();
|
|
||||||
getListLand();
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.detailbox {
|
||||||
|
width: 100%;
|
||||||
|
.box1 {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 20px 0;
|
||||||
|
> div {
|
||||||
|
width: 300px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px 15px;
|
||||||
|
border: 1px solid #e7e7e7;
|
||||||
|
margin: 0 20px;
|
||||||
|
border-radius: 6px;
|
||||||
|
> div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
> span:first-child {
|
||||||
|
font-size: 16px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
> span:last-child {
|
||||||
|
font-size: 24px;
|
||||||
|
/* font-weight: bold; */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
:leave-active-class="proxy?.animate.searchAnimate.leave">
|
|
||||||
<div v-show="showSearch" class="mb-[10px]">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
@ -9,13 +8,11 @@
|
|||||||
<el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="类别编码" prop="deptCategory">
|
<el-form-item label="类别编码" prop="deptCategory">
|
||||||
<el-input v-model="queryParams.deptCategory" placeholder="请输入类别编码" clearable style="width: 240px"
|
<el-input v-model="queryParams.deptCategory" placeholder="请输入类别编码" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
@keyup.enter="handleQuery" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="状态" prop="status">
|
<el-form-item label="状态" prop="status">
|
||||||
<el-select v-model="queryParams.status" placeholder="部门状态" clearable>
|
<el-select v-model="queryParams.status" placeholder="部门状态" clearable>
|
||||||
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label"
|
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
:value="dict.value" />
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
@ -31,8 +28,7 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10">
|
<el-row :gutter="10">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button v-hasPermi="['system:dept:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增
|
<el-button v-hasPermi="['system:dept:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增 </el-button>
|
||||||
</el-button>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
||||||
@ -41,8 +37,14 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table ref="deptTableRef" v-loading="loading" :data="deptList" row-key="deptId"
|
<el-table
|
||||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }" :default-expand-all="isExpandAll">
|
ref="deptTableRef"
|
||||||
|
v-loading="loading"
|
||||||
|
:data="deptList"
|
||||||
|
row-key="deptId"
|
||||||
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||||
|
:default-expand-all="isExpandAll"
|
||||||
|
>
|
||||||
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
|
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
|
||||||
<el-table-column prop="deptCategory" align="center" label="类别编码" width="200"></el-table-column>
|
<el-table-column prop="deptCategory" align="center" label="类别编码" width="200"></el-table-column>
|
||||||
<el-table-column prop="deptType" align="center" label="部门类型" width="200">
|
<el-table-column prop="deptType" align="center" label="部门类型" width="200">
|
||||||
@ -64,16 +66,13 @@
|
|||||||
<el-table-column fixed="right" align="center" label="操作">
|
<el-table-column fixed="right" align="center" label="操作">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="修改" placement="top">
|
<el-tooltip content="修改" placement="top">
|
||||||
<el-button v-hasPermi="['system:dept:edit']" link type="primary" icon="Edit"
|
<el-button v-hasPermi="['system:dept:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" />
|
||||||
@click="handleUpdate(scope.row)" />
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="新增" placement="top" v-if="scope.row.deptType != '2' && scope.row.deptType != '5'">
|
<el-tooltip content="新增" placement="top">
|
||||||
<el-button v-hasPermi="['system:dept:add']" link type="primary" icon="Plus"
|
<el-button v-hasPermi="['system:dept:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" />
|
||||||
@click="handleAdd(scope.row)" />
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="删除" placement="top">
|
<el-tooltip content="删除" placement="top">
|
||||||
<el-button v-hasPermi="['system:dept:remove']" link type="primary" icon="Delete"
|
<el-button v-hasPermi="['system:dept:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" />
|
||||||
@click="handleDelete(scope.row)" />
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -85,9 +84,14 @@
|
|||||||
<el-row>
|
<el-row>
|
||||||
<el-col v-if="form.parentId !== 0" :span="24">
|
<el-col v-if="form.parentId !== 0" :span="24">
|
||||||
<el-form-item label="上级部门" prop="parentId">
|
<el-form-item label="上级部门" prop="parentId">
|
||||||
<el-tree-select v-model="form.parentId" :data="deptOptions"
|
<el-tree-select
|
||||||
:props="{ value: 'deptId', label: 'deptName', children: 'children' }" value-key="deptId"
|
v-model="form.parentId"
|
||||||
placeholder="选择上级部门" check-strictly />
|
:data="deptOptions"
|
||||||
|
:props="{ value: 'deptId', label: 'deptName', children: 'children' }"
|
||||||
|
value-key="deptId"
|
||||||
|
placeholder="选择上级部门"
|
||||||
|
check-strictly
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -108,8 +112,7 @@
|
|||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="负责人" prop="leader">
|
<el-form-item label="负责人" prop="leader">
|
||||||
<el-select v-model="form.leader" placeholder="请选择负责人">
|
<el-select v-model="form.leader" placeholder="请选择负责人">
|
||||||
<el-option v-for="item in deptUserList" :key="item.userId" :label="item.userName"
|
<el-option v-for="item in deptUserList" :key="item.userId" :label="item.userName" :value="item.userId" />
|
||||||
:value="item.userId" />
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -126,32 +129,17 @@
|
|||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="部门状态">
|
<el-form-item label="部门状态">
|
||||||
<el-radio-group v-model="form.status">
|
<el-radio-group v-model="form.status">
|
||||||
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label
|
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
|
||||||
}}</el-radio>
|
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="部门类型">
|
<el-form-item label="部门类型">
|
||||||
<el-select v-model="form.deptType" placeholder="请选择部门类型" @change="changeProject">
|
<el-select v-model="form.deptType" placeholder="请选择部门类型">
|
||||||
<el-option v-for="dict in sys_dept_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
<el-option v-for="dict in sys_dept_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" v-if="form.deptType == '4'">
|
|
||||||
<el-form-item label="所属项目" prop="projectId">
|
|
||||||
<el-select v-model="form.projectId" placeholder="请选择所属项目">
|
|
||||||
<el-option v-for="item in projectList" :key="item.id" :label="item.projectName" :value="item.id" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12" v-if="form.deptType == '5'">
|
|
||||||
<el-form-item label="分包单位" prop="contractorId">
|
|
||||||
<el-select v-model="form.contractorId" placeholder="请选择分包单位">
|
|
||||||
<el-option v-for="item in contractorList" :key="item.id" :label="item.name" :value="item.id" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -336,16 +324,6 @@ const handleUpdate = async (row: DeptVO) => {
|
|||||||
dialog.title = '修改部门';
|
dialog.title = '修改部门';
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeProject = async (val: any) => {
|
|
||||||
if (val == '4' && (!projectList.value || !projectList.value.length)) {
|
|
||||||
const res = await getDeptList();
|
|
||||||
projectList.value = res.data;
|
|
||||||
} else if (val == '5' && (!contractorList.value || !contractorList.value.length)) {
|
|
||||||
const res = await optionProjectSelect(form.value.rowProjectId);
|
|
||||||
contractorList.value = res;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
deptFormRef.value?.validate(async (valid: boolean) => {
|
deptFormRef.value?.validate(async (valid: boolean) => {
|
||||||
|
@ -174,8 +174,6 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="手机号码" prop="phonenumber">
|
<el-form-item label="手机号码" prop="phonenumber">
|
||||||
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
|
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
|
||||||
@ -186,8 +184,6 @@
|
|||||||
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
|
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
|
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
|
||||||
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
|
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
|
||||||
@ -198,8 +194,6 @@
|
|||||||
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
|
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="用户性别">
|
<el-form-item label="用户性别">
|
||||||
<el-select v-model="form.sex" placeholder="请选择">
|
<el-select v-model="form.sex" placeholder="请选择">
|
||||||
@ -207,15 +201,6 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="状态">
|
|
||||||
<el-radio-group v-model="form.status">
|
|
||||||
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }} </el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="岗位">
|
<el-form-item label="岗位">
|
||||||
<el-select v-model="form.postIds" multiple placeholder="请选择">
|
<el-select v-model="form.postIds" multiple placeholder="请选择">
|
||||||
@ -229,9 +214,18 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="24">
|
||||||
<el-form-item label="角色" prop="roleIds">
|
<el-row :gutter="20" v-for="(item, index) in form.projectRoles">
|
||||||
<el-select v-model="form.roleIds" filterable multiple placeholder="请选择">
|
<el-col :span="11" :offset="0">
|
||||||
|
<el-form-item label="项目列表">
|
||||||
|
<el-select v-model="item.projectId" placeholder="请选择">
|
||||||
|
<el-option v-for="dict in projectOptions" :key="dict.id" :label="dict.shortName" :value="dict.id"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="11" :offset="0">
|
||||||
|
<el-form-item label="角色">
|
||||||
|
<el-select v-model="item.roleIds" filterable multiple placeholder="请选择">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in roleOptions"
|
v-for="item in roleOptions"
|
||||||
:key="item.roleId"
|
:key="item.roleId"
|
||||||
@ -242,8 +236,19 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="1" :offset="0">
|
||||||
|
<el-button type="primary" circle icon="Plus" @click="handleAddProject" v-if="index == 0"></el-button>
|
||||||
|
<el-button type="danger" circle icon="Delete" @click="delProject(index)" v-else></el-button>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row>
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="状态">
|
||||||
|
<el-radio-group v-model="form.status">
|
||||||
|
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }} </el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="备注">
|
<el-form-item label="备注">
|
||||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
|
||||||
@ -317,8 +322,9 @@ import { RoleVO } from '@/api/system/role/types';
|
|||||||
import { PostVO } from '@/api/system/post/types';
|
import { PostVO } from '@/api/system/post/types';
|
||||||
import { globalHeaders } from '@/utils/request';
|
import { globalHeaders } from '@/utils/request';
|
||||||
import { to } from 'await-to-js';
|
import { to } from 'await-to-js';
|
||||||
import { getRoleList, optionselect } from '@/api/system/post';
|
import { getProjectByDeptId, getRoleList, optionselect } from '@/api/system/post';
|
||||||
import ShuttleFrame from '../../project/projectRelevancy/component/ShuttleFrame.vue';
|
import ShuttleFrame from '../../project/projectRelevancy/component/ShuttleFrame.vue';
|
||||||
|
import { listProject } from '@/api/project/project';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
@ -337,6 +343,8 @@ const enabledDeptOptions = ref<DeptTreeVO[]>([]);
|
|||||||
const initPassword = ref<string>('');
|
const initPassword = ref<string>('');
|
||||||
const postOptions = ref<PostVO[]>([]);
|
const postOptions = ref<PostVO[]>([]);
|
||||||
const roleOptions = ref<RoleVO[]>([]);
|
const roleOptions = ref<RoleVO[]>([]);
|
||||||
|
const projectOptions = ref<any[]>([]);
|
||||||
|
|
||||||
/*** 用户导入参数 */
|
/*** 用户导入参数 */
|
||||||
const upload = reactive<ImportOption>({
|
const upload = reactive<ImportOption>({
|
||||||
// 是否显示弹出层(用户导入)
|
// 是否显示弹出层(用户导入)
|
||||||
@ -383,10 +391,15 @@ const initFormData: UserForm = {
|
|||||||
phonenumber: undefined,
|
phonenumber: undefined,
|
||||||
email: undefined,
|
email: undefined,
|
||||||
sex: undefined,
|
sex: undefined,
|
||||||
|
projectRoles: [
|
||||||
|
{
|
||||||
|
projectId: '',
|
||||||
|
roleIds: []
|
||||||
|
}
|
||||||
|
],
|
||||||
status: '0',
|
status: '0',
|
||||||
remark: '',
|
remark: '',
|
||||||
postIds: [],
|
postIds: [],
|
||||||
roleIds: [],
|
|
||||||
filePath: undefined
|
filePath: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -436,8 +449,7 @@ const initData: PageData<UserForm, UserQuery> = {
|
|||||||
message: '请输入正确的手机号码',
|
message: '请输入正确的手机号码',
|
||||||
trigger: 'blur'
|
trigger: 'blur'
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
roleIds: [{ required: true, message: '用户角色不能为空', trigger: 'blur' }]
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const data = reactive<PageData<UserForm, UserQuery>>(initData);
|
const data = reactive<PageData<UserForm, UserQuery>>(initData);
|
||||||
@ -473,6 +485,8 @@ const getDeptTree = async () => {
|
|||||||
const res = await api.deptTreeSelect({ isShow: '1' });
|
const res = await api.deptTreeSelect({ isShow: '1' });
|
||||||
deptOptions.value = res.data;
|
deptOptions.value = res.data;
|
||||||
enabledDeptOptions.value = filterDisabledDept(res.data);
|
enabledDeptOptions.value = filterDisabledDept(res.data);
|
||||||
|
const projectList = await listProject();
|
||||||
|
projectOptions.value = projectList.rows;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 过滤禁用的部门 */
|
/** 过滤禁用的部门 */
|
||||||
@ -494,6 +508,19 @@ const handleNodeClick = (data: DeptVO) => {
|
|||||||
handleQuery();
|
handleQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 部门选择变化 */
|
||||||
|
const handleAddProject = () => {
|
||||||
|
form.value.projectRoles.push({
|
||||||
|
projectId: '',
|
||||||
|
roleIds: []
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 删除项目 */
|
||||||
|
const delProject = (index: number) => {
|
||||||
|
form.value.projectRoles.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
@ -609,6 +636,13 @@ function submitFileForm() {
|
|||||||
/** 重置操作表单 */
|
/** 重置操作表单 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
|
form.value.projectRoles = [
|
||||||
|
{
|
||||||
|
projectId: '',
|
||||||
|
roleIds: []
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
userFormRef.value?.resetFields();
|
userFormRef.value?.resetFields();
|
||||||
};
|
};
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
@ -638,12 +672,32 @@ const handleUpdate = async (row?: UserForm) => {
|
|||||||
postOptions.value = data.posts;
|
postOptions.value = data.posts;
|
||||||
roleOptions.value = data.roles;
|
roleOptions.value = data.roles;
|
||||||
form.value.postIds = data.postIds;
|
form.value.postIds = data.postIds;
|
||||||
form.value.roleIds = data.user.roleIds;
|
form.value.projectRoles = data.projectRoles;
|
||||||
form.value.password = '';
|
form.value.password = '';
|
||||||
|
const roleList = await getRoleList(form.value.deptId);
|
||||||
|
|
||||||
|
roleOptions.value = roleList.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const validate = () => {
|
||||||
|
for (let i = 0; i < form.value.projectRoles.length; i++) {
|
||||||
|
const item = form.value.projectRoles[i];
|
||||||
|
if (!item.projectId || item.projectId.length === 0) {
|
||||||
|
proxy?.$modal.msgError(`第 ${i + 1} 行“项目列表”未填写`);
|
||||||
|
return false; // 阻止提交
|
||||||
|
}
|
||||||
|
if (!item.roleIds || item.roleIds.length === 0) {
|
||||||
|
proxy?.$modal.msgError(`第 ${i + 1} 行“角色”未填写`);
|
||||||
|
return false; // 阻止提交
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
|
const isValid = validate();
|
||||||
|
if (!isValid) return;
|
||||||
userFormRef.value?.validate(async (valid: boolean) => {
|
userFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
|
form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
|
||||||
@ -683,10 +737,16 @@ onMounted(() => {
|
|||||||
async function handleDeptChange(value: number | string) {
|
async function handleDeptChange(value: number | string) {
|
||||||
const response = await optionselect(value);
|
const response = await optionselect(value);
|
||||||
const roleList = await getRoleList(value);
|
const roleList = await getRoleList(value);
|
||||||
|
|
||||||
roleOptions.value = roleList.data;
|
roleOptions.value = roleList.data;
|
||||||
postOptions.value = response.data;
|
postOptions.value = response.data;
|
||||||
form.value.postIds = [];
|
form.value.postIds = [];
|
||||||
form.value.roleIds = [];
|
form.value.projectRoles = [
|
||||||
|
{
|
||||||
|
projectId: [],
|
||||||
|
roleIds: []
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
const shuttleVisible = ref(false);
|
const shuttleVisible = ref(false);
|
||||||
|
@ -15,12 +15,14 @@
|
|||||||
<el-option v-for="item in sheets" :key="item" :label="item" :value="item" />
|
<el-option v-for="item in sheets" :key="item" :label="item" :value="item" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="toggleExpandAll(true)">一键展开</el-button>
|
<el-button type="primary" @click="toggleExpandAll(true)">一键展开</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="toggleExpandAll(false)">一键收起</el-button>
|
<el-button type="primary" @click="toggleExpandAll(false)">一键收起</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-upload
|
<el-upload
|
||||||
ref="uploadRef"
|
ref="uploadRef"
|
||||||
@ -42,11 +44,16 @@
|
|||||||
type="warning"
|
type="warning"
|
||||||
icon="view"
|
icon="view"
|
||||||
@click="handleAudit()"
|
@click="handleAudit()"
|
||||||
v-if="versionsData.status == 'draft'"
|
v-if="versionsData.status && versionsData.status == 'draft'"
|
||||||
v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
|
v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
|
||||||
>审核</el-button
|
>审核</el-button
|
||||||
>
|
>
|
||||||
<el-button type="warning" icon="view" @click="handleAudit()" v-else v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
|
<el-button
|
||||||
|
type="warning"
|
||||||
|
icon="view"
|
||||||
|
@click="handleAudit()"
|
||||||
|
v-if="versionsData.status && versionsData.status != 'draft'"
|
||||||
|
v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
|
||||||
>查看流程</el-button
|
>查看流程</el-button
|
||||||
>
|
>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -58,12 +65,21 @@
|
|||||||
<el-table-column prop="num" label="编号" />
|
<el-table-column prop="num" label="编号" />
|
||||||
<el-table-column prop="name" label="工程或费用名称" />
|
<el-table-column prop="name" label="工程或费用名称" />
|
||||||
<el-table-column prop="unit" label="单位" />
|
<el-table-column prop="unit" label="单位" />
|
||||||
<el-table-column prop="quantity" label="数量" />
|
<el-table-column prop="quantity" label="数量">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ scope.row.children.length > 0 ? '' : scope.row.quantity }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="remark" label="单价" align="center">
|
<el-table-column prop="remark" label="单价" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:model-value="scope.row.unitPrice"
|
:model-value="scope.row.unitPrice"
|
||||||
@change="(val) => (scope.row.unitPrice = val)"
|
@change="
|
||||||
|
(val) => {
|
||||||
|
scope.row.unitPrice = val;
|
||||||
|
changePrice(scope.row);
|
||||||
|
}
|
||||||
|
"
|
||||||
:precision="2"
|
:precision="2"
|
||||||
:step="0.1"
|
:step="0.1"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
@ -82,7 +98,7 @@
|
|||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
size="small"
|
||||||
@click="handleSave(scope.row)"
|
@click="handleSave(scope.row, 'all')"
|
||||||
v-if="scope.row.quantity && scope.row.quantity != 0"
|
v-if="scope.row.quantity && scope.row.quantity != 0"
|
||||||
v-hasPermi="['tender:tenderPlanLimitList:edit']"
|
v-hasPermi="['tender:tenderPlanLimitList:edit']"
|
||||||
:disabled="versionsData.status != 'draft'"
|
:disabled="versionsData.status != 'draft'"
|
||||||
@ -133,6 +149,8 @@ const versionMap = new Map();
|
|||||||
// 切换tab
|
// 切换tab
|
||||||
const handleTabChange = (tab: string) => {
|
const handleTabChange = (tab: string) => {
|
||||||
activeTab.value = tab;
|
activeTab.value = tab;
|
||||||
|
tableData.value = [];
|
||||||
|
versionsData.value = {};
|
||||||
getVersionNums();
|
getVersionNums();
|
||||||
};
|
};
|
||||||
//切换版本
|
//切换版本
|
||||||
@ -205,6 +223,8 @@ const getSheetName = async () => {
|
|||||||
//获取表格数据
|
//获取表格数据
|
||||||
const getTableData = async () => {
|
const getTableData = async () => {
|
||||||
try {
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
projectId: currentProject.value?.id,
|
projectId: currentProject.value?.id,
|
||||||
versions: queryForm.value.versions,
|
versions: queryForm.value.versions,
|
||||||
@ -217,6 +237,8 @@ const getTableData = async () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//导入
|
//导入
|
||||||
@ -257,18 +279,21 @@ const handleExport = () => {
|
|||||||
`招标一览表${queryForm.value.sheet}.xlsx`
|
`招标一览表${queryForm.value.sheet}.xlsx`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
//确认修改
|
const modifyPrice = new Map();
|
||||||
const handleSave = (row: any) => {
|
|
||||||
|
const changePrice = (row: any) => {
|
||||||
|
modifyPrice.set(row.id, row);
|
||||||
|
// if (!row.unitPrice) {
|
||||||
|
// modifyPrice.delete(row.id);
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
//修改单价
|
||||||
|
const handleSave = (row?: any, type?: any) => {
|
||||||
try {
|
try {
|
||||||
if (!row.unitPrice) {
|
if (type == 'single') {
|
||||||
ElMessage({
|
|
||||||
message: '请输入单价',
|
|
||||||
type: 'warning'
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
updatePrice(row).then((res) => {
|
const list = [{ ...row, type: activeTab.value }];
|
||||||
|
updatePrice(list).then((res) => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: '修改成功',
|
message: '修改成功',
|
||||||
@ -277,9 +302,28 @@ const handleSave = (row: any) => {
|
|||||||
getTableData();
|
getTableData();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
if (type == 'all') {
|
||||||
|
loading.value = true;
|
||||||
|
const list = [];
|
||||||
|
modifyPrice.forEach((item) => {
|
||||||
|
list.push({ ...item, type: activeTab.value });
|
||||||
|
});
|
||||||
|
updatePrice(list).then((res) => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
ElMessage({
|
||||||
|
message: '修改成功',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
getTableData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
ElMessage({
|
||||||
loading.value = false;
|
message: '修改失败',
|
||||||
|
type: 'error'
|
||||||
|
});
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
@ -1,245 +1,78 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<el-dialog v-model="dialogVisible" title="招标文件" width="500" draggable>
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<el-form ref="ruleFormRef" style="max-width: 600px" :model="ruleForm" :rules="rules" label-width="auto">
|
||||||
<el-card shadow="always">
|
<el-form-item label="招标文件" prop="name">
|
||||||
<el-form :model="queryForm" :inline="true">
|
<file-upload
|
||||||
<el-form-item label="表名" prop="sheet">
|
v-model="form.costEstimationFile"
|
||||||
<el-select v-model="queryForm.sheet" placeholder="选择表名" @change="changeSheet">
|
:fileSize="100"
|
||||||
<el-option v-for="item in sheets" :key="item" :label="item" :value="item" />
|
:auto-upload="false"
|
||||||
</el-select>
|
uploadUrl="/tender/biddingPlan/uploadBiddingDocuments"
|
||||||
</el-form-item>
|
method="put"
|
||||||
<el-form-item>
|
ref="fileUploadRef"
|
||||||
<el-button type="primary" @click="toggleExpandAll">{{ isExpandAll ? '一键收起' : '一键展开' }}</el-button>
|
:data="{
|
||||||
</el-form-item>
|
projectId: currentProject?.id,
|
||||||
<el-form-item>
|
type: planType,
|
||||||
<el-upload
|
fileType: '1',
|
||||||
ref="uploadRef"
|
bidStatus: '0',
|
||||||
class="upload-demo"
|
id: row.id
|
||||||
:http-request="importExcel"
|
}"
|
||||||
:show-file-list="false"
|
showFileList
|
||||||
v-hasPermi="['bidding:biddingLimitList:importExcelFile']"
|
/>
|
||||||
>
|
|
||||||
<template #trigger>
|
|
||||||
<el-button type="primary">导入excel</el-button>
|
|
||||||
</template>
|
|
||||||
</el-upload>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="primary" @click="handleExport()" v-hasPermi="['bidding:biddingLimitList:export']">导出excel</el-button>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
<template #footer>
|
||||||
</transition>
|
<div class="dialog-footer">
|
||||||
<el-card shadow="never" class="mb8">
|
<el-button @click="closeDialog()"> 取消 </el-button>
|
||||||
<el-table ref="tableRef" v-loading="loading" :data="tableData" row-key="id" border lazy default-expand-all>
|
<el-button type="primary" @click="submitForm()">确定</el-button>
|
||||||
<el-table-column prop="num" label="编号" />
|
|
||||||
<el-table-column prop="name" label="工程或费用名称" />
|
|
||||||
<el-table-column prop="unit" label="单位" />
|
|
||||||
<el-table-column prop="quantity" label="数量" />
|
|
||||||
<el-table-column prop="remark" label="单价" align="center">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-input-number
|
|
||||||
:model-value="scope.row.unitPrice"
|
|
||||||
@change="(val) => (scope.row.unitPrice = val)"
|
|
||||||
:precision="2"
|
|
||||||
:step="0.1"
|
|
||||||
:controls="false"
|
|
||||||
v-if="scope.row.quantity && scope.row.quantity != 0"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="price" label="总价" align="center">
|
|
||||||
<template #default="scope">
|
|
||||||
{{ scope.row.price }}
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="price" label="操作" align="center">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
@click="handleSave(scope.row)"
|
|
||||||
v-if="scope.row.quantity && scope.row.quantity != 0"
|
|
||||||
v-hasPermi="['bidding:biddingLimitList:edit']"
|
|
||||||
>修改</el-button
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</el-card>
|
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import { obtainAllVersionNumbers } from '@/api/contract/index';
|
|
||||||
import { BiddingImportExcelFile, getTreeLimit, biddingLimitListUpdate, sheetList } from '@/api/bidding/biddingLimit';
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
||||||
|
|
||||||
const userStore = useUserStoreHook();
|
const userStore = useUserStoreHook();
|
||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
const queryForm = ref({
|
const dialogVisible = ref(false);
|
||||||
versions: '',
|
const row = ref<any>();
|
||||||
sheet: ''
|
const planType = ref<any>('');
|
||||||
|
const fileUploadRef = ref<any>();
|
||||||
|
const ruleForm = ref<any>();
|
||||||
|
const rules = ref({
|
||||||
|
costEstimationFile: [{ required: true, message: '请上传招标文件', trigger: ['blur'] }]
|
||||||
});
|
});
|
||||||
const loading = ref(false);
|
const emit = defineEmits(['success']);
|
||||||
const options = ref<any[]>([]);
|
const form = ref({
|
||||||
const sheets = ref<any[]>([]);
|
costEstimationFile: ''
|
||||||
const tableData = ref<any[]>([]);
|
|
||||||
const isExpandAll = ref(true);
|
|
||||||
// 接受父组件传递的参数
|
|
||||||
const props = defineProps({
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//获取版本号
|
const open = (rows: any, type: string) => {
|
||||||
const getVersionNums = async () => {
|
dialogVisible.value = true;
|
||||||
try {
|
console.log(rows, type);
|
||||||
const params = {
|
row.value = rows;
|
||||||
projectId: currentProject.value?.id,
|
planType.value = type;
|
||||||
pageSize: 1000,
|
|
||||||
pageNum: 1
|
|
||||||
};
|
|
||||||
|
|
||||||
const res = await obtainAllVersionNumbers(params);
|
|
||||||
if (res.code == 200) {
|
|
||||||
options.value = res.data;
|
|
||||||
if (res.data.length > 0) {
|
|
||||||
queryForm.value.versions = res.data[0];
|
|
||||||
getSheetName();
|
|
||||||
} else {
|
|
||||||
queryForm.value.versions = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
//选择版本号
|
const closeDialog = () => {
|
||||||
const changeVersions = () => {
|
dialogVisible.value = false;
|
||||||
getSheetName();
|
form.value.costEstimationFile = '';
|
||||||
|
emit('success');
|
||||||
};
|
};
|
||||||
|
const submitForm = () => {
|
||||||
//选择表名
|
fileUploadRef.value.submitUpload().then((res) => {
|
||||||
const changeSheet = () => {
|
if (res == 'noFile') {
|
||||||
getTableData();
|
|
||||||
};
|
|
||||||
|
|
||||||
//获取表名
|
|
||||||
const getSheetName = async () => {
|
|
||||||
try {
|
|
||||||
const params = {
|
|
||||||
projectId: currentProject.value?.id
|
|
||||||
// versions: queryForm.value.versions
|
|
||||||
};
|
|
||||||
const res = await sheetList(params);
|
|
||||||
if (res.code == 200) {
|
|
||||||
sheets.value = res.data;
|
|
||||||
if (res.data.length > 0) {
|
|
||||||
queryForm.value.sheet = res.data[0];
|
|
||||||
} else {
|
|
||||||
queryForm.value.sheet = '';
|
|
||||||
}
|
|
||||||
getTableData();
|
|
||||||
}
|
|
||||||
} catch (error) {}
|
|
||||||
};
|
|
||||||
//获取表格
|
|
||||||
const getTableData = async () => {
|
|
||||||
loading.value = true;
|
|
||||||
const params = {
|
|
||||||
projectId: currentProject.value?.id,
|
|
||||||
sheet: queryForm.value.sheet,
|
|
||||||
type: props.type
|
|
||||||
};
|
|
||||||
const res = await getTreeLimit(params);
|
|
||||||
loading.value = false;
|
|
||||||
if (res.code == 200) {
|
|
||||||
tableData.value = [res.data[0]];
|
|
||||||
}
|
|
||||||
console.log(loading.value);
|
|
||||||
};
|
|
||||||
//修改单价
|
|
||||||
const handleSave = (row: any) => {
|
|
||||||
try {
|
|
||||||
if (!row.unitPrice) {
|
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: '请输入单价',
|
message: '请上传招标文件',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
loading.value = true;
|
dialogVisible.value = false;
|
||||||
biddingLimitListUpdate(row).then((res) => {
|
emit('success');
|
||||||
if (res.code == 200) {
|
|
||||||
ElMessage({
|
|
||||||
message: '修改成功',
|
|
||||||
type: 'success'
|
|
||||||
});
|
|
||||||
getTableData();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage({
|
|
||||||
message: '修改失败',
|
|
||||||
type: 'error'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const tableRef = ref<any>();
|
|
||||||
|
|
||||||
const toggleExpandAll = () => {
|
|
||||||
isExpandAll.value = !isExpandAll.value;
|
|
||||||
console.log(isExpandAll.value);
|
|
||||||
|
|
||||||
tableData.value.forEach((row) => {
|
|
||||||
tableRef.value.toggleRowExpansion(row, isExpandAll.value);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
//导入
|
defineExpose({
|
||||||
const importExcel = (options: any): any => {
|
open
|
||||||
let formData = new FormData();
|
|
||||||
formData.append('file', options.file);
|
|
||||||
loading.value = true;
|
|
||||||
BiddingImportExcelFile({ projectId: currentProject.value?.id }, formData)
|
|
||||||
.then((res) => {
|
|
||||||
const { code } = res;
|
|
||||||
if (code == 200) {
|
|
||||||
proxy.$modal.msgSuccess(res.msg || '导入成功');
|
|
||||||
getTableData();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {})
|
|
||||||
.finally(() => {
|
|
||||||
loading.value = false;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
//监听项目id刷新数据
|
|
||||||
const listeningProject = watch(
|
|
||||||
() => currentProject.value?.id,
|
|
||||||
(nid, oid) => {
|
|
||||||
getVersionNums();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const handleExport = () => {
|
|
||||||
proxy?.download(
|
|
||||||
'/bidding/biddingLimitList/export',
|
|
||||||
{
|
|
||||||
projectId: currentProject.value?.id,
|
|
||||||
sheet: queryForm.value.sheet
|
|
||||||
},
|
|
||||||
`限价一览表${queryForm.value.sheet}.xlsx`
|
|
||||||
);
|
|
||||||
};
|
|
||||||
onUnmounted(() => {
|
|
||||||
listeningProject();
|
|
||||||
});
|
|
||||||
onMounted(() => {
|
|
||||||
getSheetName();
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped lang="scss"></style>
|
||||||
|
99
src/views/tender/plan/comm/winTheBid.vue
Normal file
99
src/views/tender/plan/comm/winTheBid.vue
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog v-model="dialogVisible" title="中标文件" width="500" draggable>
|
||||||
|
<el-form ref="ruleFormRef" style="max-width: 600px" :model="form" :rules="rules" label-width="auto">
|
||||||
|
<el-form-item label="中标单位" prop="winningBidder">
|
||||||
|
<el-select v-model="form.winningBidder" filterable placeholder="请选择单位" style="width: 240px">
|
||||||
|
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="招标文件" prop="name">
|
||||||
|
<file-upload
|
||||||
|
v-model="form.costEstimationFile"
|
||||||
|
:fileSize="100"
|
||||||
|
:auto-upload="false"
|
||||||
|
uploadUrl="/tender/biddingPlan/uploadBiddingDocuments"
|
||||||
|
method="put"
|
||||||
|
ref="fileUploadRef"
|
||||||
|
:data="{
|
||||||
|
projectId: currentProject?.id,
|
||||||
|
type: planType,
|
||||||
|
fileType: '0',
|
||||||
|
bidStatus: '0',
|
||||||
|
id: row.id,
|
||||||
|
winningBidderId: form.winningBidder
|
||||||
|
}"
|
||||||
|
showFileList
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="closeDialog()"> 取消 </el-button>
|
||||||
|
<el-button type="primary" @click="submitForm()">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { getUnitList } from '@/api/tender/index';
|
||||||
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
const userStore = useUserStoreHook();
|
||||||
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const row = ref<any>();
|
||||||
|
const planType = ref<any>('');
|
||||||
|
const fileUploadRef = ref<any>();
|
||||||
|
const ruleForm = ref<any>();
|
||||||
|
const options = ref<any>([]);
|
||||||
|
const rules = ref({
|
||||||
|
costEstimationFile: [{ required: true, message: '请上传招标文件', trigger: ['blur'] }]
|
||||||
|
});
|
||||||
|
const emit = defineEmits(['success']);
|
||||||
|
const form = ref({
|
||||||
|
costEstimationFile: '',
|
||||||
|
winningBidder: ''
|
||||||
|
});
|
||||||
|
const open = (rows: any, type: string) => {
|
||||||
|
dialogVisible.value = true;
|
||||||
|
console.log(rows, type);
|
||||||
|
row.value = rows;
|
||||||
|
planType.value = type;
|
||||||
|
getUnitListData();
|
||||||
|
};
|
||||||
|
const getUnitListData = async () => {
|
||||||
|
let res = await getUnitList({
|
||||||
|
projectId: currentProject.value?.id
|
||||||
|
});
|
||||||
|
if (res.code == 200) {
|
||||||
|
options.value = res.data.map((item: any) => {
|
||||||
|
return {
|
||||||
|
label: item.supplierName,
|
||||||
|
value: item.id
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log(res);
|
||||||
|
};
|
||||||
|
const closeDialog = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
form.value.winningBidder = '';
|
||||||
|
emit('success');
|
||||||
|
};
|
||||||
|
const submitForm = () => {
|
||||||
|
fileUploadRef.value.submitUpload().then((res) => {
|
||||||
|
if (res == 'noFile') {
|
||||||
|
ElMessage({
|
||||||
|
message: '请上传招标文件',
|
||||||
|
type: 'warning'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
closeDialog();
|
||||||
|
emit('success');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
defineExpose({
|
||||||
|
open
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss"></style>
|
@ -189,7 +189,8 @@
|
|||||||
<el-table-column prop="name" label="工程或费用名称" />
|
<el-table-column prop="name" label="工程或费用名称" />
|
||||||
<el-table-column prop="unit" label="单位" />
|
<el-table-column prop="unit" label="单位" />
|
||||||
<!-- <el-table-column prop="quantity" label="数量" /> -->
|
<!-- <el-table-column prop="quantity" label="数量" /> -->
|
||||||
<el-table-column prop="selectNum" label="选择数量" align="center">
|
<el-table-column prop="quantity" label="计划量" align="center" />
|
||||||
|
<el-table-column prop="selectNum" label="设计量" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:model-value="scope.row.selectNum"
|
:model-value="scope.row.selectNum"
|
||||||
@ -203,16 +204,36 @@
|
|||||||
:step="1"
|
:step="1"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
:max="Math.floor(scope.row.quantity)"
|
:max="Math.floor(scope.row.quantity)"
|
||||||
v-if="scope.row.quantity && scope.row.quantity != 0"
|
v-if="scope.row.quantity && scope.row.quantity != 0 && scope.row.unitPrice"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="unitPrice" label="单价" align="center" />
|
|
||||||
<!-- <el-table-column prop="price" label="总价" align="center">
|
<el-table-column prop="useQuantity" label="剩余量" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
{{ scope.row.price }}
|
{{
|
||||||
|
(scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) == 0
|
||||||
|
? ''
|
||||||
|
: (scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)
|
||||||
|
}}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column> -->
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="unitPrice" label="单价" align="center" />
|
||||||
|
<el-table-column prop="price" label="总价" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
{{
|
||||||
|
((scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)) *
|
||||||
|
Number(scope.row.unitPrice) ==
|
||||||
|
0
|
||||||
|
? ''
|
||||||
|
: (
|
||||||
|
((scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)) *
|
||||||
|
Number(scope.row.unitPrice)
|
||||||
|
).toFixed(2)
|
||||||
|
}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -266,6 +287,9 @@ import { useUserStoreHook } from '@/store/modules/user';
|
|||||||
import { getDicts } from '@/api/system/dict/data';
|
import { getDicts } from '@/api/system/dict/data';
|
||||||
import { Plus } from '@element-plus/icons-vue';
|
import { Plus } from '@element-plus/icons-vue';
|
||||||
import { FormInstance } from 'element-plus';
|
import { FormInstance } from 'element-plus';
|
||||||
|
import winTheBid from './comm/winTheBid.vue';
|
||||||
|
import information from './comm/planPage.vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
sheetList,
|
sheetList,
|
||||||
tenderPlanList,
|
tenderPlanList,
|
||||||
@ -279,7 +303,6 @@ import {
|
|||||||
delBiddView,
|
delBiddView,
|
||||||
editStatus
|
editStatus
|
||||||
} from '@/api/tender/index';
|
} from '@/api/tender/index';
|
||||||
import { it } from 'element-plus/es/locale/index.mjs';
|
|
||||||
|
|
||||||
const userStore = useUserStoreHook();
|
const userStore = useUserStoreHook();
|
||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
@ -275,6 +275,7 @@
|
|||||||
<el-row class="mb-4">
|
<el-row class="mb-4">
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="入库资料" prop="inputFile">
|
<el-form-item label="入库资料" prop="inputFile">
|
||||||
|
<template #label> <span class="text-red">*</span> 入库资料 </template>
|
||||||
<file-upload
|
<file-upload
|
||||||
v-model="form.inputFile"
|
v-model="form.inputFile"
|
||||||
:fileType="['doc', 'docx', 'pdf']"
|
:fileType="['doc', 'docx', 'pdf']"
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
<div v-show="showSearch" class="mb-[10px]">
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true">
|
<el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
<el-form-item>
|
<!-- <el-form-item>
|
||||||
<el-badge :value="userSelectCount" :max="10" class="item">
|
<el-badge :value="userSelectCount" :max="10" class="item">
|
||||||
<el-button type="primary" @click="openUserSelect">选择申请人</el-button>
|
<el-button type="primary" @click="openUserSelect">选择申请人</el-button>
|
||||||
</el-badge>
|
</el-badge>
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
<el-form-item label="任务名称" prop="nodeName">
|
<el-form-item label="任务名称" prop="nodeName">
|
||||||
<el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
230
vite.config.ts.timestamp-1756395377501-e6f009967ecc8.mjs
Normal file
230
vite.config.ts.timestamp-1756395377501-e6f009967ecc8.mjs
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user