This commit is contained in:
2025-08-28 14:43:23 +08:00
25 changed files with 575 additions and 170 deletions

View File

@ -6,13 +6,13 @@ VITE_APP_ENV = 'development'
# 开发环境
# 李陈杰 209
# VITE_APP_BASE_API = 'http://192.168.110.209:8899'
VITE_APP_BASE_API = 'http://192.168.110.209:8899'
# 曾涛
VITE_APP_BASE_API = 'http://192.168.110.180:8899'
# VITE_APP_BASE_API = 'http://192.168.110.180: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'

View File

@ -19,3 +19,11 @@ onMounted(() => {
});
});
</script>
<style>
* {
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+/Edge */
user-select: none; /* Standard syntax */
}
</style>

View File

@ -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
});
};

View File

@ -3,9 +3,9 @@ import { AxiosPromise } from 'axios';
import { RouteRecordRaw } from 'vue-router';
// 获取路由
export function getRouters(): AxiosPromise<RouteRecordRaw[]> {
export function getRouters(id: string): AxiosPromise<RouteRecordRaw[]> {
return request({
url: '/system/menu/getRouters',
url: '/system/menu/getRouters/' + id,
method: 'get'
});
}

View File

@ -186,3 +186,14 @@ export const uploadProjectFile = (data: any) => {
data: data
});
};
/**
* 切换项目
* @param id
*/
export const changeProject = (id: string | number) => {
return request({
url: '/project/project/changeProject/' + id,
method: 'get'
});
};

View File

@ -68,3 +68,11 @@ export const delMenu = (menuId: string | number) => {
method: 'delete'
});
};
// 获取所有路由
export const getAllRouters = () => {
return request({
url: '/system/menu/getAllRouters',
method: 'get'
});
};

View File

@ -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'
});
}

View File

@ -60,19 +60,20 @@ export interface UserForm {
nickName?: string;
password: string;
phonenumber?: string;
projectRoles?: any[];
email?: string;
sex?: string;
status: string;
remark?: string;
postIds: string[];
roleIds: string[];
filePath?: string;
}
export interface UserInfoVO {
user: UserVO;
roles: RoleVO[];
roleIds: string[];
projectRoles: any[];
posts: PostVO[];
postIds: string[];
roleGroup: string;

View File

@ -1,5 +1,5 @@
<template>
<div class="select-container">
<div class="select-container" v-loading.fullscreen.lock="fullscreenLoading">
<label for="projectSelect" class="select-label">项目列表:</label>
<el-select
id="projectSelect"
@ -19,12 +19,18 @@
import { ref, computed, watch } from 'vue';
import { useUserStore } from '@/store/modules/user';
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 projects = computed(() => [
// { id: '', name: '全部工程项目' }, // 添加空选项
...userStore.projects
]);
const proxy = getCurrentInstance()?.proxy as any;
const selectedProjectId = ref(userStore.selectedProject?.id || '');
@ -37,13 +43,60 @@ watch(
{ 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);
if (selectedProject) {
if (!selectedProject) return;
const loadingInstance = ElLoading.service({
lock: true,
text: '项目切换中...',
background: 'rgba(0, 0, 0, 0.7)'
});
await changeProject(projectId);
// 更新项目 & 权限
userStore.setSelectedProject(selectedProject);
console.log(userStore.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>
<style lang="scss" scoped>

View File

@ -1,3 +1,4 @@
import $cache from '@/plugins/cache';
import { to as tos } from 'await-to-js';
import router from './router';
import NProgress from 'nprogress';
@ -29,7 +30,7 @@ router.beforeEach(async (to, from, next) => {
} else if (isWhiteList(to.path)) {
next();
} else {
if (useUserStore().roles.length === 0) {
if (useUserStore().roles.length === 0 || $cache.local.getJSON('isCheckRole')) {
isRelogin.show = true;
// 判断当前用户是否已拉取完user_info信息
const [err] = await tos(useUserStore().getInfo());
@ -44,8 +45,11 @@ router.beforeEach(async (to, from, next) => {
accessRoutes.forEach((route) => {
if (!isHttp(route.path)) {
router.addRoute(route); // 动态添加可访问路由表
console.log('🚀 ~ route:', route);
}
});
$cache.local.remove('isCheckRole');
// @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已完成
}

View File

@ -1,6 +1,7 @@
import { createWebHistory, createRouter, RouteRecordRaw } from 'vue-router';
/* Layout */
import Layout from '@/layout/index.vue';
import usePermissionStore from '@/store/modules/permission';
/**
* Note: 路由配置项
@ -65,11 +66,7 @@ export const constantRoutes: RouteRecordRaw[] = [
component: () => import('@/views/register.vue'),
hidden: true
},
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/error/404.vue'),
hidden: true
},
{
path: '/401',
component: () => import('@/views/error/401.vue'),
@ -134,10 +131,16 @@ export const constantRoutes: RouteRecordRaw[] = [
component: () => import('@/views/gis2D/index.vue'),
hidden: true
},
{
path: '/materials/purchaseDoc/uploadCode',
component: () => import('@/views/materials/purchaseDoc/uploadCode.vue'),
hidden: true
},
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/error/404.vue'),
hidden: true
}
];
@ -231,3 +234,11 @@ const router = createRouter({
});
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);
}
});
}

View File

@ -10,6 +10,7 @@ import ParentView from '@/components/ParentView/index.vue';
import InnerLink from '@/layout/components/InnerLink/index.vue';
import { createCustomNameComponent } from '@/utils/createCustomNameComponent';
import { useUserStoreHook } from './user';
// 匹配views里面所有的.vue文件
const modules = import.meta.glob('./../../views/**/*.vue');
@ -44,7 +45,7 @@ export const usePermissionStore = defineStore('permission', () => {
sidebarRouters.value = routes;
};
const generateRoutes = async (): Promise<RouteRecordRaw[]> => {
const res = await getRouters();
const res = await getRouters(useUserStoreHook().selectedProject?.id || '0');
const { data } = res;
const sdata = JSON.parse(JSON.stringify(data));
const rdata = JSON.parse(JSON.stringify(data));

View File

@ -41,7 +41,9 @@ export const useUserStore = defineStore('user', () => {
const deptId = ref<string | number>('');
const avatar = ref('');
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 }>>([]);
// 从localStorage获取缓存的项目如果没有则默认为null
@ -66,25 +68,6 @@ export const useUserStore = defineStore('user', () => {
// 获取用户信息
const getInfo = async (): Promise<void> => {
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) {
roles.value = data.roles;
permissions.value = data.permissions;
} 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 [projectErr, projectRes] = await to(getUserProject());
if (projectRes?.data) {
@ -104,12 +87,63 @@ export const useUserStore = defineStore('user', () => {
setSelectedProject(projectList[0]);
}
}
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) {
setRoles();
permissionList.value = data.permissions;
roleList.value = data.roles;
} 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;
return Promise.resolve();
}
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) {
setRoles();
permissionList.value = data.permissions;
roleList.value = data.roles;
} 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> => {
await logoutApi();
@ -158,7 +192,9 @@ export const useUserStore = defineStore('user', () => {
setProjectTeamList,
projects,
selectedProject,
ProjectTeamList
ProjectTeamList,
setInfo,
setRoles
};
});

View File

@ -20,12 +20,10 @@ export const initSSE = (url: any) => {
});
watch(error, () => {
console.log('SSE connection error:', error.value);
error.value = null;
});
watch(data, () => {
console.log('🚀 ~ initSSE ~ data:', JSON.parse(data.value));
let label = '';
let route1 = '';
let detailId = '';
@ -33,6 +31,9 @@ export const initSSE = (url: any) => {
if (JSON.parse(data.value)) {
const obj = JSON.parse(data.value);
route1 = obj.type;
if (obj.type == 'count') {
return;
}
label = obj.content;
// detailId = obj.detailId;
data.value = null;

View File

@ -63,14 +63,7 @@
<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"
/>
<span>{{ scope.row.unitPrice }}</span>
</template>
</el-table-column>
<el-table-column prop="price" label="总价" align="center">

View File

@ -32,6 +32,15 @@
<el-form-item>
<el-button type="primary" @click="handleExport()" v-hasPermi="['bidding:biddingLimitList:export']">导出excel</el-button>
</el-form-item>
<el-form-item>
<el-button
type="primary"
:disabled="versionObj.status && versionObj.status != 'draft'"
@click="handleSave(null, 'all')"
v-hasPermi="['tender:billofquantitiesLimitList:edit']"
>一键确定</el-button
>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@ -48,7 +57,7 @@
icon="view"
@click="handleViewInfo"
v-hasPermi="['bidding:biddingLimitList:getVersionDetail']"
v-if="versionObj.status != 'draft'"
v-if="versionObj.status && versionObj.status != 'draft'"
>查看流程</el-button
>
</el-form-item>
@ -66,7 +75,12 @@
<el-input-number
:disabled="versionObj.status != 'draft'"
:model-value="scope.row.unitPrice"
@change="(val) => (scope.row.unitPrice = val)"
@change="
(val) => {
scope.row.unitPrice = val;
changePrice(scope.row);
}
"
:precision="2"
:step="0.1"
:controls="false"
@ -85,7 +99,7 @@
type="primary"
size="small"
:disabled="versionObj.status != 'draft'"
@click="handleSave(scope.row)"
@click="handleSave(scope.row, 'single')"
v-if="scope.row.quantity && scope.row.quantity != 0"
v-hasPermi="['bidding:biddingLimitList:edit']"
>确定</el-button
@ -187,18 +201,21 @@ const getTableData = async () => {
}
}
};
//修改单价
const handleSave = (row: any) => {
const modifyPrice = new Map();
const changePrice = (row: any) => {
modifyPrice.set(row.id, row);
// if (!row.unitPrice) {
// modifyPrice.delete(row.id);
// }
};
//修改单价 biddingLimitListUpdate
const handleSave = (row?: any, type?: any) => {
try {
if (!row.unitPrice) {
ElMessage({
message: '请输入单价',
type: 'warning'
});
return;
}
if (type == 'single') {
loading.value = true;
biddingLimitListUpdate(row).then((res) => {
const list = [{ ...row }];
biddingLimitListUpdate(list).then((res) => {
if (res.code == 200) {
ElMessage({
message: '修改成功',
@ -207,11 +224,30 @@ const handleSave = (row: any) => {
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) {
ElMessage({
message: '修改失败',
type: 'error'
});
} finally {
loading.value = false;
}
};
const tableRef = ref<any>();

View File

@ -26,20 +26,39 @@
<el-table-column prop="name" label="名称" />
<el-table-column prop="content" 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">
<el-date-picker v-model="scope.row.plannedBiddingTime" type="date" value-format="YYYY-MM-DD" placeholder="选择时间" />
</template>
</el-table-column>
<el-table-column prop="price" label="操作" align="center">
<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 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 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
>
</template>

View File

@ -36,13 +36,22 @@
<el-button type="primary" @click="handleExport()" v-hasPermi="['tender:billofquantitiesLimitList:export']">导出excel</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" v-if="reviewStatus == 'draft'" @click="clickApprovalSheet()">审核</el-button>
<el-button
type="primary"
:disabled="reviewStatus && reviewStatus != 'draft'"
@click="handleSave(null, 'all')"
v-hasPermi="['tender:billofquantitiesLimitList:edit']"
>一键确定</el-button
>
</el-form-item>
<el-form-item>
<el-button type="primary" v-if="reviewStatus && reviewStatus == 'draft'" @click="clickApprovalSheet()">审核</el-button>
</el-form-item>
<el-form-item>
<el-button
type="warning"
icon="view"
v-if="reviewStatus != 'draft'"
v-if="reviewStatus && reviewStatus != 'draft'"
@click="clickApprovalSheet()"
v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
>查看流程</el-button
@ -65,6 +74,7 @@
@change="
(val) => {
scope.row.unitPrice = val;
changePrice(scope.row);
}
"
:precision="2"
@ -87,7 +97,7 @@
type="primary"
size="small"
:disabled="reviewStatus != 'draft'"
@click="handleSave(scope.row)"
@click="handleSave(scope.row, 'single')"
v-if="scope.row.quantity && scope.row.quantity != 0"
v-hasPermi="['tender:billofquantitiesLimitList:edit']"
>确定</el-button
@ -220,18 +230,18 @@ const getTableData = async () => {
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 {
if (!row.unitPrice) {
ElMessage({
message: '请输入单价',
type: 'warning'
});
return;
}
if (type == 'single') {
loading.value = true;
updatePrice({ ...row, type: '1' }).then((res) => {
const list = [{ ...row, type: '1' }];
updatePrice(list).then((res) => {
if (res.code == 200) {
ElMessage({
message: '修改成功',
@ -240,11 +250,30 @@ const handleSave = (row: any) => {
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) {
ElMessage({
message: '修改失败',
type: 'error'
});
} finally {
loading.value = false;
}
};
const tableRef = ref<any>();

View File

@ -49,6 +49,11 @@
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['formalities:listOfFormalities:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="addTemplate()" v-hasPermi="['formalities:formalitiesAreConsolidated:addFormalities']"
>新增模版</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
@ -67,7 +72,7 @@
<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 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">
<template #default="scope">
<span>{{ parseTime(scope.row.planTheStartTime, '{y}-{m}-{d}') }}</span>
@ -230,6 +235,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>
<template #footer>
<span>
@ -238,6 +248,27 @@
</span>
</template>
</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>
</template>
@ -253,12 +284,15 @@ import {
editStatus,
getTemplateTreeList
} from '@/api/formalities/formalitiesAreConsolidated';
import { listListOfFormalities, addFormalities } from '@/api/formalities/listOfFormalities';
import {
FormalitiesAreConsolidatedVO,
FormalitiesAreConsolidatedQuery,
FormalitiesAreConsolidatedForm
} from '@/api/formalities/formalitiesAreConsolidated/types';
import { useUserStoreHook } from '@/store/modules/user';
import { WarningFilled } from '@element-plus/icons-vue';
const fileVisible = ref(false);
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// 获取用户 store
@ -287,6 +321,7 @@ const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const file = ref(null);
const fileParams = reactive({
pageNum: 1,
@ -404,7 +439,39 @@ const handleAdd = async () => {
tempTreeList.value = res.data;
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 () => {
// form.value.formalitiesPid = tempValue.value[tempValue.value.length - 1];

View File

@ -1,6 +1,5 @@
<template>
<formalitiesAreConsolidated ref="formalitiesAreConsolidatedRef" class="overlay" v-if="showFormalitiesAreConsolidated" />
<div class="p-2" v-else>
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">

View File

@ -86,6 +86,7 @@ import { LoginData, TenantVO } from '@/api/types';
import { to } from 'await-to-js';
import { HttpStatus } from '@/enums/RespEnum';
import { useI18n } from 'vue-i18n';
import { getAllRouters } from '@/api/system/menu';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -153,6 +154,7 @@ const handleLogin = () => {
if (!err) {
const redirectUrl = redirect.value || '/';
await router.push(redirectUrl);
loading.value = false;
} else {
loading.value = false;

View File

@ -35,7 +35,7 @@
</el-table>
<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="totalCompletionOutputValue" />
<!-- <el-table-column label="累计完工产值" align="center" prop="totalCompletionOutputValue" /> -->
<el-table-column label="分包累计结算产值" align="center" prop="subTotalSettlementOutputValue" />
<el-table-column label="业主累计结算产值" align="center" prop="ownerTotalSettlementOutputValue" />
<el-table-column label="差额" align="center" prop="differenceValue" />

View File

@ -64,32 +64,32 @@
</el-table-column>
<el-table-column label="计量单位" align="center" prop="unit">
<template #default="{ row }">
{{ row.parentId == 0 ? '' : row.unit }}
{{ row.unitType == 0 ? '' : row.unit }}
</template>
</el-table-column>
<el-table-column label="综合单价(业主)" align="center" prop="ownerPrice">
<template #default="{ row }">
{{ row.parentId == 0 ? '' : row.ownerPrice }}
{{ row.unitType == 0 ? '' : row.ownerPrice }}
</template>
</el-table-column>
<el-table-column label="综合单价(分包)" align="center" prop="constructionPrice">
<template #default="{ row }">
{{ row.parentId == 0 ? '' : row.constructionPrice }}
{{ row.unitType == 0 ? '' : row.constructionPrice }}
</template>
</el-table-column>
<el-table-column label="产值金额(业主)" align="center" prop="ownerOutputValue">
<template #default="{ row }">
{{ row.parentId == 0 ? '' : row.ownerOutputValue }}
{{ row.unitType == 0 ? '' : row.ownerOutputValue }}
</template>
</el-table-column>
<el-table-column label="产值金额(分包)" align="center" prop="constructionOutputValue">
<template #default="{ row }">
{{ row.parentId == 0 ? '' : row.constructionOutputValue }}
{{ row.unitType == 0 ? '' : row.constructionOutputValue }}
</template>
</el-table-column>
<el-table-column label="总数量" align="center" prop="total">
<template #default="{ row }">
{{ row.parentId == 0 ? '' : row.total }}
{{ row.unitType == 0 ? '' : row.total }}
</template>
</el-table-column>
<el-table-column label="关联结构" align="center" prop="relevancyStructure" width="100">
@ -128,7 +128,7 @@
check-strictly
/>
</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-option v-for="dict in progress_unit_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</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-select>
</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-option label="子项目" value="1"></el-option>
<el-option label="方阵" value="2"></el-option>
</el-select>
</el-form-item>
</el-form-item> -->
<el-form-item label="备注" prop="remark" v-if="!form.id">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
@ -433,12 +433,12 @@ const handleUpdate = async (row: ProgressCategoryVO) => {
};
const handleExport = async () => {
const ids = treeRef.value.getCheckedNodes()[0].pathNodes[0].childrenData.map((item) => item.matrixId);
const fileName = treeRef.value.getCheckedNodes()[0].pathNodes[0].label;
const ids = queryParams.value.projectId;
const fileName = matrixOptions.value.find((item) => item.projectId == ids)?.name || currentProject.value?.name || '工程项目';
proxy?.download(
'/progress/progressCategory/export',
{
ids: ids
projectId: ids
},
`${fileName}分项工程单价导入.xlsx`,
true

View File

@ -174,8 +174,6 @@
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
@ -186,8 +184,6 @@
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
<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-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="用户性别">
<el-select v-model="form.sex" placeholder="请选择">
@ -207,15 +201,6 @@
</el-select>
</el-form-item>
</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-form-item label="岗位">
<el-select v-model="form.postIds" multiple placeholder="请选择">
@ -229,9 +214,18 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="角色" prop="roleIds">
<el-select v-model="form.roleIds" filterable multiple placeholder="请选择">
<el-col :span="24">
<el-row :gutter="20" v-for="(item, index) in form.projectRoles">
<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
v-for="item in roleOptions"
:key="item.roleId"
@ -242,8 +236,19 @@
</el-select>
</el-form-item>
</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-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-form-item label="备注">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
@ -317,7 +322,7 @@ import { RoleVO } from '@/api/system/role/types';
import { PostVO } from '@/api/system/post/types';
import { globalHeaders } from '@/utils/request';
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';
const router = useRouter();
@ -337,6 +342,8 @@ const enabledDeptOptions = ref<DeptTreeVO[]>([]);
const initPassword = ref<string>('');
const postOptions = ref<PostVO[]>([]);
const roleOptions = ref<RoleVO[]>([]);
const projectOptions = ref<any[]>([]);
/*** 用户导入参数 */
const upload = reactive<ImportOption>({
// 是否显示弹出层(用户导入)
@ -383,10 +390,15 @@ const initFormData: UserForm = {
phonenumber: undefined,
email: undefined,
sex: undefined,
projectRoles: [
{
projectId: '',
roleIds: []
}
],
status: '0',
remark: '',
postIds: [],
roleIds: [],
filePath: undefined
};
@ -436,8 +448,7 @@ const initData: PageData<UserForm, UserQuery> = {
message: '请输入正确的手机号码',
trigger: 'blur'
}
],
roleIds: [{ required: true, message: '用户角色不能为空', trigger: 'blur' }]
]
}
};
const data = reactive<PageData<UserForm, UserQuery>>(initData);
@ -494,6 +505,19 @@ const handleNodeClick = (data: DeptVO) => {
handleQuery();
};
/** 部门选择变化 */
const handleAddProject = () => {
form.value.projectRoles.push({
projectId: '',
roleIds: []
});
};
/** 删除项目 */
const delProject = (index: number) => {
form.value.projectRoles.splice(index, 1);
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
@ -609,6 +633,13 @@ function submitFileForm() {
/** 重置操作表单 */
const reset = () => {
form.value = { ...initFormData };
form.value.projectRoles = [
{
projectId: '',
roleIds: []
}
];
userFormRef.value?.resetFields();
};
/** 取消按钮 */
@ -638,12 +669,34 @@ const handleUpdate = async (row?: UserForm) => {
postOptions.value = data.posts;
roleOptions.value = data.roles;
form.value.postIds = data.postIds;
form.value.roleIds = data.user.roleIds;
form.value.projectRoles = data.projectRoles;
form.value.password = '';
const roleList = await getRoleList(form.value.deptId);
const projectList = await getProjectByDeptId(form.value.deptId);
projectOptions.value = projectList.data;
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 isValid = validate();
if (!isValid) return;
userFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
@ -683,10 +736,18 @@ onMounted(() => {
async function handleDeptChange(value: number | string) {
const response = await optionselect(value);
const roleList = await getRoleList(value);
const projectList = await getProjectByDeptId(value);
projectOptions.value = projectList.data;
roleOptions.value = roleList.data;
postOptions.value = response.data;
form.value.postIds = [];
form.value.roleIds = [];
form.value.projectRoles = [
{
projectId: [],
roleIds: []
}
];
}
const shuttleVisible = ref(false);

View File

@ -15,12 +15,22 @@
<el-option v-for="item in sheets" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="toggleExpandAll(true)">一键展开</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="toggleExpandAll(false)">一键收起</el-button>
</el-form-item>
<el-form-item>
<el-button
type="primary"
:disabled="versionsData.status != 'draft'"
@click="handleSave(null, 'all')"
v-hasPermi="['tender:tenderPlanLimitList:edit']"
>一键确定</el-button
>
</el-form-item>
<el-form-item>
<el-upload
ref="uploadRef"
@ -42,11 +52,16 @@
type="warning"
icon="view"
@click="handleAudit()"
v-if="versionsData.status == 'draft'"
v-if="versionsData.status && versionsData.status == 'draft'"
v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
>审核</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-form-item>
@ -63,7 +78,12 @@
<template #default="scope">
<el-input-number
:model-value="scope.row.unitPrice"
@change="(val) => (scope.row.unitPrice = val)"
@change="
(val) => {
scope.row.unitPrice = val;
changePrice(scope.row);
}
"
:precision="2"
:step="0.1"
:controls="false"
@ -82,7 +102,7 @@
<el-button
type="primary"
size="small"
@click="handleSave(scope.row)"
@click="handleSave(scope.row, 'single')"
v-if="scope.row.quantity && scope.row.quantity != 0"
v-hasPermi="['tender:tenderPlanLimitList:edit']"
:disabled="versionsData.status != 'draft'"
@ -133,6 +153,8 @@ const versionMap = new Map();
// 切换tab
const handleTabChange = (tab: string) => {
activeTab.value = tab;
tableData.value = [];
versionsData.value = {};
getVersionNums();
};
//切换版本
@ -205,6 +227,8 @@ const getSheetName = async () => {
//获取表格数据
const getTableData = async () => {
try {
loading.value = true;
const params = {
projectId: currentProject.value?.id,
versions: queryForm.value.versions,
@ -217,6 +241,8 @@ const getTableData = async () => {
}
} catch (error) {
console.log(error);
} finally {
loading.value = false;
}
};
//导入
@ -257,18 +283,21 @@ const handleExport = () => {
`招标一览表${queryForm.value.sheet}.xlsx`
);
};
//确认修改
const handleSave = (row: any) => {
const modifyPrice = new Map();
const changePrice = (row: any) => {
modifyPrice.set(row.id, row);
// if (!row.unitPrice) {
// modifyPrice.delete(row.id);
// }
};
//修改单价
const handleSave = (row?: any, type?: any) => {
try {
if (!row.unitPrice) {
ElMessage({
message: '请输入单价',
type: 'warning'
});
return;
}
if (type == 'single') {
loading.value = true;
updatePrice(row).then((res) => {
const list = [{ ...row, type: activeTab.value }];
updatePrice(list).then((res) => {
if (res.code == 200) {
ElMessage({
message: '修改成功',
@ -277,9 +306,28 @@ const handleSave = (row: any) => {
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) {
console.log(error);
loading.value = false;
ElMessage({
message: '修改失败',
type: 'error'
});
} finally {
loading.value = false;
}