Merge branch 'main' of http://192.168.110.2:3000/taoge/mk_system into szq
10
src/App.vue
@ -8,14 +8,20 @@
|
||||
import useSettingsStore from '@/store/modules/settings';
|
||||
import { handleThemeStyle } from '@/utils/theme';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { getProjectTeam } from './utils/projectTeam';
|
||||
const appStore = useAppStore();
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
// 初始化主题样式
|
||||
handleThemeStyle(useSettingsStore().theme);
|
||||
getProjectTeam();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
* {
|
||||
-webkit-user-select: none; /* Safari */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* IE10+/Edge */
|
||||
user-select: none; /* Standard syntax */
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -21,7 +21,7 @@ export const AddbiddingUser = (data) => {
|
||||
data
|
||||
});
|
||||
};
|
||||
// 新增招投标人员
|
||||
// 查询招投标人员
|
||||
export const biddingUserList = (projectId) => {
|
||||
return request({
|
||||
url: '/bidding/biddingUser/list',
|
||||
|
||||
@ -91,3 +91,11 @@ export const getDetailsList = (query: any): AxiosPromise<any> => {
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
//获取版本详情
|
||||
export const getVersionDetails = (id: any): AxiosPromise<any> => {
|
||||
return request({
|
||||
url: '/tender/tenderPlanLimitList/getVersionDetail/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
@ -71,4 +71,16 @@ export const getFileList = (data) => {
|
||||
method: 'get',
|
||||
params: data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看收入合同附件列表
|
||||
* @param id
|
||||
*/
|
||||
export const getInfoByProjectId = (data) => {
|
||||
return request({
|
||||
url: '/bidding/listOfWinningBids/getInfoByProjectId',
|
||||
method: 'get',
|
||||
params: data
|
||||
})
|
||||
}
|
||||
@ -27,3 +27,11 @@ export const systemUserList = (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) => {
|
||||
return request({
|
||||
url: '/design/drawingreviewReceipts',
|
||||
method: 'post',
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
};
|
||||
@ -96,3 +96,10 @@ export const drawingreview = (id) => {
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
// 获取单据
|
||||
export const getDrawingreviewReceipts = (id) => {
|
||||
return request({
|
||||
url: '/design/drawingreviewReceipts/review/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
@ -24,3 +24,11 @@ export const exportWord = (params) => {
|
||||
method: 'post'
|
||||
});
|
||||
};
|
||||
// 导出模版
|
||||
export const exportExcel = (params) => {
|
||||
return request({
|
||||
url: '/design/collect/exportExcel',
|
||||
method: 'post',
|
||||
params: params
|
||||
});
|
||||
};
|
||||
|
||||
@ -116,6 +116,28 @@ export const getileDetail = (id) => {
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 获取专业列表
|
||||
* @param query
|
||||
*/
|
||||
export const majorList = (params) => {
|
||||
return request({
|
||||
url: '/design/volumeCatalog/majorList',
|
||||
method: 'get',
|
||||
params: params
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 获取人员列表
|
||||
* @param query
|
||||
*/
|
||||
export const copyUserList = (params) => {
|
||||
return request({
|
||||
url: '/design/volumeCatalog/copyUserList',
|
||||
method: 'get',
|
||||
params: params
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 获取二维码信息
|
||||
* @param query
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
FormalitiesAreConsolidatedForm,
|
||||
FormalitiesAreConsolidatedQuery
|
||||
} from '@/api/formalities/formalitiesAreConsolidated/types';
|
||||
import { ListOfFormalitiesQuery, ListOfFormalitiesVO } from '../listOfFormalities/types';
|
||||
|
||||
/**
|
||||
* 查询合规性手续合账列表
|
||||
@ -101,3 +102,17 @@ export const delFormalitiesAnnex = (id: string | number | Array<string | number>
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询手续办理清单模板属性列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const getTemplateTreeList = (query?: any): AxiosPromise<ListOfFormalitiesVO[]> => {
|
||||
return request({
|
||||
url: '/formalities/formalitiesAreConsolidated/getTree',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
@ -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
|
||||
});
|
||||
};
|
||||
|
||||
100
src/api/largeScreen/index.ts
Normal file
@ -0,0 +1,100 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { MasterVO, MasterForm, MasterQuery } from '@/api/patch/types';
|
||||
/**
|
||||
* 合同金额
|
||||
*
|
||||
*/
|
||||
export const totalAmount = () => {
|
||||
return request({
|
||||
url: '/money/big/screen/totalAmount',
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询项目位置列表
|
||||
*
|
||||
*/ export const projectGis = (clientid?: any) => {
|
||||
return request({
|
||||
url: '/money/big/screen/project/gis',
|
||||
method: 'get',
|
||||
params: clientid
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 应收实收
|
||||
*
|
||||
*/ export const incomePay = (clientid) => {
|
||||
return request({
|
||||
url: '/money/big/screen/income/pay',
|
||||
method: 'get',
|
||||
params: clientid
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 收入合同分析
|
||||
*
|
||||
*/ export const incomeAnalyze = (clientid) => {
|
||||
return request({
|
||||
url: '/money/big/screen/income/analyze',
|
||||
method: 'get',
|
||||
params: clientid
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 应付实付
|
||||
*
|
||||
*/ export const expensesPay = (clientid) => {
|
||||
return request({
|
||||
url: '/money/big/screen/expenses/pay',
|
||||
method: 'get',
|
||||
params: clientid
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 支出合同分析
|
||||
*
|
||||
*/
|
||||
export const expensesAnalyze = (clientid) => {
|
||||
return request({
|
||||
url: '/money/big/screen/expenses/analyze',
|
||||
method: 'get',
|
||||
params: clientid
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 成本
|
||||
*
|
||||
*/ export const cost = (clientid) => {
|
||||
return request({
|
||||
url: '/money/big/screen/cost',
|
||||
method: 'get',
|
||||
params: clientid
|
||||
});
|
||||
};
|
||||
|
||||
// 资金KPI
|
||||
export const monthMoney = () => {
|
||||
return request({
|
||||
url: '/money/big/screen/monthMoney',
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
// 现金流
|
||||
export const monthCash = () => {
|
||||
return request({
|
||||
url: '/money/big/screen/monthCash',
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
// 现金流总和
|
||||
|
||||
export const cashTotal = () => {
|
||||
return request({
|
||||
url: '/money/big/screen/cashTotal',
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
@ -143,3 +143,30 @@ export const getDictList = (query: any): AxiosPromise<any[]> => {
|
||||
params: query
|
||||
});
|
||||
};
|
||||
export const coryEngineeringList = (query: any): AxiosPromise<any[]> => {
|
||||
return request({
|
||||
url: '/cailiaoshebei/mrpBase/coryEngineeringList',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 获取到物资状态为已完成的版本
|
||||
*/
|
||||
export const obtainTheVersion = (query: any) => {
|
||||
return request({
|
||||
url: '/cailiaoshebei/mrpBase/obtainTheVersion',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 获取到物资剩余量
|
||||
*/
|
||||
export const mrpBaseRemaining = (query: any) => {
|
||||
return request({
|
||||
url: '/cailiaoshebei/mrpBase/remaining',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
@ -14,6 +14,18 @@ export const listCompany = (query?: CompanyQuery): AxiosPromise<CompanyVO[]> =>
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}; /**
|
||||
* 查询材料提供商
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const supplierInputGet = (query?) => {
|
||||
return request({
|
||||
url: '/supplierInput/supplierInput/getList',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -61,3 +61,25 @@ export const delMaterialIssue = (id: string | number | Array<string | number>) =
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
//获取一起名称
|
||||
export const getMaterialName = (id: any) => {
|
||||
return request({
|
||||
url: '/materials/materials/inventoryNumber/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
//获取出库记录
|
||||
export const inventoryList = (id: any) => {
|
||||
return request({
|
||||
url: '/materials/materialIssue/inventory/list/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
//获取材料表信息
|
||||
export const getMaterialInfo = (id: any) => {
|
||||
return request({
|
||||
url: '/materials/materials/listByFormCode/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
@ -61,3 +61,16 @@ export const delMaterialReceive = (id: string | number | Array<string | number>)
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 获取合同列表数据
|
||||
* @param id
|
||||
*/
|
||||
export const getContractNameList = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/materials/materialReceive/ctrList',
|
||||
params: {
|
||||
projectId: id
|
||||
},
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
70
src/api/materials/materialsUseRecord/index.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { MaterialsUseRecordVO, MaterialsUseRecordForm, MaterialsUseRecordQuery } from '@/api/materials/materialsUseRecord/types';
|
||||
|
||||
/**
|
||||
* 查询材料使用登记列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listMaterialsUseInventory = (query?: MaterialsUseRecordQuery): AxiosPromise<MaterialsUseRecordVO[]> => {
|
||||
return request({
|
||||
url: '/materials/materialsInventory/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
export const listMaterialsUseRecord = (query?: MaterialsUseRecordQuery): AxiosPromise<MaterialsUseRecordVO[]> => {
|
||||
return request({
|
||||
url: '/materials/materialsUseRecord/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询材料使用登记详细
|
||||
* @param id
|
||||
*/
|
||||
export const getMaterialsUseRecord = (id: string | number): AxiosPromise<MaterialsUseRecordVO> => {
|
||||
return request({
|
||||
url: '/materials/materialsUseRecord/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增材料使用登记
|
||||
* @param data
|
||||
*/
|
||||
export const addMaterialsUseRecord = (data: MaterialsUseRecordForm) => {
|
||||
return request({
|
||||
url: '/materials/materialsUseRecord',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改材料使用登记
|
||||
* @param data
|
||||
*/
|
||||
export const updateMaterialsUseRecord = (data: MaterialsUseRecordForm) => {
|
||||
return request({
|
||||
url: '/materials/materialsUseRecord',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除材料使用登记
|
||||
* @param id
|
||||
*/
|
||||
export const delMaterialsUseRecord = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/materials/materialsUseRecord/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
111
src/api/materials/materialsUseRecord/types.ts
Normal file
@ -0,0 +1,111 @@
|
||||
export interface MaterialsUseRecordVO {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 项目ID
|
||||
*/
|
||||
projectId: string | number;
|
||||
|
||||
/**
|
||||
* 库存ID
|
||||
*/
|
||||
inventoryId: string | number;
|
||||
|
||||
/**
|
||||
* 使用部位
|
||||
*/
|
||||
usePart: string;
|
||||
|
||||
/**
|
||||
* 使用数量
|
||||
*/
|
||||
useNumber: number;
|
||||
|
||||
/**
|
||||
* 剩余量
|
||||
*/
|
||||
residueNumber: string | number;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark: string;
|
||||
|
||||
}
|
||||
|
||||
export interface MaterialsUseRecordForm extends BaseEntity {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 项目ID
|
||||
*/
|
||||
projectId?: string | number;
|
||||
|
||||
/**
|
||||
* 库存ID
|
||||
*/
|
||||
inventoryId?: string | number;
|
||||
|
||||
/**
|
||||
* 使用部位
|
||||
*/
|
||||
usePart?: string;
|
||||
|
||||
/**
|
||||
* 使用数量
|
||||
*/
|
||||
useNumber?: number;
|
||||
|
||||
/**
|
||||
* 剩余量
|
||||
*/
|
||||
residueNumber?: string | number;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface MaterialsUseRecordQuery extends PageQuery {
|
||||
|
||||
/**
|
||||
* 项目ID
|
||||
*/
|
||||
projectId?: string | number;
|
||||
|
||||
/**
|
||||
* 库存ID
|
||||
*/
|
||||
inventoryId?: string | number;
|
||||
|
||||
/**
|
||||
* 使用部位
|
||||
*/
|
||||
usePart?: string;
|
||||
|
||||
/**
|
||||
* 使用数量
|
||||
*/
|
||||
useNumber?: number;
|
||||
|
||||
/**
|
||||
* 剩余量
|
||||
*/
|
||||
residueNumber?: string | number;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ export const totalsupplyplan = (params: any): AxiosPromise => {
|
||||
export const totalSupplyplanDetails = (id: any): AxiosPromise => {
|
||||
return request({
|
||||
url: '/design/totalsupplyplan/' + id,
|
||||
method: 'get',
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
// 修改物资-总供应计划
|
||||
@ -33,4 +33,11 @@ export const materialChangeSupplyplan = (data: any): AxiosPromise => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 总供应计划-批量编辑
|
||||
export const totalSupplyplanBatchEdit = (data: any): AxiosPromise => {
|
||||
return request({
|
||||
url: '/design/totalsupplyplan/batchEdit',
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
@ -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'
|
||||
});
|
||||
}
|
||||
|
||||
63
src/api/message/notice/index.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { NoticeVO, NoticeForm, NoticeQuery } from '@/api/message/notice/types';
|
||||
|
||||
/**
|
||||
* 查询消息列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listNotice = (query?: NoticeQuery): AxiosPromise<NoticeVO[]> => {
|
||||
return request({
|
||||
url: '/message/notice/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询消息详细
|
||||
* @param id
|
||||
*/
|
||||
export const getNotice = (id: string | number): AxiosPromise<NoticeVO> => {
|
||||
return request({
|
||||
url: '/message/notice/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增消息
|
||||
* @param data
|
||||
*/
|
||||
export const addNotice = (data: NoticeForm) => {
|
||||
return request({
|
||||
url: '/message/notice',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改消息
|
||||
* @param data
|
||||
*/
|
||||
export const updateNotice = (data: NoticeForm) => {
|
||||
return request({
|
||||
url: '/message/notice',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除消息
|
||||
* @param id
|
||||
*/
|
||||
export const delNotice = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/message/notice/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
156
src/api/message/notice/types.ts
Normal file
@ -0,0 +1,156 @@
|
||||
export interface NoticeVO {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 项目ID
|
||||
*/
|
||||
projectId: string | number;
|
||||
|
||||
/**
|
||||
* 接收通知的用户ID
|
||||
*/
|
||||
recipientId: string | number;
|
||||
|
||||
/**
|
||||
* 发送通知的用户ID(系统通知 0)
|
||||
*/
|
||||
senderId: string | number;
|
||||
|
||||
/**
|
||||
* 配置id
|
||||
*/
|
||||
configId: string | number;
|
||||
|
||||
/**
|
||||
* 详情id
|
||||
*/
|
||||
detailId: string | number;
|
||||
|
||||
/**
|
||||
* 通知内容
|
||||
*/
|
||||
content: string;
|
||||
|
||||
/**
|
||||
* 查看状态(0未读 1已读)
|
||||
*/
|
||||
viewStatus: string;
|
||||
|
||||
/**
|
||||
* 查看时间
|
||||
*/
|
||||
viewTime: string;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark: string;
|
||||
|
||||
}
|
||||
|
||||
export interface NoticeForm extends BaseEntity {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 项目ID
|
||||
*/
|
||||
projectId?: string | number;
|
||||
|
||||
/**
|
||||
* 接收通知的用户ID
|
||||
*/
|
||||
recipientId?: string | number;
|
||||
|
||||
/**
|
||||
* 发送通知的用户ID(系统通知 0)
|
||||
*/
|
||||
senderId?: string | number;
|
||||
|
||||
/**
|
||||
* 配置id
|
||||
*/
|
||||
configId?: string | number;
|
||||
|
||||
/**
|
||||
* 详情id
|
||||
*/
|
||||
detailId?: string | number;
|
||||
|
||||
/**
|
||||
* 通知内容
|
||||
*/
|
||||
content?: string;
|
||||
|
||||
/**
|
||||
* 查看状态(0未读 1已读)
|
||||
*/
|
||||
viewStatus?: string;
|
||||
|
||||
/**
|
||||
* 查看时间
|
||||
*/
|
||||
viewTime?: string;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface NoticeQuery extends PageQuery {
|
||||
|
||||
/**
|
||||
* 项目ID
|
||||
*/
|
||||
projectId?: string | number;
|
||||
|
||||
/**
|
||||
* 接收通知的用户ID
|
||||
*/
|
||||
recipientId?: string | number;
|
||||
|
||||
/**
|
||||
* 发送通知的用户ID(系统通知 0)
|
||||
*/
|
||||
senderId?: string | number;
|
||||
|
||||
/**
|
||||
* 配置id
|
||||
*/
|
||||
configId?: string | number;
|
||||
|
||||
/**
|
||||
* 详情id
|
||||
*/
|
||||
detailId?: string | number;
|
||||
|
||||
/**
|
||||
* 通知内容
|
||||
*/
|
||||
content?: string;
|
||||
|
||||
/**
|
||||
* 查看状态(0未读 1已读)
|
||||
*/
|
||||
viewStatus?: string;
|
||||
|
||||
/**
|
||||
* 查看时间
|
||||
*/
|
||||
viewTime?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -98,3 +98,26 @@ export const getMonthInfo = (query): AxiosPromise<MonthPlanVO> => {
|
||||
params: query
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 修改采购完工产值对甲
|
||||
|
||||
* @param id
|
||||
*/
|
||||
export const purchaseValueAup = (query) => {
|
||||
return request({
|
||||
url: '/out/monthPlan/purchaseValueAup',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 采购完工产值对甲
|
||||
* @param id
|
||||
*/
|
||||
export const purchaseValueA = (query) => {
|
||||
return request({
|
||||
url: '/out/monthPlan/purchaseValueA',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
@ -7,3 +7,19 @@ export function listOutTable(query: any) {
|
||||
params: query
|
||||
});
|
||||
}
|
||||
// 对甲产值和对乙产值
|
||||
export function comparisonOfOutputValue(query: any) {
|
||||
return request({
|
||||
url: '/out/table/outCompare',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
// 对甲结算和对乙结算
|
||||
export function comparisonOfSettlementValue(query: any) {
|
||||
return request({
|
||||
url: '/out/table/comparisonOfOwnerAndSub',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
24
src/api/out/purchase/index.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request';
|
||||
/**
|
||||
* 修改采购完工产值对甲
|
||||
|
||||
* @param id
|
||||
*/
|
||||
export const purchaseValueAup = (query) => {
|
||||
return request({
|
||||
url: '/out/monthPlan/purchaseValueAup',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 采购完工产值对甲
|
||||
* @param id
|
||||
*/
|
||||
export const purchaseValueA = (query) => {
|
||||
return request({
|
||||
url: '/out/monthPlan/purchaseValueA',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
@ -61,3 +61,13 @@ export const delConstructionSchedulePlan = (id: string | number | Array<string |
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 获取项目结构
|
||||
* @param id
|
||||
*/
|
||||
export const getProjectStructure = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/project/project/projectStructure/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
@ -8,11 +8,10 @@ import { ProgressCategoryVO, ProgressCategoryForm, ProgressCategoryQuery } from
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listProgressCategory = (query?: ProgressCategoryQuery): AxiosPromise<ProgressCategoryVO[]> => {
|
||||
export const listProgressCategory = (id?: string | number): AxiosPromise<any[]> => {
|
||||
return request({
|
||||
url: '/progress/progressCategory/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
url: '/progress/progressCategory/listByParent/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
@ -61,3 +60,39 @@ export const delProgressCategory = (id: string | number | Array<string | number>
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
//下载
|
||||
export const downloadProgressCategory = (data) => {
|
||||
return request({
|
||||
url: '/progress/progressCategory/export',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询分项工程单价下拉树结构
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
export const getCategoryTabList = (id?: string | number): AxiosPromise<any[]> => {
|
||||
return request({
|
||||
url: '/progress/progressCategory/listTopBySubProjectId/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询分项工程单价外层结构
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
export const getCategoryList = (id?: string | number): AxiosPromise<any[]> => {
|
||||
return request({
|
||||
url: '/progress/progressCategory/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
parentId: id
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@ -84,10 +84,10 @@ export interface ProgressCategoryVO {
|
||||
*/
|
||||
remark: string;
|
||||
|
||||
/**
|
||||
* 子对象
|
||||
*/
|
||||
children: ProgressCategoryVO[];
|
||||
/**
|
||||
* 子对象
|
||||
*/
|
||||
children: ProgressCategoryVO[];
|
||||
}
|
||||
|
||||
export interface ProgressCategoryForm extends BaseEntity {
|
||||
@ -95,6 +95,9 @@ export interface ProgressCategoryForm extends BaseEntity {
|
||||
* 主键id
|
||||
*/
|
||||
id?: string | number;
|
||||
constructionPrice?: string | number;
|
||||
ownerPrice?: string | number;
|
||||
relevancyStructure?: string;
|
||||
|
||||
/**
|
||||
* 父类别id
|
||||
@ -175,11 +178,9 @@ export interface ProgressCategoryForm extends BaseEntity {
|
||||
* 备注
|
||||
*/
|
||||
remark?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface ProgressCategoryQuery {
|
||||
|
||||
/**
|
||||
* 父类别id
|
||||
*/
|
||||
@ -255,11 +256,8 @@ export interface ProgressCategoryQuery {
|
||||
*/
|
||||
status?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { ProgressCategoryTemplateVO, ProgressCategoryTemplateForm, ProgressCategoryTemplateQuery } from '@/api/progress/progressCategoryTemplate/types';
|
||||
import {
|
||||
ProgressCategoryTemplateVO,
|
||||
ProgressCategoryTemplateForm,
|
||||
ProgressCategoryTemplateQuery
|
||||
} from '@/api/progress/progressCategoryTemplate/types';
|
||||
|
||||
/**
|
||||
* 查询进度类别模版列表
|
||||
@ -61,3 +65,22 @@ export const delProgressCategoryTemplate = (id: string | number | Array<string |
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
export const getTabList = (id: string) => {
|
||||
return request({
|
||||
url: '/progress/progressCategoryTemplate/listSystemTop/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 筛选查询进度类别模版列表
|
||||
* @param parentId
|
||||
* @returns {*}
|
||||
*/
|
||||
export const listProgressCategoryTemplateByParent = (parentId: string | number): AxiosPromise<ProgressCategoryTemplateVO[]> => {
|
||||
return request({
|
||||
url: '/progress/progressCategoryTemplate/listByParent/' + parentId,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
@ -12,7 +12,7 @@ export interface ProgressCategoryTemplateVO {
|
||||
* 计量方式(0无 1数量 2百分比)
|
||||
*/
|
||||
unitType: string;
|
||||
|
||||
parentId?: string | number;
|
||||
/**
|
||||
* 工作类型
|
||||
*/
|
||||
@ -39,7 +39,9 @@ export interface ProgressCategoryTemplateForm extends BaseEntity {
|
||||
* 主键id
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
parentId?: string | number;
|
||||
constructionType?: string;
|
||||
relevancyStructure?: string;
|
||||
/**
|
||||
* 父类别id
|
||||
*/
|
||||
@ -76,7 +78,8 @@ export interface ProgressCategoryTemplateQuery {
|
||||
* 父类别id
|
||||
*/
|
||||
pid?: string | number;
|
||||
|
||||
parentId?: string | number;
|
||||
constructionType?: string;
|
||||
/**
|
||||
* 类别名称
|
||||
*/
|
||||
|
||||
@ -28,10 +28,10 @@ export interface ContractorVO {
|
||||
* 管理人联系电话
|
||||
*/
|
||||
custodianPhone: string;
|
||||
/**
|
||||
/**
|
||||
* 分包类型
|
||||
*/
|
||||
contractorType?: string;
|
||||
contractorType?: string;
|
||||
|
||||
/**
|
||||
* 公司相关文件
|
||||
@ -54,6 +54,14 @@ export interface ContractorForm extends BaseEntity {
|
||||
* 主键id
|
||||
*/
|
||||
id?: string | number;
|
||||
/**
|
||||
* 供应商id
|
||||
*/
|
||||
supplierId?: string | number;
|
||||
/**
|
||||
* 供应商
|
||||
*/
|
||||
supplier?: string;
|
||||
|
||||
/**
|
||||
* 主键id
|
||||
@ -127,10 +135,10 @@ export interface ContractorQuery extends PageQuery {
|
||||
* 管理人联系电话
|
||||
*/
|
||||
custodianPhone?: string;
|
||||
/**
|
||||
/**
|
||||
* 分包类型
|
||||
*/
|
||||
contractorType?: string;
|
||||
contractorType?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
|
||||
@ -96,8 +96,6 @@ export const addProjectFacilities = (data: any) => {
|
||||
* @param data
|
||||
*/
|
||||
export const addProjectPilePoint = (data: any) => {
|
||||
console.log('🚀 ~ addProjectPilePoint ~ data:', data);
|
||||
|
||||
return request({
|
||||
url: '/facility/photovoltaicPanelPoint/parts/geoJson',
|
||||
method: 'post',
|
||||
@ -186,3 +184,82 @@ export const uploadProjectFile = (data: any) => {
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 切换项目
|
||||
* @param id
|
||||
*/
|
||||
export const changeProject = (id: string | number) => {
|
||||
return request({
|
||||
url: '/project/project/changeProject/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 打卡规则
|
||||
* @param id
|
||||
*/
|
||||
export const attendanceRuleEdit = (data) => {
|
||||
return request({
|
||||
url: '/project/attendanceRule',
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 打卡规则
|
||||
* @param id
|
||||
*/
|
||||
export const attendanceRuleAdd = (data) => {
|
||||
return request({
|
||||
url: '/project/attendanceRule',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 获取规则
|
||||
* @param id
|
||||
*/
|
||||
export const byProjectIdDetail = (id) => {
|
||||
return request({
|
||||
url: '/project/attendanceRule/byProjectId/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
// 新增项目打卡范围
|
||||
export const addAttendanceRange = (data) => {
|
||||
return request({
|
||||
url: '/project/projectPunchrange',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
// 删除项目打卡范围
|
||||
export const delAttendanceRange = (id) => {
|
||||
return request({
|
||||
url: '/project/projectPunchrange/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 修改项目打卡范围
|
||||
export const updateAttendanceRange = (data) => {
|
||||
return request({
|
||||
url: '/project/projectPunchrange',
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
// 查询项目打卡范围列表
|
||||
export const getAttendanceRangeList = (data) => {
|
||||
return request({
|
||||
url: '/project/projectPunchrange/list',
|
||||
method: 'get',
|
||||
params: data
|
||||
});
|
||||
};
|
||||
@ -8,7 +8,7 @@ import { SupplierInputVO, SupplierInputForm, SupplierInputQuery } from '@/api/su
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listSupplierInput = (query?: SupplierInputQuery): AxiosPromise<SupplierInputVO[]> => {
|
||||
export const listSupplierInput = (query?: any): AxiosPromise<SupplierInputVO[]> => {
|
||||
return request({
|
||||
url: '/supplierInput/supplierInput/list',
|
||||
method: 'get',
|
||||
|
||||
@ -61,3 +61,12 @@ export const delEnterRoad = (id: string | number | Array<string | number>) => {
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
// 道路信息导入
|
||||
export const importEnterRoad = (projectId: any, data: any) => {
|
||||
return request({
|
||||
url: '/land/enterRoad/upload/' + projectId,
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
@ -76,3 +76,12 @@ export const delLandBlock = (id: string | number | Array<string | number>) => {
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
// 地块信息导入
|
||||
export const importLandBlock = (projectId:any,data: any) => {
|
||||
return request({
|
||||
url: '/land/landBlock/upload/'+projectId,
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
@ -69,3 +69,13 @@ export const delLandTransferLedger = (id: string | number | Array<string | numbe
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 获取详情
|
||||
* @param id
|
||||
*/
|
||||
export const landTransferLedgerCount = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/land/landTransferLedger/count/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
@ -20,18 +20,20 @@ export const getMenu = (menuId: string | number): AxiosPromise<MenuVO> => {
|
||||
};
|
||||
|
||||
// 查询菜单下拉树结构
|
||||
export const treeselect = (): AxiosPromise<MenuTreeOption[]> => {
|
||||
export const treeselect = (params?: any): AxiosPromise<MenuTreeOption[]> => {
|
||||
return request({
|
||||
url: '/system/menu/treeselect',
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
// 根据角色ID查询菜单下拉树结构
|
||||
export const roleMenuTreeselect = (roleId: string | number): AxiosPromise<RoleMenuTree> => {
|
||||
export const roleMenuTreeselect = (roleId: string | number, params?: any): AxiosPromise<RoleMenuTree> => {
|
||||
return request({
|
||||
url: '/system/menu/roleMenuTreeselect/' + roleId,
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
@ -68,3 +70,11 @@ export const delMenu = (menuId: string | number) => {
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
// 获取所有路由
|
||||
export const getAllRouters = () => {
|
||||
return request({
|
||||
url: '/system/menu/getAllRouters',
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
@ -12,9 +12,9 @@ export function listPost(query: { pageNum: number; pageSize: number }): AxiosPro
|
||||
}
|
||||
|
||||
// 查询岗位列表
|
||||
export function listTreeByProject(projectId: string): AxiosPromise<PostVO[]> {
|
||||
export function listTreeByProject(): AxiosPromise<PostVO[]> {
|
||||
return request({
|
||||
url: '/system/dept/list/treeByProjectId/' + projectId,
|
||||
url: '/system/dept/list/tree',
|
||||
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'
|
||||
});
|
||||
}
|
||||
|
||||
@ -147,10 +147,11 @@ export const authUserSelectAll = (data: any) => {
|
||||
});
|
||||
};
|
||||
// 根据角色ID查询部门树结构
|
||||
export const deptTreeSelect = (roleId: string | number): AxiosPromise<RoleDeptTree> => {
|
||||
export const deptTreeSelect = (roleId: string | number, params?) => {
|
||||
return request({
|
||||
url: '/system/role/deptTree/' + roleId,
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -91,3 +91,41 @@ export const getTenderPlanDetail = (query: any): AxiosPromise<any> => {
|
||||
params: query
|
||||
});
|
||||
};
|
||||
//查看招标文件
|
||||
export const biddViewLook = (query: any): AxiosPromise<any> => {
|
||||
return request({
|
||||
url: '/tender/biddingPlan/getAnnex',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
//删除招标文件
|
||||
export const delBiddView = (query: any): AxiosPromise<any> => {
|
||||
return request({
|
||||
url: '/tender/biddingPlanAnnex/' + query.ids,
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
//获取招标单位
|
||||
export const getUnitList = (query: any): AxiosPromise<any> => {
|
||||
return request({
|
||||
url: '/supplierInput/supplierInput/getList',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
//修改状态
|
||||
export const editStatus = (query: any): AxiosPromise<any> => {
|
||||
return request({
|
||||
url: '/tender/biddingPlan/editStatus',
|
||||
method: 'put',
|
||||
data: query
|
||||
});
|
||||
};
|
||||
//获取版本详情
|
||||
export const getVersionDetail = (id: any) => {
|
||||
return request({
|
||||
url: '/tender/tenderPlanLimitList/getVersionDetail/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
BIN
src/assets/demo/avatar.png
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
BIN
src/assets/demo/back.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
src/assets/demo/gaojing.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
src/assets/demo/rain.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
src/assets/demo/wcl.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
src/assets/demo/yichuli.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
src/assets/demo/zzcl.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
@ -288,3 +288,14 @@ h6 {
|
||||
.top-right-btn {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.text-two-lines {
|
||||
display: -webkit-box; /* 触发弹性盒模型 */
|
||||
-webkit-box-orient: vertical; /* 垂直排列文本行 */
|
||||
-webkit-line-clamp: 2; /* 限制显示2行 */
|
||||
/* 3. 超出部分处理 */
|
||||
overflow: hidden; /* 隐藏超出容器的内容 */
|
||||
text-overflow: ellipsis; /* 超出部分显示省略号 */
|
||||
/* 可选:优化文本间距 */
|
||||
line-height: 1.5; /* 行高,控制两行的垂直间距 */
|
||||
}
|
||||
|
||||
@ -1,28 +1,14 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-upload
|
||||
v-if="type === 'url'"
|
||||
:action="upload.url"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:on-success="handleUploadSuccess"
|
||||
:on-error="handleUploadError"
|
||||
class="editor-img-uploader"
|
||||
name="file"
|
||||
:show-file-list="false"
|
||||
:headers="upload.headers"
|
||||
>
|
||||
<el-upload v-if="type === 'url'" :action="upload.url" :before-upload="handleBeforeUpload"
|
||||
:on-success="handleUploadSuccess" :on-error="handleUploadError" class="editor-img-uploader" name="file"
|
||||
:show-file-list="false" :headers="upload.headers">
|
||||
<i ref="uploadRef"></i>
|
||||
</el-upload>
|
||||
</div>
|
||||
<div class="editor">
|
||||
<quill-editor
|
||||
ref="quillEditorRef"
|
||||
v-model:content="content"
|
||||
content-type="html"
|
||||
:options="options"
|
||||
:style="styles"
|
||||
@text-change="(e: any) => $emit('update:modelValue', content)"
|
||||
/>
|
||||
<quill-editor ref="quillEditorRef" v-model:content="content" content-type="html" :options="options" :style="styles"
|
||||
@text-change="(e: any) => $emit('update:modelValue', content)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -47,7 +33,9 @@ const props = defineProps({
|
||||
/* 上传文件大小限制(MB) */
|
||||
fileSize: propTypes.number.def(5),
|
||||
/* 类型(base64格式、url格式) */
|
||||
type: propTypes.string.def('url')
|
||||
type: propTypes.string.def('url'),
|
||||
/* 占位符 */
|
||||
placeholder: propTypes.string.def('请输入内容'),
|
||||
});
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@ -90,7 +78,7 @@ const options = ref<any>({
|
||||
}
|
||||
}
|
||||
},
|
||||
placeholder: '请输入内容',
|
||||
placeholder: props.placeholder,
|
||||
readOnly: props.readOnly
|
||||
});
|
||||
|
||||
@ -166,77 +154,96 @@ const handleUploadError = (err: any) => {
|
||||
.editor-img-uploader {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.editor,
|
||||
.ql-toolbar {
|
||||
white-space: pre-wrap !important;
|
||||
line-height: normal !important;
|
||||
}
|
||||
|
||||
.quill-img {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ql-snow .ql-tooltip[data-mode='link']::before {
|
||||
content: '请输入链接地址:';
|
||||
}
|
||||
|
||||
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
|
||||
border-right: 0;
|
||||
content: '保存';
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.ql-snow .ql-tooltip[data-mode='video']::before {
|
||||
content: '请输入视频地址:';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
|
||||
content: '14px';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='small']::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='small']::before {
|
||||
content: '10px';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='large']::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='large']::before {
|
||||
content: '18px';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='huge']::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='huge']::before {
|
||||
content: '32px';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
|
||||
content: '文本';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='1']::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='1']::before {
|
||||
content: '标题1';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='2']::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='2']::before {
|
||||
content: '标题2';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='3']::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='3']::before {
|
||||
content: '标题3';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='4']::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='4']::before {
|
||||
content: '标题4';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='5']::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='5']::before {
|
||||
content: '标题5';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='6']::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='6']::before {
|
||||
content: '标题6';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
|
||||
content: '标准字体';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='serif']::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='serif']::before {
|
||||
content: '衬线字体';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='monospace']::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='monospace']::before {
|
||||
content: '等宽字体';
|
||||
|
||||
@ -1,11 +1,29 @@
|
||||
<template>
|
||||
<div class="upload-file">
|
||||
<el-upload ref="fileUploadRef" multiple :action="realUploadUrl" :before-upload="handleBeforeUpload"
|
||||
:file-list="fileList" :limit="limit" :on-error="handleUploadError" :on-exceed="handleExceed"
|
||||
:on-success="handleUploadSuccess" :show-file-list="showFileList" :headers="headers" class="upload-file-uploader"
|
||||
:list-type="isConstruction ? 'picture-card' : 'text'" :accept="accept" :drag="isDarg" :data="data"
|
||||
:auto-upload="autoUpload" :on-change="handleChange" :on-remove="handleRemove" :method="method"
|
||||
:http-request="customUpload">
|
||||
<el-upload
|
||||
ref="fileUploadRef"
|
||||
multiple
|
||||
:action="realUploadUrl"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:file-list="fileList"
|
||||
:limit="limit"
|
||||
:on-error="handleUploadError"
|
||||
:on-exceed="handleExceed"
|
||||
:on-success="handleUploadSuccess"
|
||||
:show-file-list="showFileList"
|
||||
:on-preview="handlePreview"
|
||||
:headers="headers"
|
||||
class="upload-file-uploader"
|
||||
:list-type="isConstruction ? 'picture-card' : 'text'"
|
||||
:accept="accept"
|
||||
:drag="isDarg"
|
||||
:data="data"
|
||||
:auto-upload="autoUpload"
|
||||
:on-change="handleChange"
|
||||
:on-remove="handleRemove"
|
||||
:method="method"
|
||||
:http-request="customUpload"
|
||||
>
|
||||
<slot>
|
||||
<div>
|
||||
<!-- 上传按钮 -->
|
||||
@ -24,10 +42,20 @@
|
||||
的文件
|
||||
</div>
|
||||
<!-- 文件列表 -->
|
||||
<transition-group v-if="!isConstruction && !isImportInfo"
|
||||
class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul" @click.stop>
|
||||
<li style="margin-top: 10px" v-for="(file, index) in fileList" :key="file.uid"
|
||||
class="el-upload-list__item ele-upload-list__item-content">
|
||||
<transition-group
|
||||
v-if="!isConstruction && !isImportInfo"
|
||||
class="upload-file-list el-upload-list el-upload-list--text"
|
||||
name="el-fade-in-linear"
|
||||
tag="ul"
|
||||
@click.stop
|
||||
>
|
||||
<li
|
||||
style="margin-top: 10px"
|
||||
v-for="(file, index) in fileList"
|
||||
:key="file.uid"
|
||||
class="el-upload-list__item ele-upload-list__item-content"
|
||||
v-if="autoUpload"
|
||||
>
|
||||
<el-link :href="`${file.url}`" :underline="false" target="_blank">
|
||||
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
|
||||
</el-link>
|
||||
@ -180,40 +208,39 @@ watch(
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
watch(() => props.defaultFileList, () => {
|
||||
if (props.defaultFileList.length === 0) return;
|
||||
props.defaultFileList.forEach((item: any) => {
|
||||
fileList.value.push(item);
|
||||
});
|
||||
|
||||
}, { deep: true, immediate: true });
|
||||
watch(
|
||||
() => props.defaultFileList,
|
||||
() => {
|
||||
if (props.defaultFileList.length === 0) return;
|
||||
props.defaultFileList.forEach((item: any) => {
|
||||
fileList.value.push(item);
|
||||
});
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
// 上传前校检格式和大小
|
||||
const handleBeforeUpload = (file: any) => {
|
||||
// 校检文件类型
|
||||
if (props.fileType.length) {
|
||||
const fileName = file.name.split('.');
|
||||
const fileExt = fileName[fileName.length - 1];
|
||||
const isTypeOk = props.fileType.indexOf(fileExt) >= 0;
|
||||
if (!isTypeOk) {
|
||||
proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join('/')}格式文件!`);
|
||||
return false;
|
||||
}
|
||||
if (!validateFile(file)) return false;
|
||||
proxy?.$modal.loading('正在上传文件,请稍候...');
|
||||
number.value++;
|
||||
return true;
|
||||
};
|
||||
|
||||
//校检格式和大小
|
||||
const validateFile = (file: File) => {
|
||||
const ext = file.name.split('.').pop()?.toLowerCase();
|
||||
if (props.fileType.length && !props.fileType.includes(ext!)) {
|
||||
proxy?.$modal.msgError(`文件格式不正确,请上传 ${props.fileType.join('/')} 格式文件!`);
|
||||
return false;
|
||||
}
|
||||
// 校检文件名是否包含特殊字符
|
||||
if (file.name.includes(',')) {
|
||||
proxy?.$modal.msgError('文件名不正确,不能包含英文逗号!');
|
||||
return false;
|
||||
}
|
||||
// 校检文件大小
|
||||
if (props.fileSize) {
|
||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||
if (!isLt) {
|
||||
proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
|
||||
return false;
|
||||
}
|
||||
if (props.fileSize && file.size / 1024 / 1024 > props.fileSize) {
|
||||
proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
|
||||
return false;
|
||||
}
|
||||
proxy?.$modal.loading('正在上传文件,请稍候...');
|
||||
number.value++;
|
||||
return true;
|
||||
};
|
||||
|
||||
@ -254,13 +281,25 @@ const handleUploadSuccess = (res: any, file: UploadFileWithOssId) => {
|
||||
uploadedSuccessfully(res);
|
||||
};
|
||||
|
||||
const handleChange = (file: any, fileList: any) => {
|
||||
const handleChange = (file: any, filelist: any) => {
|
||||
if (!props.autoUpload) {
|
||||
// 手动上传模式:在选中文件时拦截非法文件
|
||||
const isValid = validateFile(file.raw || file);
|
||||
if (!isValid) {
|
||||
fileUploadRef.value?.handleRemove(file); // 直接移除非法文件
|
||||
console.log(file, filelist, fileList.value);
|
||||
fileList.value = [...fileList.value]; // 触发列表更新
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 记录 status = 'ready' 的文件
|
||||
if (file.status === 'ready') {
|
||||
pendingFiles.value.push(file);
|
||||
fileList.value = pendingFiles.value;
|
||||
}
|
||||
console.log(fileList.value);
|
||||
|
||||
emit('handleChange', file, fileList);
|
||||
emit('handleChange', file, filelist);
|
||||
};
|
||||
|
||||
// 删除文件
|
||||
@ -270,6 +309,12 @@ const handleRemove = (file: any, fileList: any) => {
|
||||
emit('handleRemove', file, fileList);
|
||||
};
|
||||
|
||||
const handlePreview = (file: any) => {
|
||||
if (file.url) {
|
||||
window.open(file.url);
|
||||
}
|
||||
};
|
||||
|
||||
// 删除文件
|
||||
const handleDelete = async (index: string | number, type?: string) => {
|
||||
await proxy?.$modal.confirm('是否确认删除此文件?').finally();
|
||||
@ -308,11 +353,6 @@ const uploadedSuccessfully = (res: any) => {
|
||||
emit('update:modelValue', listToString(fileList.value));
|
||||
proxy?.$modal.closeLoading();
|
||||
}
|
||||
// if (props.autoUpload && props.limit === fileList.value.length) {
|
||||
// fileUploadRef.value?.clearFiles();
|
||||
// fileList.value = [];
|
||||
// emit('update:modelValue', ''); // 同步到外部 v-model
|
||||
// }
|
||||
props.onUploadSuccess?.(fileList.value, res);
|
||||
};
|
||||
|
||||
@ -376,6 +416,11 @@ const submitUpload = async () => {
|
||||
if (!pendingFiles.value.length) {
|
||||
return 'noFile';
|
||||
}
|
||||
const validFiles = pendingFiles.value.filter((f: any) => validateFile(f.raw || f));
|
||||
if (!validFiles.length) {
|
||||
proxy?.$modal.msgError('没有符合条件的文件可上传');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
proxy?.$modal.loading('正在上传文件,请稍候...');
|
||||
const formData = new FormData();
|
||||
@ -424,7 +469,7 @@ defineExpose({ submitUpload });
|
||||
}
|
||||
}
|
||||
|
||||
>span {
|
||||
> span {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,6 +185,10 @@ const props = defineProps({
|
||||
taskVariables: {
|
||||
type: Object as () => Record<string, any>,
|
||||
default: () => {}
|
||||
},
|
||||
businessId1: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
//遮罩层
|
||||
@ -336,6 +340,9 @@ const handleCompleteTask = async () => {
|
||||
}
|
||||
if (isDrawing.value) {
|
||||
isShowSubmit.value = true;
|
||||
nextTick(() => {
|
||||
detailFormTeRef.value.getInfo(props.businessId1);
|
||||
});
|
||||
return;
|
||||
}
|
||||
await proxy?.$modal.confirm('是否确认提交?');
|
||||
@ -538,6 +545,9 @@ const handleTermination = async () => {
|
||||
const handleTerminationTask = async () => {
|
||||
if (isDrawing.value) {
|
||||
isShowTermination.value = true;
|
||||
nextTick(() => {
|
||||
detailFormTeRef.value.getInfo(props.businessId1);
|
||||
});
|
||||
return;
|
||||
}
|
||||
const params = {
|
||||
|
||||
@ -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,66 @@ 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) {
|
||||
userStore.setSelectedProject(selectedProject);
|
||||
console.log(userStore.selectedProject); // 打印选中的项目
|
||||
}
|
||||
if (!selectedProject) return;
|
||||
const loadingInstance = ElLoading.service({
|
||||
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>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
<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 : ''" />
|
||||
{{ item.meta?.title }}
|
||||
<!-- <span class="bage" v-if="item.meta?.title == '我的任务' && total > 0">{{ total }}</span> -->
|
||||
</el-menu-item>
|
||||
</template>
|
||||
|
||||
@ -26,20 +27,27 @@ import useAppStore from '@/store/modules/app';
|
||||
import useSettingsStore from '@/store/modules/settings';
|
||||
import usePermissionStore from '@/store/modules/permission';
|
||||
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);
|
||||
// 当前激活菜单的 index
|
||||
const currentIndex = ref<string>();
|
||||
// 隐藏侧边栏路由
|
||||
const hideList = ['/index', '/user/profile'];
|
||||
|
||||
const total = ref(1);
|
||||
const appStore = useAppStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const permissionStore = usePermissionStore();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
onMounted(() => {
|
||||
console.log(33333);
|
||||
getWaitingList();
|
||||
});
|
||||
// 主题颜色
|
||||
const theme = computed(() => settingsStore.theme);
|
||||
// 所有的路由信息
|
||||
@ -158,6 +166,26 @@ onBeforeUnmount(() => {
|
||||
onMounted(() => {
|
||||
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>
|
||||
|
||||
<style lang="scss">
|
||||
@ -197,4 +225,31 @@ onMounted(() => {
|
||||
.topmenu-container .svg-icon {
|
||||
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>
|
||||
|
||||
@ -23,14 +23,14 @@
|
||||
|
||||
<!-- <header-search id="header-search" class="right-menu-item" /> -->
|
||||
<search-menu ref="searchMenuRef" />
|
||||
<el-tooltip effect="dark" placement="bottom">
|
||||
<el-tooltip effect="dark" placement="bottom">
|
||||
<ProjectSelector />
|
||||
</el-tooltip>
|
||||
<!-- <el-tooltip content="搜索" effect="dark" placement="bottom">
|
||||
<el-tooltip content="搜索" effect="dark" placement="bottom">
|
||||
<div class="right-menu-item hover-effect" @click="openSearchMenu">
|
||||
<svg-icon class-name="search-icon" icon-class="search" />
|
||||
</div>
|
||||
</el-tooltip> -->
|
||||
</el-tooltip>
|
||||
<!-- 消息 -->
|
||||
<el-tooltip :content="proxy.$t('navbar.message')" effect="dark" placement="bottom">
|
||||
<div>
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
<svg-icon :icon-class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" />
|
||||
<template #title>
|
||||
<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>
|
||||
</el-menu-item>
|
||||
</app-link>
|
||||
@ -15,6 +16,7 @@
|
||||
<template v-if="item.meta" #title>
|
||||
<svg-icon :icon-class="item.meta ? item.meta.icon : ''" />
|
||||
<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>
|
||||
|
||||
<sidebar-item
|
||||
@ -34,7 +36,11 @@ import { isExternal } from '@/utils/validate';
|
||||
import AppLink from './Link.vue';
|
||||
import { getNormalPath } from '@/utils/ruoyi';
|
||||
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({
|
||||
item: {
|
||||
type: Object as PropType<RouteRecordRaw>,
|
||||
@ -49,7 +55,22 @@ const props = defineProps({
|
||||
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 hasOneShowingChild = (parent: RouteRecordRaw, children?: RouteRecordRaw[]) => {
|
||||
@ -64,12 +85,12 @@ const hasOneShowingChild = (parent: RouteRecordRaw, children?: RouteRecordRaw[])
|
||||
return true;
|
||||
});
|
||||
|
||||
// When there is only one child router, the child router is displayed by default
|
||||
// 只有一个子路由时默认显示子路由
|
||||
if (showingChildren.length === 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Show parent if there are no child router to display
|
||||
// 没有子路由可显示时显示父路由
|
||||
if (showingChildren.length === 0) {
|
||||
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true };
|
||||
return true;
|
||||
@ -98,4 +119,49 @@ const hasTitle = (title: string | undefined): string => {
|
||||
}
|
||||
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>
|
||||
|
||||
<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>
|
||||
|
||||
@ -51,11 +51,12 @@ const getTableData = async () => {
|
||||
//点击消息,写入已读
|
||||
const onNewsClick = (item: any) => {
|
||||
newsList.value[item].read = true;
|
||||
console.log('🚀 ~ onNewsClick ~ newsList.value[item]:', newsList.value[item]);
|
||||
//并且写入pinia
|
||||
noticeStore.state.value.notices = newsList.value;
|
||||
//如果有formPath,就前往
|
||||
if (newsList.value[item].route) {
|
||||
proxy?.$tab.openPage('/' + newsList.value[item].route, '', { id: newsList.value[item].detailId, type: 'view' });
|
||||
proxy?.$tab.openPage(newsList.value[item].route, '', { id: newsList.value[item].detailId, type: 'view' });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -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';
|
||||
@ -9,6 +10,8 @@ import useUserStore from '@/store/modules/user';
|
||||
import useSettingsStore from '@/store/modules/settings';
|
||||
import usePermissionStore from '@/store/modules/permission';
|
||||
|
||||
let isFirst = false;
|
||||
|
||||
NProgress.configure({ showSpinner: false });
|
||||
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));
|
||||
};
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
router.beforeEach(async (to, from) => {
|
||||
NProgress.start();
|
||||
if (to.path == '/indexEquipment' || to.path == '/materials/purchaseDoc/uploadCode' || to.path == '/codeDetail') {
|
||||
next();
|
||||
} else if (getToken()) {
|
||||
to.meta.title && useSettingsStore().setTitle(to.meta.title);
|
||||
/* has token*/
|
||||
if (to.path === '/login') {
|
||||
next({ path: '/' });
|
||||
NProgress.done();
|
||||
} else if (isWhiteList(to.path)) {
|
||||
next();
|
||||
} else {
|
||||
if (useUserStore().roles.length === 0) {
|
||||
isRelogin.show = true;
|
||||
// 判断当前用户是否已拉取完user_info信息
|
||||
const [err] = await tos(useUserStore().getInfo());
|
||||
if (err) {
|
||||
await useUserStore().logout();
|
||||
ElMessage.error(err);
|
||||
next({ path: '/' });
|
||||
} else {
|
||||
isRelogin.show = false;
|
||||
const accessRoutes = await usePermissionStore().generateRoutes();
|
||||
// 根据roles权限生成可访问的路由表
|
||||
accessRoutes.forEach((route) => {
|
||||
if (!isHttp(route.path)) {
|
||||
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已完成
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 没有token
|
||||
if (isWhiteList(to.path)) {
|
||||
// 在免登录白名单,直接进入
|
||||
next();
|
||||
} else {
|
||||
const redirect = encodeURIComponent(to.fullPath || '/');
|
||||
next(`/login?redirect=${redirect}`); // 否则全部重定向到登录页
|
||||
NProgress.done();
|
||||
}
|
||||
|
||||
// 特殊页面放行
|
||||
if (['/indexEquipment', '/materials/purchaseDoc/uploadCode', '/codeDetail'].includes(to.path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 已登录
|
||||
if (getToken()) {
|
||||
if (to.meta.title) useSettingsStore().setTitle(to.meta.title);
|
||||
|
||||
if (to.path === '/login') {
|
||||
NProgress.done();
|
||||
return { path: '/' };
|
||||
}
|
||||
|
||||
if (isWhiteList(to.path)) {
|
||||
return true;
|
||||
}
|
||||
if ((!isFirst && useUserStore().roles.length === 0) || $cache.local.getJSON('isCheckRole') === 'true') {
|
||||
isFirst = true;
|
||||
isRelogin.show = true;
|
||||
|
||||
const [err] = await tos(useUserStore().getInfo());
|
||||
|
||||
if (err) {
|
||||
await useUserStore().logout();
|
||||
ElMessage.error(err);
|
||||
NProgress.done();
|
||||
return { path: '/' };
|
||||
}
|
||||
|
||||
isRelogin.show = false;
|
||||
const accessRoutes = await usePermissionStore().generateRoutes();
|
||||
accessRoutes.forEach((route) => {
|
||||
if (!isHttp(route.path)) router.addRoute(route);
|
||||
});
|
||||
|
||||
$cache.local.remove('isCheckRole');
|
||||
|
||||
// 确保路由已添加后再跳转
|
||||
return { ...to, replace: true };
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
// 未登录
|
||||
if (isWhiteList(to.path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const redirect = encodeURIComponent(to.fullPath || '/');
|
||||
NProgress.done();
|
||||
return { path: `/login?redirect=${redirect}` };
|
||||
});
|
||||
|
||||
router.afterEach(() => {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -28,7 +28,6 @@ const getSelectedProjectFromStorage = () => {
|
||||
const getProjectTeamListFromStorage = () => {
|
||||
const stored = $cache.local.getJSON('ProjectTeamList');
|
||||
console.log('获取缓存的项目班组列表:', stored);
|
||||
|
||||
return stored ? stored : null;
|
||||
};
|
||||
|
||||
@ -41,7 +40,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,15 +67,32 @@ export const useUserStore = defineStore('user', () => {
|
||||
|
||||
// 获取用户信息
|
||||
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());
|
||||
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;
|
||||
permissionList.value = data.permissions;
|
||||
roleList.value = data.roles;
|
||||
setRoles();
|
||||
} else {
|
||||
roles.value = ['ROLE_DEFAULT'];
|
||||
}
|
||||
@ -85,30 +103,39 @@ export const useUserStore = defineStore('user', () => {
|
||||
tenantId.value = user.tenantId;
|
||||
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.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;
|
||||
getProjectTeam();
|
||||
};
|
||||
|
||||
// 注销
|
||||
const logout = async (): Promise<void> => {
|
||||
@ -158,7 +185,9 @@ export const useUserStore = defineStore('user', () => {
|
||||
setProjectTeamList,
|
||||
projects,
|
||||
selectedProject,
|
||||
ProjectTeamList
|
||||
ProjectTeamList,
|
||||
setInfo,
|
||||
setRoles
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@ -2,7 +2,11 @@ import $cache from '@/plugins/cache';
|
||||
//获取班组列表
|
||||
import { listProjectTeam } from '@/api/project/projectTeam';
|
||||
import { ProjectTeamVO } from '@/api/project/projectTeam/types';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
export const getProjectTeam = async () => {
|
||||
const isPermission = useUserStore().permissions.some((item) => item == 'project:team:list');
|
||||
if (!isPermission && useUserStore().permissions[0] != '*:*:*') return;
|
||||
|
||||
const { id } = $cache.local.getJSON('selectedProject');
|
||||
const res = await listProjectTeam({
|
||||
pageNum: 1,
|
||||
|
||||
@ -176,22 +176,26 @@ service.interceptors.response.use(
|
||||
}
|
||||
);
|
||||
// 通用下载方法
|
||||
export function download(url: string, params: any, fileName: string) {
|
||||
export function download(url: string, params: any, fileName: string, isHeader?: boolean) {
|
||||
downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' });
|
||||
// prettier-ignore
|
||||
return service.post(url, params, {
|
||||
let data={
|
||||
transformRequest: [
|
||||
(params: any) => {
|
||||
|
||||
return tansParams(params);
|
||||
}
|
||||
],
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
headers: isHeader?{'Content-Type': 'application/json'}:{ 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
responseType: 'blob'
|
||||
}).then(async (resp: any) => {
|
||||
}
|
||||
if (isHeader) delete data.transformRequest;
|
||||
return service
|
||||
.post(url, params, data as any)
|
||||
.then(async (resp: any) => {
|
||||
const isLogin = blobValidate(resp);
|
||||
if (isLogin) {
|
||||
console.log("🚀 ~ download ~ resp:", resp)
|
||||
console.log('🚀 ~ download ~ resp:', resp);
|
||||
const blob = new Blob([resp]);
|
||||
FileSaver.saveAs(blob, fileName);
|
||||
} else {
|
||||
@ -201,7 +205,8 @@ export function download(url: string, params: any, fileName: string) {
|
||||
ElMessage.error(errMsg);
|
||||
}
|
||||
downloadLoadingInstance.close();
|
||||
}).catch((r: any) => {
|
||||
})
|
||||
.catch((r: any) => {
|
||||
console.error(r);
|
||||
ElMessage.error('下载文件出现错误,请联系管理员!');
|
||||
downloadLoadingInstance.close();
|
||||
|
||||
@ -20,7 +20,6 @@ export const initSSE = (url: any) => {
|
||||
});
|
||||
|
||||
watch(error, () => {
|
||||
console.log('SSE connection error:', error.value);
|
||||
error.value = null;
|
||||
});
|
||||
|
||||
@ -31,9 +30,12 @@ export const initSSE = (url: any) => {
|
||||
try {
|
||||
if (JSON.parse(data.value)) {
|
||||
const obj = JSON.parse(data.value);
|
||||
route1 = obj.route;
|
||||
label = obj.message;
|
||||
detailId = obj.detailId;
|
||||
route1 = obj.type;
|
||||
if (obj.type == 'count') {
|
||||
return;
|
||||
}
|
||||
label = obj.content;
|
||||
// detailId = obj.detailId;
|
||||
data.value = null;
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="centerPage">
|
||||
<div class="topPage">
|
||||
<img src="@/assets/projectLarge/center.png" alt="">
|
||||
<div id="earth" style="width: 100%;height: 100%;"></div>
|
||||
</div>
|
||||
<div class="endPage" :class="{ 'slide-out-down': isHide }">
|
||||
<Title title="AI安全巡检">
|
||||
@ -30,7 +30,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
<script setup>
|
||||
import { ref, onMounted, toRefs, getCurrentInstance } from "vue"
|
||||
import Title from './title.vue'
|
||||
import { ArrowLeft, ArrowRight } from '@element-plus/icons-vue'
|
||||
@ -56,12 +56,12 @@ const inspectionList = ref([{
|
||||
picture: "",
|
||||
createTime: ""
|
||||
}])
|
||||
const swiperContent = ref<HTMLDivElement>()
|
||||
const swiperContent = ref()
|
||||
const swiperItemWidth = ref(100)
|
||||
const canLeft = ref(false)
|
||||
const canRight = ref(true)
|
||||
|
||||
const swiperClick = (direction: 'left' | 'right') => {
|
||||
const swiperClick = (direction) => {
|
||||
if (!swiperContent.value) return
|
||||
|
||||
if (direction === 'right') {
|
||||
@ -90,18 +90,67 @@ const getInspectionList = async () => {
|
||||
const { code, data } = res
|
||||
if (code === 200) {
|
||||
data.map(item => {
|
||||
item.label = violation_level_type.value.find((i: any) => i.value === item.violationType)?.label
|
||||
item.label = violation_level_type.value.find((i) => i.value === item.violationType)?.label
|
||||
})
|
||||
inspectionList.value = data
|
||||
}
|
||||
}
|
||||
// 创建地球
|
||||
const createEarth = () => {
|
||||
window.YJ.on({
|
||||
ws: true,
|
||||
// host: getIP(), //资源所在服务器地址
|
||||
// username: this.loginForm.username, //用户名 可以不登录(不填写用户名),不登录时无法加载服务端的数据
|
||||
// password: md5pass, //密码 生成方式:md5(用户名_密码)
|
||||
}).then((res) => {
|
||||
let earth = new YJ.YJEarth("earth");
|
||||
window.Earth1 = earth;
|
||||
YJ.Global.openRightClick(window.Earth1);
|
||||
YJ.Global.openLeftClick(window.Earth1);
|
||||
let view = {
|
||||
"position": {
|
||||
"lng": 102.03643298211526,
|
||||
"lat": 34.393586474501,
|
||||
"alt": 11298179.51993155
|
||||
},
|
||||
"orientation": {
|
||||
"heading": 360,
|
||||
"pitch": -89.94481747201486,
|
||||
"roll": 0
|
||||
}
|
||||
}
|
||||
loadBaseMap(earth.viewer)
|
||||
// YJ.Global.flyTo(earth, view);
|
||||
// YJ.Global.setDefaultView(earth.viewer, view)
|
||||
})
|
||||
}
|
||||
// 加载底图
|
||||
const loadBaseMap = (viewer) => {
|
||||
// 创建瓦片提供器
|
||||
const imageryProvider = new Cesium.UrlTemplateImageryProvider({
|
||||
url: 'https://webst01.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
|
||||
// 可选:设置瓦片的格式
|
||||
fileExtension: 'png',
|
||||
// 可选:设置瓦片的范围和级别
|
||||
minimumLevel: 0,
|
||||
maximumLevel: 18,
|
||||
// 可选:设置瓦片的投影(默认为Web Mercator)
|
||||
projection: Cesium.WebMercatorProjection,
|
||||
// 可选:如果瓦片服务需要跨域请求,设置请求头部
|
||||
credit: new Cesium.Credit('卫星图数据来源')
|
||||
});
|
||||
|
||||
// 添加图层到视图
|
||||
const layer = viewer.imageryLayers.addImageryProvider(imageryProvider);
|
||||
}
|
||||
onMounted(() => {
|
||||
getInspectionList()
|
||||
createEarth()
|
||||
if (swiperContent.value && swiperContent.value.children.length > 0) {
|
||||
swiperItemWidth.value = swiperContent.value.children[0].clientWidth + 20
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@ -10,27 +10,25 @@
|
||||
@click="isDisabled = false"
|
||||
class="px-8 py-2.5 transition-all duration-300 font-medium"
|
||||
v-if="isDisabled"
|
||||
v-hasPermi="['cailiaoshebei:purchaseUser:addOrUpdate']"
|
||||
v-hasPermi="['bidding:biddingUser:add']"
|
||||
>
|
||||
点击编辑
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 表单内容区域 -->
|
||||
<el-form ref="leaveFormRef" :model="form" :rules="rules" label-width="120px" class="p-6 pt30 space-y-6 h75" :disabled="isDisabled">
|
||||
<!-- 设计负责人 -->
|
||||
<div class="fonts w60% ma">
|
||||
<el-form-item label="招投标专员" prop="userId" class="mb-4">
|
||||
<el-select
|
||||
v-model="form.userId"
|
||||
v-model="form.userId" filterable
|
||||
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.userName" :value="item.userId" />
|
||||
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 提交按钮区域 -->
|
||||
<div class="flex justify-center space-x-6 mt-8 pt-6 border-t border-gray-100" v-if="!isDisabled">
|
||||
<el-button
|
||||
@ -38,7 +36,7 @@
|
||||
@click="submitForm"
|
||||
icon="Check"
|
||||
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"
|
||||
v-hasPermi="['cailiaoshebei:purchaseUser:addOrUpdate']"
|
||||
v-hasPermi="['bidding:biddingUser:add']"
|
||||
>
|
||||
确认提交
|
||||
</el-button>
|
||||
@ -53,22 +51,14 @@
|
||||
|
||||
<script setup name="PersonnelForm" lang="ts">
|
||||
import { ref, reactive, computed, onMounted, toRefs } from 'vue';
|
||||
import { getCurrentInstance } from 'vue';
|
||||
import type { ComponentInternalInstance } from 'vue';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { ElMessage, ElLoading } from 'element-plus';
|
||||
import { biddingGetUser, AddbiddingUser, biddingUserList } from '@/api/bidding/appointment';
|
||||
|
||||
// 获取当前实例
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
// 专业字典数据
|
||||
const { des_user_major } = toRefs<any>(proxy?.useDict('des_user_major'));
|
||||
const isDisabled = ref(false);
|
||||
|
||||
// 表单数据
|
||||
const form = reactive({
|
||||
id: null,
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<el-form :model="queryForm" :inline="true">
|
||||
<el-form-item label="版本号" prop="versions">
|
||||
<el-select v-model="queryForm.versions" placeholder="选择版本号" @change="changeVersions">
|
||||
<el-option v-for="item in options" :key="item.id" :label="item.versions" :value="item.id" />
|
||||
<el-option v-for="item in options" :key="item.id" :label="item.versions" :value="item.versions" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="表名" prop="sheet">
|
||||
@ -16,7 +16,7 @@
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="toggleExpandAll">{{ isExpandAll ? '一键收起' : '一键展开' }}</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<!-- <el-form-item>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
class="upload-demo"
|
||||
@ -28,11 +28,11 @@
|
||||
<el-button type="primary">导入excel</el-button>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</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-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
v-if="versionObj.status == 'draft' || versionObj.status == 'back'"
|
||||
@ -51,26 +51,20 @@
|
||||
v-if="versionObj.status != 'draft'"
|
||||
>查看流程</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
</el-form>
|
||||
</el-card>
|
||||
</transition>
|
||||
<el-card shadow="never" class="mb8">
|
||||
<el-table ref="tableRef" v-loading="loading" :data="tableData" row-key="id" border lazy default-expand-all>
|
||||
<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="name" label="工程或费用名称" />
|
||||
<el-table-column prop="unit" label="单位" align="center" />
|
||||
<el-table-column prop="quantity" label="数量" align="center" />
|
||||
<el-table-column prop="specification" label="规格" align="center" />
|
||||
<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">
|
||||
@ -78,7 +72,7 @@
|
||||
{{ scope.row.price }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="price" label="操作" align="center">
|
||||
<!-- <el-table-column prop="price" label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
@ -89,7 +83,7 @@
|
||||
>修改</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table-column> -->
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
@ -172,7 +166,9 @@ const getTableData = async () => {
|
||||
loading.value = true;
|
||||
const params = {
|
||||
projectId: currentProject.value?.id,
|
||||
sheet: queryForm.value.sheet
|
||||
sheet: queryForm.value.sheet,
|
||||
versions: queryForm.value.versions,
|
||||
type: '1'
|
||||
};
|
||||
const res = await getTreeLimit(params);
|
||||
loading.value = false;
|
||||
@ -215,8 +211,6 @@ const tableRef = ref<any>();
|
||||
|
||||
const toggleExpandAll = () => {
|
||||
isExpandAll.value = !isExpandAll.value;
|
||||
console.log(isExpandAll.value);
|
||||
|
||||
tableData.value.forEach((row) => {
|
||||
tableRef.value.toggleRowExpansion(row, isExpandAll.value);
|
||||
});
|
||||
@ -254,7 +248,7 @@ const handleExport = () => {
|
||||
projectId: currentProject.value?.id,
|
||||
sheet: queryForm.value.sheet
|
||||
},
|
||||
`限价一览表${queryForm.value.sheet}.xlsx`
|
||||
`投标成本核算清单${queryForm.value.sheet}.xlsx`
|
||||
);
|
||||
};
|
||||
// 审核
|
||||
|
||||
@ -19,13 +19,35 @@
|
||||
<h3 class="text-lg font-semibold text-gray-800">成本核算清单</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<el-form ref="leaveFormRef" disabled :model="form" :rules="rules" label-width="100px" class="space-y-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4" v-for="item in sheets" :key="item">
|
||||
<el-form-item label="表格文件">
|
||||
<span style="color: #8d8d8d">{{ item }}</span>
|
||||
</el-form-item>
|
||||
<el-form ref="leaveFormRef" v-loading="loading" :model="form" :rules="rules" label-width="100px" class="space-y-4">
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="版本号" prop="formNo">
|
||||
<el-input :disabled="true" v-model="form.versions" placeholder="请输入文件名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="表名" prop="sheet">
|
||||
<el-select v-model="form.sheet" placeholder="选择表名" @change="changeSheet">
|
||||
<el-option v-for="item in sheets" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
<el-table :data="tableData" style="width: 100%; margin-bottom: 20px; height: calc(100vh - 305px)" row-key="id" default-expand-all border>
|
||||
<el-table-column prop="num" label="编号" />
|
||||
<el-table-column prop="name" label="名称" />
|
||||
<el-table-column prop="specification" label="规格" />
|
||||
<el-table-column prop="unit" label="单位" />
|
||||
<el-table-column prop="quantity" label="数量" />
|
||||
<el-table-column prop="unitPrice" label="单价" align="center" />
|
||||
<el-table-column prop="price" label="总价" align="center">
|
||||
<template #default="scope">
|
||||
{{ scope.row.price != 0 ? Number(scope.row.price).toFixed(2) : null }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
@ -68,9 +90,9 @@ import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { getVersionDetail } from '@/api/bidding/biddingLimit';
|
||||
import { getVersionDetail, sheetList, getTreeLimit } from '@/api/bidding/biddingLimit';
|
||||
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
@ -82,8 +104,8 @@ const loading = ref(true);
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
const flowCodeOptions = [
|
||||
{
|
||||
value: currentProject.value?.id + '_costAccounting',
|
||||
label: '成本核算清单审批'
|
||||
value: currentProject.value?.id + '_biddingLimitList',
|
||||
label: '投标一览审核'
|
||||
}
|
||||
];
|
||||
|
||||
@ -99,7 +121,6 @@ const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||
//按钮组件
|
||||
const approvalButtonRef = ref<InstanceType<typeof ApprovalButton>>();
|
||||
const sheets = ref([]);
|
||||
const versions = ref({});
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
@ -124,7 +145,10 @@ const initFormData = {
|
||||
fileSuffix: undefined,
|
||||
originalName: undefined,
|
||||
remark: undefined,
|
||||
fileId: undefined
|
||||
fileId: undefined,
|
||||
status: undefined,
|
||||
versions: undefined,
|
||||
sheet: undefined
|
||||
};
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
@ -150,12 +174,49 @@ const getInfo = () => {
|
||||
buttonLoading.value = false;
|
||||
nextTick(async () => {
|
||||
const res = await getVersionDetail(routeParams.value.id);
|
||||
console.log(res);
|
||||
Object.assign(form.value, res.data);
|
||||
loading.value = false;
|
||||
buttonLoading.value = false;
|
||||
getSheetName();
|
||||
});
|
||||
};
|
||||
const sheets = ref([]);
|
||||
//获取表名
|
||||
const getSheetName = async () => {
|
||||
try {
|
||||
const params = {
|
||||
projectId: currentProject.value?.id,
|
||||
versions: form.value.versions
|
||||
};
|
||||
const res = await sheetList(params);
|
||||
if (res.code == 200) {
|
||||
sheets.value = res.data;
|
||||
if (res.data.length > 0) {
|
||||
form.value.sheet = res.data[0];
|
||||
}
|
||||
getListTable();
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
//选择表名
|
||||
const changeSheet = () => {
|
||||
getListTable();
|
||||
};
|
||||
const tableData = ref([]);
|
||||
|
||||
//获取列表
|
||||
const getListTable = async () => {
|
||||
const res = await getTreeLimit({
|
||||
projectId: currentProject.value?.id,
|
||||
versions: form.value.versions,
|
||||
sheet: form.value.sheet,
|
||||
type: '0'
|
||||
});
|
||||
if (res.code == 200) {
|
||||
tableData.value = res.data;
|
||||
}
|
||||
};
|
||||
/** 提交按钮 */
|
||||
const submitForm = (status1: string) => {
|
||||
status.value = status1;
|
||||
@ -227,12 +288,10 @@ onMounted(() => {
|
||||
nextTick(async () => {
|
||||
reset();
|
||||
routeParams.value = proxy.$route.query;
|
||||
sheets.value = routeParams.value.sheets;
|
||||
versions.value = routeParams.value.versions;
|
||||
Object.assign(form.value, versions.value);
|
||||
loading.value = false;
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getInfo();
|
||||
console.log('routeParams.value', routeParams.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
524
src/views/biddingManagemen/listOfWinningBids/index copy 2.vue
Normal file
@ -0,0 +1,524 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50 min-h-screen">
|
||||
<!-- 卡片容器:控制最大宽度+居中+圆角阴影 -->
|
||||
<el-card shadow="hover" class="max-w-6xl mx-auto rounded-xl overflow-hidden border-0" style="background-color: #ffffff">
|
||||
<!-- 卡片头部:项目信息展示区(非表单布局) -->
|
||||
<template #header>
|
||||
<div class="bg-blue-50 px-6 rounded-t-xl" style="padding: 10px 20px">
|
||||
<h3 class="el-card__header-title text-lg font-semibold text-blue-800">投标项目信息</h3>
|
||||
<h4>{{ currentProject.name }}</h4>
|
||||
<!-- 项目信息部分 -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div class="project-info-item">
|
||||
<span>负责人:</span>
|
||||
<span> {{ projectInfo.principal || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>负责人电话:</span>
|
||||
<span> {{ projectInfo.principalPhone || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>项目类型:</span>
|
||||
<span> {{ getDictLabel(project_type, projectInfo.projectType) || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>项目阶段:</span>
|
||||
<span> {{ getDictLabel(project_stage, projectInfo.projectStage) || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>开工时间:</span>
|
||||
<span> {{ projectInfo.onStreamTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>经纬度:</span>
|
||||
<span> {{ projectInfo.lng || '-' }},{{ projectInfo.lat || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item md:col-span-2 lg:col-span-3">
|
||||
<span>项目地址:</span>
|
||||
<span> {{ projectInfo.projectSite || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>计划容量(M):</span>
|
||||
<span> {{ projectInfo.plan || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>实际容量(M):</span>
|
||||
<span> {{ projectInfo.actual || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>设计总量(M):</span>
|
||||
<span> {{ projectInfo.designTotal || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item md:col-span-2 lg:col-span-3">
|
||||
<span>备注:</span>
|
||||
<span> {{ projectInfo.remark || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 mb-6">
|
||||
<el-button @click="isDisabled = false" type="primary" class="px-8 py-2.5 transition-all duration-300 font-medium" v-if="isDisabled">
|
||||
点击编辑
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 中标信息表单区域(保持原有逻辑) -->
|
||||
<el-form
|
||||
:disabled="isDisabled"
|
||||
ref="listOfWinningBidsFormRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="150px"
|
||||
class="p-6 pt-4"
|
||||
style="background-color: #ffffff"
|
||||
>
|
||||
<el-row :gutter="32">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="中标价(美元)" prop="winningBidOriginal" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model.number="form.winningBidOriginal" type="number" placeholder="请输入中标价" @input="calculateWinningBid" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="汇率" prop="exchangeRate" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model.number="form.exchangeRate" type="number" placeholder="请输入汇率" step="0.0001" @input="calculateWinningBid" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="币种" prop="currency" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.currency" placeholder="请输入币种" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="中标价(人民币)" prop="winningBid" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.winningBid" type="number" placeholder="根据美元中标价和汇率自动计算" readonly />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="中标日期" prop="bidWinningDate" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-date-picker
|
||||
clearable
|
||||
v-model="form.bidWinningDate"
|
||||
type="date"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择中标日期"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="投标保证金(人民币)" prop="bidDeposit" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.bidDeposit" type="number" placeholder="请输入投标保证金" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否退还" prop="whetherSendBack" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-radio-group v-model="form.whetherSendBack">
|
||||
<el-radio label="是" border>是</el-radio>
|
||||
<el-radio label="否" border>否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所属主体" prop="subject" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.subject" placeholder="请输入所属主体" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设单位" prop="construction" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.construction" placeholder="请输入建设单位" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="总造价" prop="totalCost" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.totalCost" placeholder="请输入总造价" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="立项申请人" prop="projectApplicant" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.projectApplicant" placeholder="请输入立项申请人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="立项部门" prop="projectApplicantDept" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.projectApplicantDept" placeholder="请输入立项部门" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="立项申请日期" prop="projectApplicantTime" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-date-picker
|
||||
clearable
|
||||
v-model="form.projectApplicantTime"
|
||||
type="date"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择立项申请日期"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- <el-col :span="12">
|
||||
<el-form-item label="项目编号" prop="projectNumbering" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.projectNumbering" placeholder="请输入项目编号" />
|
||||
</el-form-item>
|
||||
</el-col> -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="中标通知书" prop="projectNumbering" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<file-upload v-model="form.bidFile" :limit="10" :file-type="['pdf']" :file-size="50" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 操作按钮区域 -->
|
||||
<el-row v-if="!isDisabled" class="mt-8">
|
||||
<el-col :span="24" class="text-center">
|
||||
<el-button
|
||||
:loading="buttonLoading"
|
||||
type="primary"
|
||||
@click="submitForm"
|
||||
v-hasPermi="['bidding:listOfWinningBids:add', 'bidding:listOfWinningBids:edit']"
|
||||
class="rounded-full px-8"
|
||||
size="large"
|
||||
>
|
||||
确认提交
|
||||
</el-button>
|
||||
<el-button type="default" @click="resetForm" class="ml-6 rounded-full px-8" size="large"> 重置 </el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ListOfWinningBidsForm" lang="ts">
|
||||
import { ref, reactive, toRefs, watch, onMounted, onUnmounted, getCurrentInstance, ComponentInternalInstance, computed } from 'vue';
|
||||
import { addListOfWinningBids, updateListOfWinningBids, listListOfWinningBids, getListOfWinningBids } from '@/api/bidding/listOfWinningBids';
|
||||
import { ListOfWinningBidsVO, ListOfWinningBidsForm } from '@/api/bidding/listOfWinningBids/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { ElFormInstance, ElMessage } from 'element-plus';
|
||||
import { getProject, updateProject } from '@/api/project/project'; // 补充项目信息更新接口
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { project_type, project_stage } = toRefs<any>(proxy?.useDict('project_type', 'project_stage'));
|
||||
|
||||
// 用户状态管理
|
||||
const userStore = useUserStoreHook();
|
||||
// 当前选中项目(从store获取)
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
|
||||
// 项目信息(非表单绑定,直接响应式数据)
|
||||
const projectInfo = reactive({
|
||||
projectName: undefined,
|
||||
shortName: undefined,
|
||||
pId: undefined,
|
||||
status: undefined,
|
||||
picUrl: undefined,
|
||||
remark: undefined,
|
||||
projectType: undefined,
|
||||
projectCategory: undefined,
|
||||
deletedAt: undefined,
|
||||
projectSite: undefined,
|
||||
principal: undefined,
|
||||
principalPhone: undefined,
|
||||
actual: undefined,
|
||||
lng: undefined,
|
||||
lat: undefined,
|
||||
plan: undefined,
|
||||
onStreamTime: undefined,
|
||||
playCardStart: undefined,
|
||||
playCardEnd: undefined,
|
||||
designTotal: undefined,
|
||||
securityAgreement: undefined,
|
||||
sort: 0,
|
||||
showHidden: undefined,
|
||||
isDelete: undefined
|
||||
});
|
||||
|
||||
// 表单相关引用
|
||||
const listOfWinningBidsFormRef = ref<ElFormInstance>();
|
||||
// 加载状态
|
||||
const buttonLoading = ref(false);
|
||||
// 编辑/查看状态控制
|
||||
const isDisabled = ref(false);
|
||||
|
||||
// 表单初始数据
|
||||
const initFormData: ListOfWinningBidsForm = {
|
||||
id: undefined,
|
||||
projectId: currentProject.value?.id,
|
||||
projectStatus: undefined,
|
||||
projectName: undefined,
|
||||
winningBidOriginal: undefined,
|
||||
exchangeRate: undefined,
|
||||
currency: undefined,
|
||||
subject: undefined,
|
||||
winningBid: undefined,
|
||||
bidWinningDate: undefined,
|
||||
bidDeposit: undefined,
|
||||
whetherSendBack: undefined,
|
||||
construction: undefined,
|
||||
totalCost: undefined,
|
||||
projectApplicant: undefined,
|
||||
projectApplicantDept: undefined,
|
||||
projectApplicantTime: undefined,
|
||||
processStatus: undefined,
|
||||
projectNumbering: undefined
|
||||
};
|
||||
|
||||
// 表单数据与验证规则
|
||||
const data = reactive({
|
||||
form: { ...initFormData } as ListOfWinningBidsForm,
|
||||
rules: {
|
||||
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
||||
projectName: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
|
||||
winningBidOriginal: [{ required: true, message: '请输入原始中标价', trigger: 'blur' }],
|
||||
exchangeRate: [
|
||||
{ required: true, message: '请输入汇率', trigger: 'blur' },
|
||||
{ type: 'number', min: 0.001, message: '汇率需大于0', trigger: 'blur' }
|
||||
],
|
||||
currency: [{ required: true, message: '请输入币种', trigger: 'blur' }],
|
||||
subject: [{ required: true, message: '请输入所属主体', trigger: 'blur' }],
|
||||
winningBid: [{ required: true, message: '请输入中标价', trigger: 'blur' }],
|
||||
bidWinningDate: [{ required: true, message: '请选择中标日期', trigger: 'blur' }],
|
||||
projectNumbering: [{ required: true, message: '请输入项目编号', trigger: 'blur' }]
|
||||
} as Record<string, any>
|
||||
});
|
||||
|
||||
// 解构响应式数据
|
||||
const { form, rules } = toRefs(data);
|
||||
|
||||
/**
|
||||
* 根据字典值获取字典标签(用于项目类型/阶段的文本展示)
|
||||
*/
|
||||
const getDictLabel = (dictList: any[], value: any) => {
|
||||
if (!dictList || !value) return '';
|
||||
const dictItem = dictList.find((item) => item.value === value);
|
||||
return dictItem ? dictItem.label : '';
|
||||
};
|
||||
|
||||
/**
|
||||
* 计算人民币中标价
|
||||
*/
|
||||
const calculateWinningBid = () => {
|
||||
const dollarAmount = Number(form.value.winningBidOriginal);
|
||||
const rate = Number(form.value.exchangeRate);
|
||||
|
||||
if (isNaN(dollarAmount) || isNaN(rate) || dollarAmount <= 0 || rate <= 0) {
|
||||
form.value.winningBid = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
const result = dollarAmount * rate;
|
||||
form.value.winningBid = Number(result.toFixed(2));
|
||||
};
|
||||
|
||||
/**
|
||||
* 页面初始化 - 获取已有数据(如存在)
|
||||
*/
|
||||
const initData = async () => {
|
||||
try {
|
||||
if (currentProject.value?.id) {
|
||||
const res = await listListOfWinningBids({ projectId: currentProject.value.id });
|
||||
if (res.code === 200) {
|
||||
resetForm();
|
||||
if (!res.data) {
|
||||
isDisabled.value = false;
|
||||
return;
|
||||
}
|
||||
Object.assign(form.value, res.data);
|
||||
isDisabled.value = true;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('初始化中标数据失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 提交表单(含项目信息+中标信息同步提交)
|
||||
*/
|
||||
const submitForm = () => {
|
||||
listOfWinningBidsFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
try {
|
||||
// 1. 计算人民币中标价
|
||||
calculateWinningBid();
|
||||
// 2. 绑定项目ID和项目名称(从项目信息同步)
|
||||
form.value.projectId = currentProject.value?.id;
|
||||
form.value.projectName = projectInfo.projectName;
|
||||
|
||||
// 3. 先更新项目信息(若项目信息有修改)
|
||||
if (currentProject.value?.id) {
|
||||
await updateProject({ id: currentProject.value.id, ...projectInfo });
|
||||
}
|
||||
|
||||
// 4. 再提交中标信息(新增/编辑逻辑)
|
||||
const isEdit = !!form.value.id;
|
||||
if (isEdit) {
|
||||
await updateListOfWinningBids(form.value);
|
||||
} else {
|
||||
await addListOfWinningBids(form.value);
|
||||
}
|
||||
|
||||
// 5. 提交成功后切换为查看状态
|
||||
isDisabled.value = true;
|
||||
ElMessage.success(isEdit ? '编辑成功' : '提交成功');
|
||||
} catch (error) {
|
||||
ElMessage.error('提交失败,请重试');
|
||||
console.error('提交表单失败:', error);
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取项目详细信息
|
||||
*/
|
||||
const getProjectDetail = async () => {
|
||||
try {
|
||||
if (currentProject.value?.id) {
|
||||
const res = await getProject(currentProject.value.id);
|
||||
Object.assign(projectInfo, res.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取项目详情失败:', error);
|
||||
ElMessage.error('获取项目信息失败');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置表单(含项目信息重置)
|
||||
*/
|
||||
const resetForm = () => {
|
||||
// 重置中标表单
|
||||
form.value = { ...initFormData, projectId: currentProject.value?.id };
|
||||
listOfWinningBidsFormRef.value?.resetFields();
|
||||
|
||||
// 重置项目信息(恢复为当前项目的原始数据)
|
||||
getProjectDetail();
|
||||
};
|
||||
|
||||
/**
|
||||
* 监听项目ID变化 - 重新初始化数据
|
||||
*/
|
||||
const projectIdWatcher = watch(
|
||||
() => currentProject.value?.id,
|
||||
(newId) => {
|
||||
if (newId) {
|
||||
form.value.projectId = newId;
|
||||
getProjectDetail();
|
||||
initData();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 页面挂载时初始化
|
||||
onMounted(() => {
|
||||
getProjectDetail();
|
||||
initData();
|
||||
});
|
||||
|
||||
// 页面卸载时清除监听
|
||||
onUnmounted(() => {
|
||||
projectIdWatcher();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 全局背景色 */
|
||||
.bg-gray-50 {
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
|
||||
/* 项目信息项布局样式 */
|
||||
.project-info-item {
|
||||
transition: all 0.2s ease;
|
||||
padding: 4px 0;
|
||||
color: #696969;
|
||||
}
|
||||
|
||||
/* 输入框/选择器统一样式 */
|
||||
.el-input__wrapper,
|
||||
.el-date-editor .el-input__wrapper,
|
||||
.el-select__wrapper {
|
||||
border-radius: 6px !important;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
/* 输入框hover效果 */
|
||||
.el-input__wrapper:hover,
|
||||
.el-date-editor .el-input__wrapper:hover,
|
||||
.el-select__wrapper:hover {
|
||||
border-color: #409eff;
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
|
||||
/* 卡片头部文字样式 */
|
||||
.el-card__header-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.el-button:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* 表单项样式优化 */
|
||||
.el-form-item {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.el-form-item:hover {
|
||||
border-color: #e6f7ff;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* 响应式网格布局适配 */
|
||||
@media (max-width: 767px) {
|
||||
.grid {
|
||||
display: grid;
|
||||
}
|
||||
.grid-cols-1 {
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) and (max-width: 1023px) {
|
||||
.md\:grid-cols-2 {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
.md\:col-span-2 {
|
||||
grid-column: span 2 / span 2;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.lg\:grid-cols-3 {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
.lg\:col-span-3 {
|
||||
grid-column: span 3 / span 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* 间距样式 */
|
||||
.gap-6 {
|
||||
gap: 1.5rem;
|
||||
}
|
||||
.mb-1 {
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
.mb-6 {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
.mt-4 {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.mt-6 {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
.mt-8 {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,344 +0,0 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="110px">
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<el-input v-model="queryParams.projectName" placeholder="请输入项目名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="建设单位" prop="construction">
|
||||
<el-input v-model="queryParams.construction" placeholder="请输入建设单位" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="立项申请人" prop="projectApplicant">
|
||||
<el-input v-model="queryParams.projectApplicant" placeholder="请输入立项申请人" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['bidding:listOfWinningBids:add']">新增</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" :data="listOfWinningBidsList" @selection-change="handleSelectionChange">
|
||||
<!-- <el-table-column type="selection" width="55" align="center" /> -->
|
||||
<el-table-column label="序号" align="center" type="index" width="60" />
|
||||
<el-table-column label="项目状态" align="center" prop="projectStatus" />
|
||||
<el-table-column label="项目名称" align="center" prop="projectName" />
|
||||
<el-table-column label="中标价" align="center" prop="winningBidOriginal" />
|
||||
<el-table-column label="汇率" align="center" prop="exchangeRate" />
|
||||
<el-table-column label="币种" align="center" prop="currency" />
|
||||
<el-table-column label="所属主体" align="center" prop="subject" />
|
||||
<el-table-column label="中标价" align="center" prop="winningBid" />
|
||||
<el-table-column label="中标日期" align="center" prop="bidWinningDate" width="120"> </el-table-column>
|
||||
<el-table-column label="投标保证金" align="center" prop="bidDeposit" width="120" />
|
||||
<el-table-column label="是否退还" align="center" prop="whetherSendBack" />
|
||||
<el-table-column label="建设单位" align="center" prop="construction" />
|
||||
<el-table-column label="总造价" align="center" prop="totalCost" />
|
||||
<el-table-column label="立项申请人" align="center" prop="projectApplicant" width="120" />
|
||||
<el-table-column label="立项部门" align="center" prop="projectApplicantDept" />
|
||||
<el-table-column label="立项申请日期" align="center" prop="projectApplicantTime" width="120"> </el-table-column>
|
||||
<el-table-column label="流程状态" align="center" prop="processStatus" />
|
||||
<el-table-column label="项目编号" align="center" prop="projectNumbering" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="200">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['bidding:listOfWinningBids:edit']"
|
||||
>修改</el-button
|
||||
>
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['bidding:listOfWinningBids:remove']">
|
||||
删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
</el-card>
|
||||
<!-- 添加或修改中标项目一览对话框 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
|
||||
<el-form ref="listOfWinningBidsFormRef" :model="form" :rules="rules" label-width="110px">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目名称" prop="projectName"> <el-input v-model="form.projectName" placeholder="请输入项目名称" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="中标价" prop="winningBidOriginal">
|
||||
<el-input v-model="form.winningBidOriginal" placeholder="请输入中标价" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="汇率" prop="exchangeRate"> <el-input v-model="form.exchangeRate" placeholder="请输入汇率" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="币种" prop="currency"> <el-input v-model="form.currency" placeholder="请输入币种" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所属主体" prop="subject"> <el-input v-model="form.subject" placeholder="请输入所属主体" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="中标价" prop="winningBid"> <el-input v-model="form.winningBid" placeholder="请输入中标价" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="中标日期" prop="bidWinningDate">
|
||||
<el-date-picker
|
||||
clearable
|
||||
v-model="form.bidWinningDate"
|
||||
type="date"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择中标日期"
|
||||
>
|
||||
</el-date-picker> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="投标保证金" prop="bidDeposit"> <el-input v-model="form.bidDeposit" placeholder="请输入投标保证金" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否退还" prop="whetherSendBack">
|
||||
<el-input v-model="form.whetherSendBack" placeholder="请输入是否退还" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="建设单位" prop="construction"> <el-input v-model="form.construction" placeholder="请输入建设单位" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="总造价" prop="totalCost"> <el-input v-model="form.totalCost" placeholder="请输入总造价" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="立项申请人" prop="projectApplicant">
|
||||
<el-input v-model="form.projectApplicant" placeholder="请输入立项申请人" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="立项部门" prop="projectApplicantDept">
|
||||
<el-input v-model="form.projectApplicantDept" placeholder="请输入立项部门" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="立项申请日期" prop="projectApplicantTime">
|
||||
<el-date-picker
|
||||
clearable
|
||||
v-model="form.projectApplicantTime"
|
||||
type="date"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择立项申请日期"
|
||||
>
|
||||
</el-date-picker> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="项目编号" prop="projectNumbering">
|
||||
<el-input v-model="form.projectNumbering" placeholder="请输入项目编号" /> </el-form-item
|
||||
></el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ListOfWinningBids" lang="ts">
|
||||
import {
|
||||
listListOfWinningBids,
|
||||
getListOfWinningBids,
|
||||
delListOfWinningBids,
|
||||
addListOfWinningBids,
|
||||
updateListOfWinningBids
|
||||
} from '@/api/bidding/listOfWinningBids';
|
||||
import { ListOfWinningBidsVO, ListOfWinningBidsQuery, ListOfWinningBidsForm } from '@/api/bidding/listOfWinningBids/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const listOfWinningBidsList = ref<ListOfWinningBidsVO[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref<Array<string | number>>([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const listOfWinningBidsFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const initFormData: ListOfWinningBidsForm = {
|
||||
id: undefined,
|
||||
projectId: currentProject.value?.id,
|
||||
projectStatus: undefined,
|
||||
projectName: undefined,
|
||||
winningBidOriginal: undefined,
|
||||
exchangeRate: undefined,
|
||||
currency: undefined,
|
||||
subject: undefined,
|
||||
winningBid: undefined,
|
||||
bidWinningDate: undefined,
|
||||
bidDeposit: undefined,
|
||||
whetherSendBack: undefined,
|
||||
construction: undefined,
|
||||
totalCost: undefined,
|
||||
projectApplicant: undefined,
|
||||
projectApplicantDept: undefined,
|
||||
projectApplicantTime: undefined,
|
||||
processStatus: undefined,
|
||||
projectNumbering: undefined
|
||||
};
|
||||
const data = reactive<PageData<ListOfWinningBidsForm, ListOfWinningBidsQuery>>({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: currentProject.value?.id,
|
||||
projectStatus: undefined,
|
||||
projectName: undefined,
|
||||
winningBidOriginal: undefined,
|
||||
exchangeRate: undefined,
|
||||
currency: undefined,
|
||||
subject: undefined,
|
||||
winningBid: undefined,
|
||||
bidWinningDate: undefined,
|
||||
bidDeposit: undefined,
|
||||
whetherSendBack: undefined,
|
||||
construction: undefined,
|
||||
totalCost: undefined,
|
||||
projectApplicant: undefined,
|
||||
projectApplicantDept: undefined,
|
||||
projectApplicantTime: undefined,
|
||||
processStatus: undefined,
|
||||
projectNumbering: undefined,
|
||||
params: {}
|
||||
},
|
||||
rules: {
|
||||
id: [{ required: true, message: '不能为空', trigger: 'blur' }],
|
||||
projectId: [{ required: true, message: '项目id不能为空', trigger: 'blur' }]
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 查询中标项目一览列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listListOfWinningBids(queryParams.value);
|
||||
listOfWinningBidsList.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
};
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
listOfWinningBidsFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: ListOfWinningBidsVO[]) => {
|
||||
ids.value = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = '添加中标项目一览';
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: ListOfWinningBidsVO) => {
|
||||
reset();
|
||||
const _id = row?.id || ids.value[0];
|
||||
const res = await getListOfWinningBids(_id);
|
||||
Object.assign(form.value, res.data);
|
||||
dialog.visible = true;
|
||||
dialog.title = '修改中标项目一览';
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
listOfWinningBidsFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.id) {
|
||||
await updateListOfWinningBids(form.value).finally(() => (buttonLoading.value = false));
|
||||
} else {
|
||||
await addListOfWinningBids(form.value).finally(() => (buttonLoading.value = false));
|
||||
}
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: ListOfWinningBidsVO) => {
|
||||
const _ids = row?.id || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除中标项目一览编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||
await delListOfWinningBids(_ids);
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
await getList();
|
||||
};
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.download(
|
||||
'bidding/listOfWinningBids/export',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`listOfWinningBids_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
};
|
||||
//监听项目id刷新数据
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
getList();
|
||||
}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
@ -2,18 +2,67 @@
|
||||
<div class="p-4 bg-gray-50 min-h-screen">
|
||||
<!-- 卡片容器:控制最大宽度+居中+圆角阴影 -->
|
||||
<el-card shadow="hover" class="max-w-6xl mx-auto rounded-xl overflow-hidden border-0" style="background-color: #ffffff">
|
||||
<!-- 卡片头部:独立背景色+内边距+圆角 -->
|
||||
<!-- 卡片头部:项目信息展示区 -->
|
||||
<template #header>
|
||||
<div class="bg-blue-50 px-6 py-4 rounded-t-xl mb-0">
|
||||
<h3 class="el-card__header-title text-lg font-semibold text-blue-800">投标项目信息填写</h3>
|
||||
<span>{{ currentProject.name }}</span>
|
||||
<div style="margin-top: 10px">
|
||||
<el-button @click="isDisabled = false" type="primary" class="px-8 py-2.5 transition-all duration-300 font-medium" v-if="isDisabled">
|
||||
点击编辑
|
||||
</el-button>
|
||||
<div class="bg-blue-50 px-6 rounded-t-xl" style="padding: 10px 20px">
|
||||
<h3 class="el-card__header-title text-lg font-semibold text-blue-800">投标项目信息</h3>
|
||||
<h4>{{ currentProject.name }}</h4>
|
||||
<!-- 项目信息部分 -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div class="project-info-item">
|
||||
<span>负责人:</span>
|
||||
<span> {{ projectInfo.principal || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>负责人电话:</span>
|
||||
<span> {{ projectInfo.principalPhone || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>项目类型:</span>
|
||||
<span> {{ getDictLabel(project_type, projectInfo.projectType) || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>项目阶段:</span>
|
||||
<span> {{ getDictLabel(project_stage, projectInfo.projectStage) || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>开工时间:</span>
|
||||
<span> {{ projectInfo.onStreamTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>经纬度:</span>
|
||||
<span> {{ projectInfo.lng || '-' }},{{ projectInfo.lat || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item md:col-span-2 lg:col-span-3">
|
||||
<span>项目地址:</span>
|
||||
<span> {{ projectInfo.projectSite || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>计划容量(M):</span>
|
||||
<span> {{ projectInfo.plan || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>实际容量(M):</span>
|
||||
<span> {{ projectInfo.actual || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item">
|
||||
<span>设计总量(M):</span>
|
||||
<span> {{ projectInfo.designTotal || '-' }}</span>
|
||||
</div>
|
||||
<div class="project-info-item md:col-span-2 lg:col-span-3">
|
||||
<span>备注:</span>
|
||||
<span> {{ projectInfo.remark || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="mt-4 mb-6">
|
||||
<el-button @click="isDisabled = false" type="primary"
|
||||
class="px-8 py-2.5 transition-all duration-300 font-medium" v-if="isDisabled">
|
||||
点击编辑
|
||||
</el-button>
|
||||
</div> -->
|
||||
</template>
|
||||
<!-- 中标信息表单区域 -->
|
||||
<el-form
|
||||
:disabled="isDisabled"
|
||||
ref="listOfWinningBidsFormRef"
|
||||
@ -24,103 +73,88 @@
|
||||
style="background-color: #ffffff"
|
||||
>
|
||||
<el-row :gutter="32">
|
||||
<!-- 招标代理机构 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="中标价(美元)" prop="winningBidOriginal" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model.number="form.winningBidOriginal" type="number" placeholder="请输入中标价" @input="calculateWinningBid" />
|
||||
<el-form-item label="招标代理机构" prop="biddingAgency" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.biddingAgency" placeholder="请输入招标代理机构" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 招标人 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="汇率" prop="exchangeRate" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model.number="form.exchangeRate" type="number" placeholder="请输入汇率" step="0.0001" @input="calculateWinningBid" />
|
||||
<el-form-item label="招标人" prop="tenderer" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.tenderer" placeholder="请输入招标人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 投标截止时间 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="币种" prop="currency" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.currency" placeholder="请输入币种" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="中标价(人民币)" prop="winningBid" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<!-- 人民币输入框:添加readonly禁止手动修改 -->
|
||||
<el-input v-model="form.winningBid" type="number" placeholder="根据美元中标价和汇率自动计算" readonly />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 其他表单项保持不变 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="中标日期" prop="bidWinningDate" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-form-item label="投标截止时间" prop="biddingDeadline" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-date-picker
|
||||
clearable
|
||||
v-model="form.bidWinningDate"
|
||||
type="date"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择中标日期"
|
||||
v-model="form.biddingDeadline"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
type="datetime"
|
||||
placeholder="请选择投标截止时间"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 开标时间 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="投标保证金(人民币)" prop="bidDeposit" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.bidDeposit" type="number" placeholder="请输入投标保证金" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否退还" prop="whetherSendBack" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-radio-group v-model="form.whetherSendBack">
|
||||
<el-radio label="是" border>是</el-radio>
|
||||
<el-radio label="否" border>否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所属主体" prop="subject" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.subject" placeholder="请输入所属主体" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设单位" prop="construction" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.construction" placeholder="请输入建设单位" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="总造价" prop="totalCost" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.totalCost" placeholder="请输入总造价" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="立项申请人" prop="projectApplicant" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.projectApplicant" placeholder="请输入立项申请人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="立项部门" prop="projectApplicantDept" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.projectApplicantDept" placeholder="请输入立项部门" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="立项申请日期" prop="projectApplicantTime" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-form-item label="开标时间" prop="bidopeningTime" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-date-picker
|
||||
clearable
|
||||
v-model="form.projectApplicantTime"
|
||||
type="date"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择立项申请日期"
|
||||
v-model="form.bidopeningTime"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
type="datetime"
|
||||
placeholder="请选择开标时间"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 建设地点 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目编号" prop="projectNumbering" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.projectNumbering" placeholder="请输入项目编号" />
|
||||
<el-form-item label="建设地点" prop="constructionsite" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.constructionsite" placeholder="请输入建设地点" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- <el-col :span="12">
|
||||
<el-form-item label="项目状态" prop="projectStatus" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.projectStatus" placeholder="请输入项目状态(如:进行中/已完成)" />
|
||||
<!-- 计划工期 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="计划工期" prop="planDuration" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.planDuration" placeholder="请输入计划工期(如:180天)" />
|
||||
</el-form-item>
|
||||
</el-col> -->
|
||||
</el-col>
|
||||
<!-- 答疑截止时间 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="答疑截止时间" prop="answeringDeadlineTime" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-date-picker
|
||||
v-model="form.answeringDeadlineTime"
|
||||
type="datetime"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
placeholder="请选择答疑截止时间"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 澄清截止时间 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="澄清截止时间" prop="clarifyDeadlineTime" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-date-picker
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
value-format="YYYY-MM-DD HH:mm:ss "
|
||||
v-model="form.clarifyDeadlineTime"
|
||||
type="datetime"
|
||||
placeholder="请选择澄清截止时间"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 项目概况 -->
|
||||
<el-col :span="24">
|
||||
<el-form-item label="项目概况" prop="projectOverview" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.projectOverview" type="textarea" placeholder="请输入项目概况" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 操作按钮区域 -->
|
||||
<el-row v-if="!isDisabled" class="mt-8">
|
||||
<el-row v-if="!form.id" class="mt-4">
|
||||
<el-col :span="24" class="text-center">
|
||||
<el-button
|
||||
:loading="buttonLoading"
|
||||
@ -136,210 +170,406 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div style="margin-top: 20px" v-if="form.id">
|
||||
<span style="color: rgb(38 153 255); display: inline-block; margin-left: 40px; font-weight: 700">是否中标配置</span>
|
||||
<el-form
|
||||
ref="listOfWinningBidsFormRef"
|
||||
:disabled="iswhetherBid"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="150px"
|
||||
class="p-6 pt-4"
|
||||
style="background-color: #ffffff"
|
||||
>
|
||||
<el-row>
|
||||
<!-- 是否中标(必填) -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否中标" prop="whetherBid" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-radio-group v-model="form.whetherBid">
|
||||
<el-radio label="0" border>中标</el-radio>
|
||||
<el-radio label="1" border>未中标</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 中标价(必填,仅中标时显示) -->
|
||||
<el-col :span="12" v-if="form.whetherBid == '0'">
|
||||
<el-form-item label="中标价(人民币)" prop="bidPrice" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-model="form.bidPrice" type="number" placeholder="请输入中标价" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 中标通知书(必填,仅中标时显示) -->
|
||||
<!-- <el-col :span="12" v-if="form.whetherBid == '0'">
|
||||
<el-form-item label="中标通知书" prop="bidFileId" class="rounded-lg border border-gray-100 p-1 mb-5">
|
||||
<el-input v-if="form.bidFileName" v-model="form.bidFileName" disabled placeholder="请输入中标通知书" />
|
||||
<file-upload v-else v-model="form.bidFileId" :limit="1" :file-type="['pdf']" :file-size="50" />
|
||||
</el-form-item>
|
||||
</el-col> -->
|
||||
</el-row>
|
||||
<!-- 操作按钮区域 -->
|
||||
<el-row class="mt-4" v-if="!iswhetherBid && form.whetherBid == '0'">
|
||||
<el-col :span="24" class="text-center">
|
||||
<el-button
|
||||
:loading="buttonLoading1"
|
||||
type="primary"
|
||||
@click="submitForm"
|
||||
v-hasPermi="['bidding:listOfWinningBids:add', 'bidding:listOfWinningBids:edit']"
|
||||
class="rounded-full px-8"
|
||||
size="large"
|
||||
>
|
||||
中标
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ListOfWinningBidsForm" lang="ts">
|
||||
import { ref, reactive, toRefs, watch, onMounted, onUnmounted, getCurrentInstance, ComponentInternalInstance, computed } from 'vue';
|
||||
import { addListOfWinningBids, updateListOfWinningBids, listListOfWinningBids, getListOfWinningBids } from '@/api/bidding/listOfWinningBids';
|
||||
import { ListOfWinningBidsVO, ListOfWinningBidsForm } from '@/api/bidding/listOfWinningBids/types';
|
||||
import { addListOfWinningBids, updateListOfWinningBids, listListOfWinningBids } from '@/api/bidding/listOfWinningBids';
|
||||
import { ListOfWinningBidsForm } from '@/api/bidding/listOfWinningBids/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { ElFormInstance, ElMessage } from 'element-plus';
|
||||
|
||||
// 获取组件实例
|
||||
import { getProject, updateProject } from '@/api/project/project';
|
||||
import { globalHeaders } from '@/utils/request';
|
||||
import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus';
|
||||
import { genFileId } from 'element-plus';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
// 用户状态管理
|
||||
const { project_type, project_stage } = toRefs<any>(proxy?.useDict('project_type', 'project_stage'));
|
||||
const headers = ref(globalHeaders());
|
||||
const fileList = ref([]);
|
||||
// 用户状态管理与当前项目
|
||||
const userStore = useUserStoreHook();
|
||||
// 当前选中项目(从store获取)
|
||||
const iswhetherBid = ref(false); // 是否中标
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
// 项目信息(仅展示,非表单编辑)
|
||||
const projectInfo = reactive({
|
||||
principal: undefined,
|
||||
principalPhone: undefined,
|
||||
projectType: undefined,
|
||||
projectStage: undefined,
|
||||
onStreamTime: undefined,
|
||||
lng: undefined,
|
||||
lat: undefined,
|
||||
projectSite: undefined,
|
||||
plan: undefined,
|
||||
actual: undefined,
|
||||
designTotal: undefined,
|
||||
remark: undefined,
|
||||
projectName: undefined
|
||||
});
|
||||
|
||||
// 表单相关引用
|
||||
// 表单核心变量
|
||||
const listOfWinningBidsFormRef = ref<ElFormInstance>();
|
||||
// 加载状态
|
||||
const buttonLoading = ref(false);
|
||||
const buttonLoading1 = ref(false);
|
||||
const isDisabled = ref(false);
|
||||
// 表单初始数据
|
||||
const initFormData: ListOfWinningBidsForm = {
|
||||
const fileObj = ref({
|
||||
bidFile: undefined,
|
||||
bidFileName: undefined
|
||||
});
|
||||
// 表单初始数据(新增招标相关参数)
|
||||
const initFormData = {
|
||||
id: undefined,
|
||||
projectId: currentProject.value?.id,
|
||||
projectStatus: undefined,
|
||||
projectName: undefined,
|
||||
winningBidOriginal: undefined,
|
||||
exchangeRate: undefined,
|
||||
currency: undefined,
|
||||
subject: undefined,
|
||||
winningBid: undefined,
|
||||
bidWinningDate: undefined,
|
||||
bidDeposit: undefined,
|
||||
whetherSendBack: undefined,
|
||||
construction: undefined,
|
||||
totalCost: undefined,
|
||||
projectApplicant: undefined,
|
||||
projectApplicantDept: undefined,
|
||||
projectApplicantTime: undefined,
|
||||
processStatus: undefined,
|
||||
projectNumbering: undefined
|
||||
whetherBid: '1', // 是否中标:0=中标,1=未中标
|
||||
bidPrice: undefined, // 中标价(人民币)
|
||||
bidFileId: undefined, // 中标通知书
|
||||
biddingAgency: undefined, //招标代理机构
|
||||
tenderer: undefined, //招标人
|
||||
biddingDeadline: undefined, //投标截止时间
|
||||
bidopeningTime: undefined, //开标时间
|
||||
projectOverview: undefined, //项目概况
|
||||
constructionsite: undefined, //建设地点
|
||||
planDuration: undefined, //计划工期
|
||||
answeringDeadlineTime: undefined, //答疑截止时间
|
||||
clarifyDeadlineTime: undefined //澄清截止时间
|
||||
};
|
||||
|
||||
// 表单数据与验证规则
|
||||
// 表单数据与验证规则(核心:是否中标/中标价/中标通知书均设为必填,新增参数添加基础验证)
|
||||
const data = reactive({
|
||||
form: { ...initFormData } as ListOfWinningBidsForm,
|
||||
rules: {
|
||||
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
||||
projectName: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
|
||||
winningBidOriginal: [{ required: true, message: '请输入原始中标价', trigger: 'blur' }],
|
||||
exchangeRate: [
|
||||
{ required: true, message: '请输入汇率', trigger: 'blur' },
|
||||
{ type: 'number', min: 0.001, message: '汇率需大于0', trigger: 'blur' }
|
||||
// 是否中标:必填
|
||||
whetherBid: [{ required: true, message: '请选择是否中标', trigger: 'change' }],
|
||||
// 中标价:仅中标时必填,且为正数
|
||||
bidPrice: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入中标价',
|
||||
trigger: 'blur',
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (form.value.whetherBid === '0') {
|
||||
if (!value && value !== 0) {
|
||||
return callback(new Error('请输入中标价'));
|
||||
}
|
||||
if (Number(value) <= 0) {
|
||||
return callback(new Error('中标价需大于0'));
|
||||
}
|
||||
}
|
||||
callback();
|
||||
}
|
||||
}
|
||||
],
|
||||
currency: [{ required: true, message: '请输入币种', trigger: 'blur' }],
|
||||
subject: [{ required: true, message: '请输入所属主体', trigger: 'blur' }],
|
||||
winningBid: [{ required: true, message: '请输入中标价', trigger: 'blur' }],
|
||||
bidWinningDate: [{ required: true, message: '请选择中标日期', trigger: 'blur' }],
|
||||
projectNumbering: [{ required: true, message: '请输入项目编号', trigger: 'blur' }]
|
||||
// 中标通知书:仅中标时必填
|
||||
bidFileId: [
|
||||
{
|
||||
required: true,
|
||||
message: '请上传中标通知书',
|
||||
trigger: 'change',
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (form.value.whetherBid === '0' && !value) {
|
||||
return callback(new Error('请上传中标通知书'));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
}
|
||||
],
|
||||
// 招标代理机构:必填
|
||||
biddingAgency: [{ required: true, message: '请输入招标代理机构', trigger: 'blur' }],
|
||||
// 招标人:必填
|
||||
tenderer: [{ required: true, message: '请输入招标人', trigger: 'blur' }],
|
||||
// 投标截止时间:必填
|
||||
biddingDeadline: [{ required: true, message: '请选择投标截止时间', trigger: 'change' }],
|
||||
// 开标时间:必填
|
||||
bidopeningTime: [{ required: true, message: '请选择开标时间', trigger: 'change' }],
|
||||
// 项目概况:必填
|
||||
projectOverview: [{ required: true, message: '请输入项目概况', trigger: 'blur' }],
|
||||
// 建设地点:必填
|
||||
constructionsite: [{ required: true, message: '请输入建设地点', trigger: 'blur' }],
|
||||
// 计划工期:必填
|
||||
planDuration: [{ required: true, message: '请输入计划工期', trigger: 'blur' }],
|
||||
// 答疑截止时间:必填
|
||||
answeringDeadlineTime: [{ required: true, message: '请选择答疑截止时间', trigger: 'change' }],
|
||||
// 澄清截止时间:必填
|
||||
clarifyDeadlineTime: [{ required: true, message: '请选择澄清截止时间', trigger: 'change' }]
|
||||
} as Record<string, any>
|
||||
});
|
||||
|
||||
// 解构响应式数据
|
||||
const { form, rules } = toRefs(data);
|
||||
|
||||
/**
|
||||
* 计算人民币中标价
|
||||
* 显式触发的计算函数,确保执行时机可靠
|
||||
* 字典标签转换(项目类型/阶段)
|
||||
*/
|
||||
const calculateWinningBid = () => {
|
||||
// 确保数据类型正确
|
||||
const dollarAmount = Number(form.value.winningBidOriginal);
|
||||
const rate = Number(form.value.exchangeRate);
|
||||
|
||||
// 验证输入有效性
|
||||
if (isNaN(dollarAmount) || isNaN(rate) || dollarAmount <= 0 || rate <= 0) {
|
||||
form.value.winningBid = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算并保留2位小数
|
||||
const result = dollarAmount * rate;
|
||||
form.value.winningBid = Number(result.toFixed(2));
|
||||
const getDictLabel = (dictList: any[], value: any) => {
|
||||
if (!dictList || !value) return '';
|
||||
const dictItem = dictList.find((item) => item.value === value);
|
||||
return dictItem ? dictItem.label : '';
|
||||
};
|
||||
|
||||
/**
|
||||
* 页面初始化 - 获取已有数据(如存在)
|
||||
* 初始化中标数据(根据项目ID查询已有记录)
|
||||
*/
|
||||
const initData = async () => {
|
||||
try {
|
||||
if (currentProject.value?.id) {
|
||||
const res = await listListOfWinningBids({ projectId: currentProject.value.id });
|
||||
if (res.code == 200) {
|
||||
console.log(res.data);
|
||||
console.log(res);
|
||||
if (res.code === 200) {
|
||||
resetForm();
|
||||
if (!res.data) {
|
||||
isDisabled.value = false;
|
||||
return;
|
||||
} else {
|
||||
if (res.data) {
|
||||
if (res.data.bidPrice) {
|
||||
iswhetherBid.value = true;
|
||||
} else {
|
||||
iswhetherBid.value = false;
|
||||
}
|
||||
Object.assign(form.value, res.data);
|
||||
isDisabled.value = true;
|
||||
} else {
|
||||
isDisabled.value = false;
|
||||
}
|
||||
isDisabled.value = true;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// ElMessage.error('初始化数据失败');
|
||||
console.error('初始化中标数据失败:', error);
|
||||
ElMessage.error('初始化数据失败');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 提交表单
|
||||
* 提交表单(含项目信息更新+中标信息提交)
|
||||
*/
|
||||
const submitForm = () => {
|
||||
const submitForm = async () => {
|
||||
listOfWinningBidsFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
try {
|
||||
// 提交前确保计算正确
|
||||
calculateWinningBid();
|
||||
// 1. 同步项目ID和名称
|
||||
form.value.projectId = currentProject.value?.id;
|
||||
await addListOfWinningBids(form.value);
|
||||
form.value.projectName = projectInfo.projectName;
|
||||
delete projectInfo.id;
|
||||
await addListOfWinningBids({ ...form.value, ...projectInfo });
|
||||
initData();
|
||||
// 4. 提交成功后切换为查看状态
|
||||
isDisabled.value = true;
|
||||
ElMessage.success('提交成功');
|
||||
} catch (error) {
|
||||
ElMessage.error('提交失败,请重试');
|
||||
console.error('提交表单失败:', error);
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置表单
|
||||
* 获取项目详细信息(用于展示)
|
||||
*/
|
||||
const getProjectDetail = async () => {
|
||||
try {
|
||||
if (currentProject.value?.id) {
|
||||
const res = await getProject(currentProject.value.id);
|
||||
|
||||
Object.assign(projectInfo, res.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取项目详情失败:', error);
|
||||
ElMessage.error('获取项目信息失败');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置表单(恢复初始状态+重新拉取项目信息)
|
||||
*/
|
||||
const resetForm = () => {
|
||||
form.value = { ...initFormData, projectId: currentProject.value?.id };
|
||||
listOfWinningBidsFormRef.value?.resetFields();
|
||||
getProjectDetail();
|
||||
};
|
||||
|
||||
/**
|
||||
* 监听项目ID变化 - 重新初始化数据
|
||||
* 监听项目ID变化,重新初始化数据
|
||||
*/
|
||||
const projectIdWatcher = watch(
|
||||
() => currentProject.value?.id,
|
||||
(newId) => {
|
||||
if (newId) {
|
||||
form.value.projectId = newId;
|
||||
getProjectDetail();
|
||||
initData();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 页面挂载时初始化
|
||||
// 生命周期钩子
|
||||
onMounted(() => {
|
||||
getProjectDetail();
|
||||
initData();
|
||||
});
|
||||
|
||||
// 页面卸载时清除监听
|
||||
onUnmounted(() => {
|
||||
projectIdWatcher();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 全局背景色:柔和灰色,区分页面与卡片 */
|
||||
/* 全局背景色 */
|
||||
.bg-gray-50 {
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
|
||||
/* 表单项优化:hover效果+边框过渡,提升交互感 */
|
||||
.el-form-item {
|
||||
/* 项目信息项样式 */
|
||||
.project-info-item {
|
||||
transition: all 0.2s ease;
|
||||
padding: 4px 0;
|
||||
color: #696969;
|
||||
}
|
||||
|
||||
/* 输入框/选择器统一样式 */
|
||||
.el-input__wrapper,
|
||||
.el-date-editor .el-input__wrapper,
|
||||
.el-select__wrapper {
|
||||
border-radius: 6px !important;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.el-form-item:hover {
|
||||
border-color: #e6f7ff;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
|
||||
/* 输入框hover效果 */
|
||||
.el-input__wrapper:hover,
|
||||
.el-date-editor .el-input__wrapper:hover,
|
||||
.el-select__wrapper:hover {
|
||||
border-color: #409eff;
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
|
||||
/* 输入框/选择器统一圆角 */
|
||||
.el-input__wrapper,
|
||||
.el-date-editor .el-input__wrapper {
|
||||
border-radius: 6px !important;
|
||||
}
|
||||
|
||||
/* 卡片头部文字对齐优化 */
|
||||
/* 卡片头部文字样式 */
|
||||
.el-card__header-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 按钮间距与过渡效果 */
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.el-button:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* 只读输入框样式优化(区分可编辑状态) */
|
||||
.el-input--readonly .el-input__wrapper {
|
||||
background-color: #f9fafb;
|
||||
cursor: not-allowed;
|
||||
/* 表单项样式优化 */
|
||||
.el-form-item {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.el-form-item:hover {
|
||||
border-color: #e6f7ff;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* 响应式网格布局适配 */
|
||||
@media (max-width: 767px) {
|
||||
.grid {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.grid-cols-1 {
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) and (max-width: 1023px) {
|
||||
.md\:grid-cols-2 {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.md\:col-span-2 {
|
||||
grid-column: span 2 / span 2;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.lg\:grid-cols-3 {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.lg\:col-span-3 {
|
||||
grid-column: span 3 / span 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* 间距样式 */
|
||||
.gap-6 {
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.mb-5 {
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.mb-6 {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.mt-4 {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.mt-6 {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.mt-8 {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
335
src/views/contract/bidCost/index.vue
Normal file
@ -0,0 +1,335 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<el-card shadow="always">
|
||||
<el-form :model="queryForm" :inline="true">
|
||||
<el-form-item label="版本号" prop="versions">
|
||||
<el-select v-model="queryForm.versions" placeholder="选择版本号" @change="changeVersions">
|
||||
<el-option v-for="item in options" :key="item.id" :label="item.versions" :value="item.versions" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="表名" prop="sheet">
|
||||
<el-select v-model="queryForm.sheet" placeholder="选择表名" @change="changeSheet">
|
||||
<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">{{ isExpandAll ? '一键收起' : '一键展开' }}</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
class="upload-demo"
|
||||
:http-request="importExcel"
|
||||
:show-file-list="false"
|
||||
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-button
|
||||
type="primary"
|
||||
v-if="versionObj.status == 'draft'"
|
||||
icon="Edit"
|
||||
@click="handleAudit"
|
||||
v-hasPermi="['bidding:biddingLimitList:getVersionDetail']"
|
||||
>审核</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="warning"
|
||||
icon="view"
|
||||
@click="handleViewInfo"
|
||||
v-hasPermi="['bidding:biddingLimitList:getVersionDetail']"
|
||||
v-if="versionObj.status && versionObj.status != 'draft'"
|
||||
>查看流程</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</transition>
|
||||
<el-card shadow="never" class="mb8">
|
||||
<el-table ref="tableRef" v-loading="loading" :data="tableData" row-key="id" border lazy default-expand-all>
|
||||
<el-table-column prop="num" label="编号" />
|
||||
<el-table-column prop="name" label="工程或费用名称" />
|
||||
<el-table-column prop="unit" label="单位" align="center" />
|
||||
<el-table-column prop="specification" label="规格" align="center"/>
|
||||
<el-table-column prop="quantity" label="数量" align="center">
|
||||
<template #default="scope">
|
||||
{{ scope.row.children.length > 0 ? '' : scope.row.quantity }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="单价" align="center">
|
||||
<template #default="scope">
|
||||
<el-input-number
|
||||
:disabled="versionObj.status != 'draft'"
|
||||
:model-value="scope.row.unitPrice"
|
||||
@change="
|
||||
(val) => {
|
||||
scope.row.unitPrice = val;
|
||||
changePrice(scope.row);
|
||||
}
|
||||
"
|
||||
: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 != 0 ? Number(scope.row.price).toFixed(2) : null }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operate" label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="versionObj.status != 'draft'"
|
||||
@click="handleSave(scope.row, 'all')"
|
||||
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>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { BiddingImportExcelFile, getTreeLimit, biddingLimitListUpdate, sheetList, obtainAllVersionNumbers } from '@/api/bidding/biddingLimit';
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
|
||||
const userStore = useUserStoreHook();
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const queryForm = ref({
|
||||
versions: '',
|
||||
sheet: ''
|
||||
});
|
||||
const loading = ref(false);
|
||||
const options = ref<any[]>([]);
|
||||
const sheets = ref<any[]>([]);
|
||||
const tableData = ref<any[]>([]);
|
||||
const isExpandAll = ref(true);
|
||||
const versionObj: any = ref({});
|
||||
const versionMap = new Map();
|
||||
//获取版本号
|
||||
const getVersionNums = async () => {
|
||||
try {
|
||||
const params = {
|
||||
projectId: currentProject.value?.id,
|
||||
pageSize: 1000,
|
||||
pageNum: 1
|
||||
};
|
||||
const res = await obtainAllVersionNumbers(params);
|
||||
if (res.code == 200) {
|
||||
options.value = res.data;
|
||||
if (res.data.length > 0) {
|
||||
res.data.forEach((item: any) => {
|
||||
versionMap.set(item.versions, item);
|
||||
});
|
||||
queryForm.value.versions = res.data[0].versions;
|
||||
versionObj.value = res.data[0];
|
||||
getSheetName();
|
||||
} else {
|
||||
queryForm.value.versions = '';
|
||||
versionObj.value = {};
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
//选择版本号
|
||||
const changeVersions = (val) => {
|
||||
getSheetName();
|
||||
};
|
||||
|
||||
//选择表名
|
||||
const changeSheet = () => {
|
||||
getTableData();
|
||||
};
|
||||
|
||||
//获取表名
|
||||
const getSheetName = async () => {
|
||||
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();
|
||||
}
|
||||
};
|
||||
//获取表格
|
||||
const getTableData = async () => {
|
||||
loading.value = true;
|
||||
const params = {
|
||||
projectId: currentProject.value?.id,
|
||||
sheet: queryForm.value.sheet,
|
||||
versions: queryForm.value.versions,
|
||||
type: '0'
|
||||
};
|
||||
const res = await getTreeLimit(params);
|
||||
loading.value = false;
|
||||
if (res.code == 200) {
|
||||
if (res.data && res.data.length > 0) {
|
||||
tableData.value = [res.data[0]];
|
||||
} else {
|
||||
tableData.value = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
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 (type == 'single') {
|
||||
loading.value = true;
|
||||
const list = [{ ...row }];
|
||||
biddingLimitListUpdate(list).then((res) => {
|
||||
if (res.code == 200) {
|
||||
ElMessage({
|
||||
message: '修改成功',
|
||||
type: 'success'
|
||||
});
|
||||
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>();
|
||||
|
||||
const toggleExpandAll = () => {
|
||||
isExpandAll.value = !isExpandAll.value;
|
||||
console.log(isExpandAll.value);
|
||||
|
||||
tableData.value.forEach((row) => {
|
||||
tableRef.value.toggleRowExpansion(row, isExpandAll.value);
|
||||
});
|
||||
};
|
||||
//导入
|
||||
const importExcel = (options: any): any => {
|
||||
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();
|
||||
// getSheetName();
|
||||
}
|
||||
);
|
||||
const handleExport = () => {
|
||||
proxy?.download(
|
||||
'/bidding/biddingLimitList/export',
|
||||
{
|
||||
projectId: currentProject.value?.id,
|
||||
sheet: queryForm.value.sheet
|
||||
},
|
||||
`投标成本核算${queryForm.value.sheet}.xlsx`
|
||||
);
|
||||
};
|
||||
// 审核
|
||||
const handleAudit = () => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
let id = versionMap.get(queryForm.value.versions).id;
|
||||
proxy.$router.push({
|
||||
path: `/approval/biddingLimit/indexEdit`,
|
||||
query: {
|
||||
id,
|
||||
type: 'update',
|
||||
sheets: sheets.value,
|
||||
versions: versionObj.value
|
||||
}
|
||||
});
|
||||
};
|
||||
// 查看审核
|
||||
const handleViewInfo = () => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
let id = versionMap.get(queryForm.value.versions).id;
|
||||
console.log(versionObj.value);
|
||||
|
||||
proxy.$router.push({
|
||||
path: `/approval/biddingLimit/indexEdit`,
|
||||
query: {
|
||||
id,
|
||||
type: 'view',
|
||||
sheets: sheets.value,
|
||||
versions: versionObj.value
|
||||
}
|
||||
});
|
||||
};
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
onMounted(() => {
|
||||
getVersionNums();
|
||||
// getSheetName();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
343
src/views/contract/bidCost/indexEdit.vue
Normal file
@ -0,0 +1,343 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 顶部按钮区域 -->
|
||||
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||
<approvalButton
|
||||
@submitForm="submitForm"
|
||||
@approvalVerifyOpen="approvalVerifyOpen"
|
||||
@handleApprovalRecord="handleApprovalRecord"
|
||||
:buttonLoading="buttonLoading"
|
||||
:id="form.id"
|
||||
:status="form.status"
|
||||
:pageType="routeParams.type"
|
||||
/>
|
||||
</el-card>
|
||||
<!-- 表单区域 -->
|
||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-800">成本核算清单</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<el-form ref="leaveFormRef" disabled :model="form" :rules="rules" label-width="100px" class="space-y-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4" v-for="item in sheets" :key="item">
|
||||
<el-form-item label="表格文件">
|
||||
<span style="color: #8d8d8d">{{ item }}</span>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||
<!-- 流程选择对话框 -->
|
||||
<el-dialog
|
||||
draggable
|
||||
v-model="dialogVisible.visible"
|
||||
:title="dialogVisible.title"
|
||||
:before-close="handleClose"
|
||||
width="500"
|
||||
class="rounded-lg shadow-lg"
|
||||
>
|
||||
<div class="p-4">
|
||||
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||
>取消</el-button
|
||||
>
|
||||
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||
>确认</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Leave" lang="ts">
|
||||
import { LeaveForm } from '@/api/workflow/leave/types';
|
||||
import { startWorkFlow } from '@/api/workflow/task';
|
||||
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { getVersionDetail } from '@/api/bidding/biddingLimit';
|
||||
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
//路由参数
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
const flowCodeOptions = [
|
||||
{
|
||||
value: currentProject.value?.id + '_biddingLimitList',
|
||||
label: '成本核算清单审批'
|
||||
}
|
||||
];
|
||||
|
||||
const flowCode = ref<string>('');
|
||||
const status = ref<string>('');
|
||||
const dialogVisible = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '流程定义'
|
||||
});
|
||||
//提交组件
|
||||
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||
//审批记录组件
|
||||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||
//按钮组件
|
||||
const approvalButtonRef = ref<InstanceType<typeof ApprovalButton>>();
|
||||
const sheets = ref([]);
|
||||
const versions = ref({});
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: '',
|
||||
isEdit: false
|
||||
});
|
||||
const submitFormData = ref<StartProcessBo>({
|
||||
businessId: '',
|
||||
flowCode: '',
|
||||
variables: {}
|
||||
});
|
||||
const taskVariables = ref<Record<string, any>>({});
|
||||
|
||||
const initFormData = {
|
||||
id: undefined,
|
||||
projectId: currentProject.value?.id,
|
||||
versionNumber: undefined,
|
||||
fileName: undefined,
|
||||
fileUrl: undefined,
|
||||
fileType: undefined,
|
||||
fileSuffix: undefined,
|
||||
originalName: undefined,
|
||||
remark: undefined,
|
||||
fileId: undefined
|
||||
};
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
rules: {}
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
dialogVisible.visible = false;
|
||||
flowCode.value = '';
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
const { form, rules } = toRefs(data);
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 获取详情 */
|
||||
const getInfo = () => {
|
||||
loading.value = true;
|
||||
buttonLoading.value = false;
|
||||
nextTick(async () => {
|
||||
const res = await getVersionDetail(routeParams.value.id);
|
||||
Object.assign(form.value, res.data);
|
||||
loading.value = false;
|
||||
buttonLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = (status1: string) => {
|
||||
status.value = status1;
|
||||
buttonLoading.value = true;
|
||||
submit(status.value, form.value);
|
||||
};
|
||||
|
||||
const submitFlow = async () => {
|
||||
handleStartWorkFlow(form.value);
|
||||
dialogVisible.visible = false;
|
||||
};
|
||||
//提交申请
|
||||
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||
try {
|
||||
submitFormData.value.flowCode = flowCode.value;
|
||||
submitFormData.value.businessId = data.id;
|
||||
//流程变量
|
||||
taskVariables.value = {
|
||||
// leave4/5 使用的流程变量
|
||||
userList: ['1', '3', '4']
|
||||
};
|
||||
submitFormData.value.variables = taskVariables.value;
|
||||
const resp = await startWorkFlow(submitFormData.value);
|
||||
if (submitVerifyRef.value) {
|
||||
buttonLoading.value = false;
|
||||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||
}
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
//审批记录
|
||||
const handleApprovalRecord = () => {
|
||||
approvalRecordRef.value.init(form.value.id);
|
||||
};
|
||||
//提交回调
|
||||
const submitCallback = async () => {
|
||||
await proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
};
|
||||
//审批
|
||||
const approvalVerifyOpen = async () => {
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||
};
|
||||
// 图纸上传成功之后 开始提交
|
||||
const submit = async (status, data) => {
|
||||
form.value = data;
|
||||
if (status === 'draft') {
|
||||
buttonLoading.value = false;
|
||||
proxy?.$modal.msgSuccess('暂存成功');
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
} else {
|
||||
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||
flowCode.value = flowCodeOptions[0].value;
|
||||
dialogVisible.visible = true;
|
||||
return;
|
||||
}
|
||||
//说明启动过先随意穿个参数
|
||||
if (flowCode.value === '' || flowCode.value === null) {
|
||||
flowCode.value = 'xx';
|
||||
}
|
||||
console.log(data);
|
||||
await handleStartWorkFlow(data);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
reset();
|
||||
routeParams.value = proxy.$route.query;
|
||||
sheets.value = routeParams.value.sheets;
|
||||
versions.value = routeParams.value.versions;
|
||||
Object.assign(form.value, versions.value);
|
||||
loading.value = false;
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getInfo();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式 */
|
||||
:root {
|
||||
--primary: #409eff;
|
||||
--primary-light: #66b1ff;
|
||||
--primary-dark: #3a8ee6;
|
||||
--success: #67c23a;
|
||||
--warning: #e6a23c;
|
||||
--danger: #f56c6c;
|
||||
--info: #909399;
|
||||
}
|
||||
|
||||
/* 表单样式优化 */
|
||||
.el-form-item {
|
||||
.el-form-item__label {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-input__inner,
|
||||
.el-select .el-input__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.el-textarea__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-primary {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-light);
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
.el-card {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
/* transform: translateY(-2px); */
|
||||
}
|
||||
}
|
||||
|
||||
/* 对话框样式优化 */
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -25,20 +25,40 @@
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="名称" />
|
||||
<el-table-column prop="content" label="内容" />
|
||||
<el-table-column prop="plannedBiddingTime" label="计划招标时间" align="center">
|
||||
<el-table-column prop="price" label="限价" />
|
||||
<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
|
||||
<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>
|
||||
@ -76,10 +96,7 @@
|
||||
</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-button type="primary" @click="toggleExpandAll">{{ isExpandAll ? '一键收起' : '一键展开' }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
@ -98,7 +115,8 @@
|
||||
<el-table-column prop="name" label="工程或费用名称" />
|
||||
<el-table-column prop="unit" 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">
|
||||
<el-input-number
|
||||
:model-value="scope.row.selectNum"
|
||||
@ -112,22 +130,51 @@
|
||||
:step="1"
|
||||
:controls="false"
|
||||
: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>
|
||||
</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">
|
||||
{{ scope.row.price }}
|
||||
{{
|
||||
(scope.row.quantity ? Number(scope.row.quantity) : 0) -
|
||||
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) -
|
||||
(scope.row.selectNum ? Number(scope.row.selectNum) : 0) ==
|
||||
0
|
||||
? ''
|
||||
: (scope.row.quantity ? Number(scope.row.quantity) : 0) -
|
||||
(scope.row.selectNum ? Number(scope.row.selectNum) : 0) -
|
||||
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)
|
||||
}}
|
||||
</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) -
|
||||
(scope.row.selectNum ? Number(scope.row.selectNum) : 0)) *
|
||||
Number(scope.row.unitPrice) ==
|
||||
0
|
||||
? ''
|
||||
: (
|
||||
((scope.row.quantity ? Number(scope.row.quantity) : 0) -
|
||||
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) -
|
||||
(scope.row.selectNum ? Number(scope.row.selectNum) : 0)) *
|
||||
Number(scope.row.unitPrice)
|
||||
).toFixed(2)
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<template #footer>
|
||||
<el-button @click="closeDialog">取消</el-button>
|
||||
<el-button type="primary" @click="submitForm(formRef)">确定</el-button>
|
||||
<el-button type="primary" @click="submitForm(formRef)" :loading="loadingBtn">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog title="详情" v-model="detailDialog" width="75%" draggable>
|
||||
@ -190,7 +237,7 @@ const rules = ref({
|
||||
content: [{ required: true, message: '请输入内容', trigger: 'blur' }]
|
||||
});
|
||||
const loading = ref(false);
|
||||
|
||||
const loadingBtn = ref();
|
||||
//字典获取数据
|
||||
const getTabsList = async () => {
|
||||
const res = await getDicts('subcontracting_type');
|
||||
@ -290,18 +337,10 @@ const getVersionNums = async () => {
|
||||
getSheetName();
|
||||
} else {
|
||||
treeForm.value.versions = '';
|
||||
ElMessage({
|
||||
message: '获取版本号失败',
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
ElMessage({
|
||||
message: '获取版本号失败',
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
};
|
||||
//获取表名
|
||||
@ -318,19 +357,11 @@ const getSheetName = async () => {
|
||||
treeForm.value.sheet = res.data[0];
|
||||
} else {
|
||||
treeForm.value.sheet = '';
|
||||
ElMessage({
|
||||
message: '获取表名失败',
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
getTreeList();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
ElMessage({
|
||||
message: '获取表名失败',
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
};
|
||||
const handleSelection = (selection: any) => {
|
||||
@ -372,11 +403,12 @@ const changeSheet = () => {
|
||||
getTreeList();
|
||||
};
|
||||
|
||||
const toggleExpandAll = (isExpand: boolean) => {
|
||||
const toggleExpandAll = () => {
|
||||
isExpandAll.value = !isExpandAll.value;
|
||||
console.log(isExpandAll.value);
|
||||
treeData.value.forEach((row) => {
|
||||
treeTableRef.value.toggleRowExpansion(row, isExpand);
|
||||
treeTableRef.value.toggleRowExpansion(row, isExpandAll.value);
|
||||
});
|
||||
isExpandAll.value = isExpand;
|
||||
};
|
||||
//打开获取表数据
|
||||
const getTreeList = async () => {
|
||||
@ -418,6 +450,7 @@ const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
});
|
||||
return;
|
||||
}
|
||||
loadingBtn.value = true;
|
||||
const newSelectionData = selectionData.value.filter((item) => item.quantity != '' && item.quantity != null);
|
||||
if (newSelectionData.some((item) => item.selectNum == '' || item.selectNum == null)) {
|
||||
ElMessage.error('存在未填写数量的工程或费用名称,请检查');
|
||||
@ -449,6 +482,8 @@ const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
loadingBtn.value = false;
|
||||
}
|
||||
} else {
|
||||
console.log('error submit!', fields);
|
||||
@ -505,7 +540,7 @@ const handleDetail = (row: any) => {
|
||||
getDetails(row);
|
||||
};
|
||||
const getDetails = (row: any) => {
|
||||
getDetailsList({ id: row.id, type: '1' }).then((res) => {
|
||||
getDetailsList({ id: row.id, type: '1', projectId: currentProject.value?.id }).then((res) => {
|
||||
if (res.code == 200) {
|
||||
detailData.value = res.data;
|
||||
}
|
||||
|
||||
@ -14,11 +14,9 @@
|
||||
</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-button type="primary" @click="toggleExpandAll">{{ isExpandAll ? '一键收起' : '一键展开' }}</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
@ -35,6 +33,26 @@
|
||||
<el-form-item>
|
||||
<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 && reviewStatus == 'draft'"
|
||||
@click="clickApprovalSheet()"
|
||||
v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
|
||||
>审核</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="warning"
|
||||
icon="view"
|
||||
v-if="reviewStatus && reviewStatus != 'draft'"
|
||||
@click="clickApprovalSheet()"
|
||||
v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
|
||||
>查看流程</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</transition>
|
||||
@ -42,13 +60,25 @@
|
||||
<el-table ref="tableRef" v-loading="loading" :data="tableData" row-key="id" border lazy default-expand-all>
|
||||
<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">
|
||||
<el-table-column prop="unit" label="单位" align="center" />
|
||||
<el-table-column prop="taxRate" label="税率" align="center" />
|
||||
<el-table-column prop="specification" label="规格" align="center" />
|
||||
<el-table-column prop="quantity" label="数量" align="center">
|
||||
<template #default="scope">
|
||||
{{ scope.row.children.length > 0 ? '' : scope.row.quantity }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="unitPrice" label="单价" align="center">
|
||||
<template #default="scope">
|
||||
<el-input-number
|
||||
:disabled="reviewStatus != '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"
|
||||
@ -56,17 +86,20 @@
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="price" label="总价" align="center">
|
||||
<el-table-column prop="price" label="总价" align="center" >
|
||||
<template #default="scope">
|
||||
{{ scope.row.price }}
|
||||
<!-- {{ scope.row.children.length > 0 ? scope.row.children.reduce((sum, child) => sum + child.price, 0) : scope.row.price }} -->
|
||||
{{ scope.row.price != 0 ? Number(scope.row.price).toFixed(2) : null }}
|
||||
<!-- {{ scope.row.price }} -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="price" label="操作" align="center">
|
||||
<el-table-column prop="operate" label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleSave(scope.row)"
|
||||
:disabled="reviewStatus != 'draft'"
|
||||
@click="handleSave(scope.row, 'all')"
|
||||
v-if="scope.row.quantity && scope.row.quantity != 0"
|
||||
v-hasPermi="['tender:billofquantitiesLimitList:edit']"
|
||||
>确定</el-button
|
||||
@ -81,7 +114,7 @@
|
||||
<script setup lang="ts">
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { listBillofquantitiesLimitList, obtainAllVersionNumbers, sheetList, updatePrice, importExcelFile } from '@/api/contract/index';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
|
||||
const userStore = useUserStoreHook();
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
@ -93,8 +126,10 @@ const loading = ref(false);
|
||||
const options = ref<any[]>([]);
|
||||
const sheets = ref<any[]>([]);
|
||||
const tableData = ref<any[]>([]);
|
||||
const isExpandAll = ref(false);
|
||||
|
||||
const isExpandAll = ref(true);
|
||||
const reviewStatus = ref('');
|
||||
const versionObj: any = ref({});
|
||||
const versionMap = new Map();
|
||||
//获取版本号
|
||||
const getVersionNums = async () => {
|
||||
try {
|
||||
@ -109,27 +144,27 @@ const getVersionNums = async () => {
|
||||
if (res.code == 200) {
|
||||
options.value = res.data;
|
||||
if (res.data.length > 0) {
|
||||
res.data.forEach((item: any) => {
|
||||
versionMap.set(item.versions, item);
|
||||
});
|
||||
queryForm.value.versions = res.data[0].versions;
|
||||
|
||||
reviewStatus.value = res.data[0].status;
|
||||
getSheetName();
|
||||
} else {
|
||||
queryForm.value.versions = '';
|
||||
ElMessage({
|
||||
message: '获取版本号失败',
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
ElMessage({
|
||||
message: '获取版本号失败',
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
};
|
||||
//选择版本号
|
||||
const changeVersions = () => {
|
||||
const changeVersions = (val) => {
|
||||
options.value.forEach((item) => {
|
||||
if (item.versions == val) {
|
||||
reviewStatus.value = item.status;
|
||||
}
|
||||
});
|
||||
getSheetName();
|
||||
};
|
||||
|
||||
@ -152,19 +187,11 @@ const getSheetName = async () => {
|
||||
queryForm.value.sheet = res.data[0];
|
||||
} else {
|
||||
queryForm.value.sheet = '';
|
||||
ElMessage({
|
||||
message: '获取表名失败',
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
getTableData();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
ElMessage({
|
||||
message: '获取表名失败',
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
};
|
||||
//获取表格
|
||||
@ -179,54 +206,70 @@ const getTableData = async () => {
|
||||
};
|
||||
const res = await listBillofquantitiesLimitList(params);
|
||||
if (res.code == 200) {
|
||||
tableData.value = [res.data[0]];
|
||||
tableData.value = res.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
ElMessage({
|
||||
message: '获取表格失败',
|
||||
type: 'error'
|
||||
});
|
||||
tableData.value = [];
|
||||
loading.value = false;
|
||||
} finally {
|
||||
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'
|
||||
if (type == 'single') {
|
||||
loading.value = true;
|
||||
const list = [{ ...row, type: '1' }];
|
||||
updatePrice(list).then((res) => {
|
||||
if (res.code == 200) {
|
||||
ElMessage({
|
||||
message: '修改成功',
|
||||
type: 'success'
|
||||
});
|
||||
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();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
updatePrice({ ...row, type: '1' }).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>();
|
||||
|
||||
const toggleExpandAll = (isExpand: boolean) => {
|
||||
const toggleExpandAll = () => {
|
||||
isExpandAll.value = !isExpandAll.value;
|
||||
console.log(isExpandAll.value);
|
||||
tableData.value.forEach((row) => {
|
||||
tableRef.value.toggleRowExpansion(row, isExpand);
|
||||
tableRef.value.toggleRowExpansion(row, isExpandAll.value);
|
||||
});
|
||||
isExpandAll.value = isExpand;
|
||||
};
|
||||
//导入
|
||||
const importExcel = (options: any): any => {
|
||||
@ -266,11 +309,25 @@ const handleExport = () => {
|
||||
versions: queryForm.value.versions,
|
||||
type: '1'
|
||||
},
|
||||
`限价一览表${queryForm.value.sheet}.xlsx`
|
||||
`限价一览${queryForm.value.sheet}.xlsx`
|
||||
);
|
||||
};
|
||||
// 审批
|
||||
const clickApprovalSheet = () => {
|
||||
proxy.$tab.closePage(proxy?.$route);
|
||||
let id = versionMap.get(queryForm.value.versions).id;
|
||||
proxy?.$router.push({
|
||||
path: `/approval/contractLimitPrice/indexEdit`,
|
||||
query: {
|
||||
id: id,
|
||||
type: 'update',
|
||||
sheets: queryForm.value.sheet
|
||||
}
|
||||
});
|
||||
};
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
// console.log(11111111);
|
||||
});
|
||||
onMounted(() => {
|
||||
getVersionNums();
|
||||
|
||||
385
src/views/contract/limitPrice/indexEdit.vue
Normal file
@ -0,0 +1,385 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 顶部按钮区域 -->
|
||||
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||
<approvalButton
|
||||
@submitForm="submitForm"
|
||||
@approvalVerifyOpen="approvalVerifyOpen"
|
||||
@handleApprovalRecord="handleApprovalRecord"
|
||||
:buttonLoading="buttonLoading"
|
||||
:id="form.versions"
|
||||
:status="form.status"
|
||||
:pageType="routeParams.type"
|
||||
/>
|
||||
</el-card>
|
||||
<!-- 表单区域 -->
|
||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-800">合约限价审核</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<el-form ref="leaveFormRef" v-loading="loading" :model="form" :rules="rules" label-width="100px" class="space-y-4">
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="版本号" prop="formNo">
|
||||
<el-input :disabled="true" v-model="form.versions" placeholder="请输入文件名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="表名" prop="sheet">
|
||||
<el-select v-model="form.sheet" placeholder="选择表名" @change="changeSheet">
|
||||
<el-option v-for="item in sheets" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
<el-table :data="tableData" style="width: 100%; margin-bottom: 20px; height: calc(100vh - 305px)" row-key="id" default-expand-all border>
|
||||
<el-table-column prop="num" label="编号" />
|
||||
<el-table-column prop="name" label="名称" />
|
||||
<el-table-column prop="specification" label="规格" />
|
||||
<el-table-column prop="unit" label="单位" />
|
||||
<el-table-column prop="quantity" label="数量" />
|
||||
<el-table-column prop="unitPrice" label="单价" align="center" />
|
||||
<el-table-column prop="price" label="总价" align="center">
|
||||
<template #default="scope">
|
||||
{{ scope.row.price != 0 ? Number(scope.row.price).toFixed(2) : null }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||
<!-- 流程选择对话框 -->
|
||||
<el-dialog
|
||||
draggable
|
||||
v-model="dialogVisible.visible"
|
||||
:title="dialogVisible.title"
|
||||
:before-close="handleClose"
|
||||
width="500"
|
||||
class="rounded-lg shadow-lg"
|
||||
>
|
||||
<div class="p-4">
|
||||
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors">取消</el-button>
|
||||
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Leave" lang="ts">
|
||||
import { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types';
|
||||
import { startWorkFlow } from '@/api/workflow/task';
|
||||
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
const { design_change_reason_type } = toRefs<any>(proxy?.useDict('design_change_reason_type'));
|
||||
import { listBillofquantitiesLimitList, getVersionDetails, sheetList } from '@/api/contract/index';
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
//路由参数
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
|
||||
const flowCode = ref<string>('');
|
||||
const status = ref<string>('');
|
||||
const dialogVisible = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '流程定义'
|
||||
});
|
||||
//提交组件
|
||||
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||
//审批记录组件
|
||||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||
//按钮组件
|
||||
const flowCodeOptions = [
|
||||
{
|
||||
value: currentProject.value?.id + '_xianjiayilan',
|
||||
label: '合约限价审核'
|
||||
}
|
||||
];
|
||||
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: '',
|
||||
isEdit: false
|
||||
});
|
||||
const submitFormData = ref<StartProcessBo>({
|
||||
businessId: '',
|
||||
flowCode: '',
|
||||
variables: {}
|
||||
});
|
||||
const taskVariables = ref<Record<string, any>>({});
|
||||
|
||||
const initFormData = {
|
||||
versions: '',
|
||||
sheet: '',
|
||||
status: '',
|
||||
id: ''
|
||||
};
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
tableData: [],
|
||||
rules: {}
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
dialogVisible.visible = false;
|
||||
flowCode.value = '';
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
const { form, rules, tableData } = toRefs(data);
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 获取详情 */
|
||||
const getInfo = () => {
|
||||
loading.value = true;
|
||||
buttonLoading.value = false;
|
||||
nextTick(async () => {
|
||||
const res = await getVersionDetails(routeParams.value.id);
|
||||
console.log(res);
|
||||
Object.assign(form.value, res.data);
|
||||
loading.value = false;
|
||||
buttonLoading.value = false;
|
||||
getSheetName();
|
||||
});
|
||||
};
|
||||
const sheets = ref([]);
|
||||
//获取表名
|
||||
const getSheetName = async () => {
|
||||
try {
|
||||
const params = {
|
||||
projectId: currentProject.value?.id,
|
||||
versions: form.value.versions
|
||||
};
|
||||
const res = await sheetList(params);
|
||||
if (res.code == 200) {
|
||||
sheets.value = res.data;
|
||||
if (res.data.length > 0) {
|
||||
form.value.sheet = res.data[0];
|
||||
}
|
||||
getListTable();
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
//选择表名
|
||||
const changeSheet = () => {
|
||||
getListTable();
|
||||
};
|
||||
//获取列表
|
||||
const getListTable = async () => {
|
||||
const res = await listBillofquantitiesLimitList({
|
||||
projectId: currentProject.value?.id,
|
||||
versions: form.value.versions,
|
||||
sheet: form.value.sheet
|
||||
});
|
||||
if (res.code == 200) {
|
||||
tableData.value = res.data;
|
||||
}
|
||||
};
|
||||
/** 提交按钮 */
|
||||
const submitForm = (status1: string) => {
|
||||
status.value = status1;
|
||||
submit(status.value, form.value);
|
||||
};
|
||||
|
||||
const submitFlow = async () => {
|
||||
handleStartWorkFlow(form.value);
|
||||
dialogVisible.visible = false;
|
||||
};
|
||||
//提交申请
|
||||
const handleStartWorkFlow = async (data: any) => {
|
||||
try {
|
||||
submitFormData.value.flowCode = flowCode.value;
|
||||
submitFormData.value.businessId = data.id;
|
||||
//流程变量
|
||||
taskVariables.value = {
|
||||
// leave4/5 使用的流程变量
|
||||
userList: ['1', '3', '4']
|
||||
};
|
||||
submitFormData.value.variables = taskVariables.value;
|
||||
const resp = await startWorkFlow(submitFormData.value);
|
||||
if (submitVerifyRef.value) {
|
||||
buttonLoading.value = false;
|
||||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||
}
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
//审批记录
|
||||
const handleApprovalRecord = () => {
|
||||
approvalRecordRef.value.init(form.value.id);
|
||||
};
|
||||
//提交回调
|
||||
const submitCallback = async () => {
|
||||
await proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
};
|
||||
//审批
|
||||
const approvalVerifyOpen = async () => {
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||
};
|
||||
// 图纸上传成功之后 开始提交
|
||||
const submit = async (status, data) => {
|
||||
form.value = data;
|
||||
if (status === 'draft') {
|
||||
buttonLoading.value = false;
|
||||
proxy?.$modal.msgSuccess('暂存成功');
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
} else {
|
||||
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||
flowCode.value = flowCodeOptions[0].value;
|
||||
dialogVisible.visible = true;
|
||||
return;
|
||||
}
|
||||
//说明启动过先随意穿个参数
|
||||
if (flowCode.value === '' || flowCode.value === null) {
|
||||
flowCode.value = 'xx';
|
||||
}
|
||||
await handleStartWorkFlow(data);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
routeParams.value = proxy.$route.query;
|
||||
reset();
|
||||
loading.value = false;
|
||||
console.log(routeParams.value);
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getInfo();
|
||||
console.log('routeParams.value', routeParams.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式 */
|
||||
:root {
|
||||
--primary: #409eff;
|
||||
--primary-light: #66b1ff;
|
||||
--primary-dark: #3a8ee6;
|
||||
--success: #67c23a;
|
||||
--warning: #e6a23c;
|
||||
--danger: #f56c6c;
|
||||
--info: #909399;
|
||||
}
|
||||
|
||||
/* 表单样式优化 */
|
||||
.el-form-item {
|
||||
.el-form-item__label {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-input__inner,
|
||||
.el-select .el-input__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.el-textarea__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-primary {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-light);
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
.el-card {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
/* transform: translateY(-2px); */
|
||||
}
|
||||
}
|
||||
|
||||
/* 对话框样式优化 */
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="content-box">
|
||||
<el-table :data="data" @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 align="center" prop="projectName" label="工程名称" />
|
||||
<el-table-column align="center" prop="serialNumber" label="编号" />
|
||||
<el-table-column align="center" prop="to" label="致" />
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="content-box">
|
||||
<el-table :data="data" style="width: 100%" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column type="index" width="55" label="序号" align="center" />
|
||||
<el-table-column align="center" prop="projectName" label="工程名称" />
|
||||
<el-table-column align="center" prop="submitUnit" label="提出单位" />
|
||||
<el-table-column align="center" prop="specialty" label="专业">
|
||||
@ -30,7 +30,7 @@
|
||||
</el-button>
|
||||
<el-button link type="primary" icon="View" @click="handleViewInfo(scope.row)" class="ml-3"> 查看流程 </el-button>
|
||||
<el-button link type="success" icon="View" @click="handleDetail(scope.row)" class="ml-3"> 详情 </el-button>
|
||||
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)"> 删除 </el-button>
|
||||
<!-- <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)"> 删除 </el-button> -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
@ -36,12 +36,42 @@
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工程名称">
|
||||
<el-input v-model="form.projectName" />
|
||||
<el-input disabled v-model="form.projectName" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="提出单位">
|
||||
<el-input v-model="form.submitUnit" />
|
||||
<el-input v-model="form.submitUnit" placeholder="请输入提出单位" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 卷册名称 & 附图 -->
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="卷册号">
|
||||
<!-- <el-input v-model="form.volumeName" /> -->
|
||||
<el-select
|
||||
id="projectSelect"
|
||||
v-model="form.volumeNumber"
|
||||
placeholder="请选择原卷册号"
|
||||
clearable
|
||||
filterable
|
||||
@change="handleSelect"
|
||||
style="width: 150px; margin-right: 20px"
|
||||
>
|
||||
<el-option
|
||||
v-for="project in volumeCatalogList"
|
||||
:key="project.volumeNumber"
|
||||
:label="project.volumeNumber"
|
||||
:value="project.volumeNumber"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<!-- 卷册号 -->
|
||||
<el-form-item label="卷册名称">
|
||||
<el-input disabled v-model="form.volumeName" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -50,7 +80,7 @@
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="专业">
|
||||
<el-select v-model="form.specialty" placeholder="">
|
||||
<el-select disabled v-model="form.specialty" placeholder="请选择专业">
|
||||
<el-option v-for="item in des_user_major" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@ -62,27 +92,9 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 卷册名称 & 附图 -->
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="卷册名称">
|
||||
<el-input v-model="form.volumeName" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="附图">
|
||||
<file-Upload v-model="form.attachmentsImg" :file-type="['pdf', 'png', 'jpg', 'jpeg', 'gif', 'bmp']">
|
||||
<el-button type="primary">上传附件</el-button>
|
||||
</file-Upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 卷册号 -->
|
||||
<el-form-item label="卷册号">
|
||||
<el-input v-model="form.volumeNumber" />
|
||||
<el-form-item label="附图">
|
||||
<file-Upload :fileSize="50" v-model="form.attachmentsImg" :file-type="['png', 'jpg', 'jpeg']"> </file-Upload>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 变更原因 -->
|
||||
<el-form-item label="变更原因">
|
||||
<el-checkbox-group v-model="form.changeReasons">
|
||||
@ -100,10 +112,10 @@
|
||||
<el-input v-model="form.content" type="textarea" :rows="6" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
<el-form-item label="附件" prop="attachments">
|
||||
<file-upload v-model="form.attachments" :limit="1" :file-type="['pdf']"></file-upload>
|
||||
<file-upload :fileSize="50" v-model="form.attachments" :limit="1" :file-type="['pdf']"></file-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="变更费用估算" prop="costEstimation">
|
||||
<el-input v-model="form.costEstimation" :rows="6" placeholder="请输入变更费用估算" />
|
||||
<el-input v-model="form.costEstimation" :rows="6" type="number" placeholder="请输入变更费用估算" />
|
||||
</el-form-item>
|
||||
<el-divider class="mb-10! mt-10!">施工项目部</el-divider>
|
||||
<el-form-item label="项目负责人" prop="contractorLeader">
|
||||
@ -177,6 +189,7 @@ import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { listByIds } from '@/api/system/oss';
|
||||
import { addContactnotice, getContactnotice, updateContactnotice } from '@/api/cory/contactnotice';
|
||||
const { des_user_major } = toRefs(proxy?.useDict('des_user_major'));
|
||||
import { catalogList } from '@/api/design/designChange';
|
||||
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
@ -221,11 +234,11 @@ const initFormData = {
|
||||
id: undefined,
|
||||
projectId: currentProject.value?.id,
|
||||
projectType: '',
|
||||
projectName: '',
|
||||
projectName: currentProject.value?.name,
|
||||
serialNumber: '',
|
||||
to: '',
|
||||
subject: '',
|
||||
costEstimation: '',
|
||||
costEstimation: 0,
|
||||
content: '',
|
||||
attachments: '',
|
||||
contractorLeader: '',
|
||||
@ -275,13 +288,27 @@ const handleClose = () => {
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
const { form, rules } = toRefs(data);
|
||||
|
||||
const volumeCatalogList = ref([]);
|
||||
let volumeMap = new Map();
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
// 获取卷册号列表
|
||||
const getJuance = async () => {
|
||||
const res = await catalogList(currentProject.value?.id);
|
||||
volumeCatalogList.value = res.data;
|
||||
volumeCatalogList.value.forEach((e) => {
|
||||
volumeMap.set(e.volumeNumber, e);
|
||||
});
|
||||
};
|
||||
const handleSelect = (val) => {
|
||||
let obj = volumeMap.get(val);
|
||||
console.log(obj);
|
||||
form.value.volumeName = obj.documentName;
|
||||
form.value.specialty = obj.specialty;
|
||||
};
|
||||
/** 获取详情 */
|
||||
const getInfo = () => {
|
||||
loading.value = true;
|
||||
@ -345,7 +372,8 @@ const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||
//流程变量
|
||||
taskVariables.value = {
|
||||
// leave4/5 使用的流程变量
|
||||
userList: ['1', '3', '4']
|
||||
userList: ['1', '3', '4'],
|
||||
costEstimation: form.value.costEstimation
|
||||
};
|
||||
submitFormData.value.variables = taskVariables.value;
|
||||
const resp = await startWorkFlow(submitFormData.value);
|
||||
@ -402,6 +430,7 @@ onMounted(() => {
|
||||
routeParams.value = proxy.$route.query;
|
||||
thumbnailUrl.value = proxy.$route.query.thumbnailUrl;
|
||||
reset();
|
||||
getJuance();
|
||||
loading.value = false;
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getInfo();
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||
<el-table-column label="处理状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="safety_inspection_type" :value="scope.row.status" />
|
||||
<dict-tag :options="wf_business_status" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="检查人" align="center" prop="correctorName" />
|
||||
@ -46,13 +46,16 @@
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="220">
|
||||
<template #default="scope">
|
||||
<el-space>
|
||||
<el-button link type="primary" icon="View" @click="handleDetail(scope.row)" v-hasPermi="['safety:safetyInspection:query']">
|
||||
详情
|
||||
<el-button link type="primary" icon="View" @click="handleDetail(scope.row)"> 详情 </el-button>
|
||||
<el-button link type="primary" icon="Edit" @click="handleAddApp(scope.row)" v-if="scope.row.status && scope.row.status == 'draft'"
|
||||
>审批
|
||||
</el-button>
|
||||
<!-- <el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['safety:safetyInspection:edit']">修改 </el-button> -->
|
||||
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['safety:safetyInspection:remove']">
|
||||
<el-button link type="primary" icon="View" @click="handleAddApp(scope.row)" v-if="scope.row.status && scope.row.status != 'draft'"
|
||||
>查看流程
|
||||
</el-button>
|
||||
<!-- <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['safety:safetyInspection:remove']">
|
||||
删除
|
||||
</el-button>
|
||||
</el-button> -->
|
||||
</el-space>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -191,9 +194,10 @@ const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
|
||||
const { safety_inspection_violation_type, safety_inspection_check_type, review_type, safety_inspection_type } = toRefs<any>(
|
||||
useDict('safety_inspection_violation_type', 'safety_inspection_check_type', 'review_type', 'safety_inspection_type')
|
||||
const { safety_inspection_violation_type, safety_inspection_check_type, review_type, safety_inspection_type, wf_business_status } = toRefs<any>(
|
||||
useDict('safety_inspection_violation_type', 'safety_inspection_check_type', 'review_type', 'safety_inspection_type', 'wf_business_status')
|
||||
);
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const safetyInspectionDetail = ref<SafetyInspectionVO>();
|
||||
|
||||
const form = reactive({
|
||||
@ -236,6 +240,18 @@ const handleDetail = async (row) => {
|
||||
rectificationFileList.value = rectificationFileRes.data;
|
||||
}
|
||||
};
|
||||
const handleAddApp = (row) => {
|
||||
// 添加审批
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/workMessage/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
|
||||
type: 'update'
|
||||
}
|
||||
});
|
||||
};
|
||||
const getList = (row) => {};
|
||||
const handleDelete = (row) => {};
|
||||
</script>
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" :disabled="addSingle" @click="handleAdd" v-hasPermi="['quality:qualityInspection:add']"
|
||||
<el-button type="primary" plain icon="Plus" :disabled="addSingle" @click="handleAdd" v-hasPermi="['cory:contactnotice:add']"
|
||||
>新增</el-button
|
||||
>
|
||||
</el-col>
|
||||
@ -31,13 +31,7 @@
|
||||
>
|
||||
</el-col> -->
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="Delete"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete()"
|
||||
v-hasPermi="['quality:qualityInspection:remove']"
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['cory:contactnotice:remove']"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-col>
|
||||
@ -306,6 +300,7 @@ const selectType = (value: string) => {
|
||||
const resetForm = () => {
|
||||
formRef.value?.resetFields();
|
||||
};
|
||||
|
||||
//监听项目id刷新数据
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
|
||||
482
src/views/cory/workMessage/indexEdit.vue
Normal file
@ -0,0 +1,482 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 顶部按钮区域 -->
|
||||
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||
<approvalButton
|
||||
@submitForm="submitForm"
|
||||
@approvalVerifyOpen="approvalVerifyOpen"
|
||||
@handleApprovalRecord="handleApprovalRecord"
|
||||
:buttonLoading="buttonLoading"
|
||||
:id="form.id"
|
||||
:status="form.status"
|
||||
:pageType="routeParams.type"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 表单区域 -->
|
||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-800">工作联系单审批</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<div class="w80% ma">
|
||||
<h2 style="text-align: center; margin-top: 5px; font-weight: bold">通知单</h2>
|
||||
<el-row>
|
||||
<el-col :span="12" style="text-align: left">填报人:{{ safetyInspectionDetail?.creatorName }}</el-col>
|
||||
<el-col :span="12" style="text-align: right">填报时间:{{ safetyInspectionDetail?.createTime }}</el-col>
|
||||
</el-row>
|
||||
<el-descriptions :column="2" border style="margin-top: 8px" label-width="160px" size="large">
|
||||
<el-descriptions-item label-align="center" label="检查项目" :span="2" class-name="zebra"
|
||||
>{{ currentProject?.name }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label-align="center" label="检查类型" label-class-name="white">
|
||||
<dict-tag :options="safety_inspection_check_type" :value="safetyInspectionDetail?.checkType" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label-align="center" label="违章类型" label-class-name="white">
|
||||
<dict-tag :options="safety_inspection_violation_type" :value="safetyInspectionDetail?.violationType" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label-align="center" label="检查时间" class-name="zebra"
|
||||
>{{ safetyInspectionDetail?.checkTime }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label-align="center" label="检查人" class-name="zebra"
|
||||
>{{ safetyInspectionDetail?.creatorName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label-align="center" label="整改人" label-class-name="white"
|
||||
>{{ safetyInspectionDetail?.correctorName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label-align="center" label="要求整改期限" label-class-name="white">
|
||||
{{ dayjs(safetyInspectionDetail?.rectificationDeadline).format('YYYY 年 MM 月 DD 日') }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-descriptions border direction="vertical" size="large">
|
||||
<el-descriptions-item label-align="center" label="巡检结果" class-name="none"></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-descriptions :column="2" border label-width="160px" size="large">
|
||||
<el-descriptions-item label-align="center" label="内容" :span="2" label-class-name="white"
|
||||
>{{ safetyInspectionDetail?.hiddenDanger }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label-align="center" label="检查附件" :span="2" label-class-name="white">
|
||||
<el-space wrap>
|
||||
<div v-for="item in checkFileList" :key="item.ossId">
|
||||
<span v-if="['.png', '.jpg', '.jpeg'].includes(item.fileSuffix)">
|
||||
<image-preview :src="item.url" width="200px" />
|
||||
</span>
|
||||
<span v-else>
|
||||
<el-link :href="`${item.url}`" type="primary" :underline="false" target="_blank">
|
||||
<span> {{ item.originalName }} </span>
|
||||
</el-link>
|
||||
</span>
|
||||
</div>
|
||||
</el-space>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label-align="center" label="检查状态" :span="2" label-class-name="white">
|
||||
<el-steps style="max-width: 200px" :active="Number(safetyInspectionDetail?.status)" finish-status="finish">
|
||||
<el-step v-for="item in safety_inspection_type" :key="item.value" :title="item.label" />
|
||||
</el-steps>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-descriptions border direction="vertical" size="large">
|
||||
<el-descriptions-item label-align="center" label="整改情况" class-name="none"></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-descriptions :column="2" border label-width="160px" size="large">
|
||||
<el-descriptions-item label-align="center" label="班组" label-class-name="white"
|
||||
>{{ safetyInspectionDetail?.teamName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label-align="center" label="整改日期" label-class-name="white"
|
||||
>{{ safetyInspectionDetail?.rectificationTime }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label-align="center" label="整改措施及完成情况" :span="2" label-class-name="white">
|
||||
{{ safetyInspectionDetail?.measure }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label-align="center" label="整改附件" :span="2" label-class-name="white">
|
||||
<el-space wrap>
|
||||
<div v-for="item in rectificationFileList" :key="item.ossId">
|
||||
<span v-if="['.png', '.jpg', '.jpeg'].includes(item.fileSuffix)">
|
||||
<image-preview :src="item.url" width="200px" />
|
||||
</span>
|
||||
<span v-else>
|
||||
<el-link :href="`${item.url}`" :underline="false" target="_blank">
|
||||
<span> {{ item.originalName }} </span>
|
||||
</el-link>
|
||||
</span>
|
||||
</div>
|
||||
</el-space>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-descriptions border direction="vertical" size="large">
|
||||
<el-descriptions-item label-align="center" label="复查结果" class-name="none"></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-descriptions :column="2" border label-width="160px" size="large">
|
||||
<el-descriptions-item label-align="center" label="复查人" label-class-name="white"
|
||||
>{{ safetyInspectionDetail?.creatorName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label-align="center" label="复查日期" label-class-name="white"
|
||||
>{{ safetyInspectionDetail?.reviewTime }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label-align="center" label="复查情况" :span="2" label-class-name="white"
|
||||
>{{ safetyInspectionDetail?.review }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||
<!-- 流程选择对话框 -->
|
||||
<el-dialog
|
||||
draggable
|
||||
v-model="dialogVisible.visible"
|
||||
:title="dialogVisible.title"
|
||||
:before-close="handleClose"
|
||||
width="500"
|
||||
class="rounded-lg shadow-lg"
|
||||
>
|
||||
<div class="p-4">
|
||||
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||
>取消</el-button
|
||||
>
|
||||
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||
>确认</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Leave" lang="ts">
|
||||
import { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types';
|
||||
import { startWorkFlow } from '@/api/workflow/task';
|
||||
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { listByIds } from '@/api/system/oss';
|
||||
import { dayjs } from 'element-plus';
|
||||
import { useDict } from '@/utils/dict';
|
||||
import { SafetyInspectionVO } from '@/api/safety/safetyInspection/types';
|
||||
// const { des_user_major } = toRefs(proxy?.useDict('des_user_major'));
|
||||
import { getContactnotice } from '@/api/cory/contactnotice';
|
||||
const { safety_inspection_violation_type, safety_inspection_check_type, review_type, safety_inspection_type, wf_business_status } = toRefs<any>(
|
||||
useDict('safety_inspection_violation_type', 'safety_inspection_check_type', 'review_type', 'safety_inspection_type', 'wf_business_status')
|
||||
);
|
||||
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const thumbnailUrl = ref('');
|
||||
//路由参数
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
const flowCodeOptions = [
|
||||
{
|
||||
value: currentProject.value?.id + '_contactForm',
|
||||
label: '工作联系单审批'
|
||||
}
|
||||
];
|
||||
|
||||
const flowCode = ref<string>('');
|
||||
const status = ref<string>('');
|
||||
const dialogVisible = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '流程定义'
|
||||
});
|
||||
//提交组件
|
||||
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||
//审批记录组件
|
||||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: '',
|
||||
isEdit: false
|
||||
});
|
||||
const submitFormData = ref<StartProcessBo>({
|
||||
businessId: '',
|
||||
flowCode: '',
|
||||
variables: {}
|
||||
});
|
||||
const taskVariables = ref<Record<string, any>>({});
|
||||
|
||||
const initFormData = {
|
||||
id: undefined,
|
||||
projectId: currentProject.value?.id,
|
||||
projectType: '',
|
||||
projectName: '',
|
||||
serialNumber: '',
|
||||
to: '',
|
||||
subject: '',
|
||||
costEstimation: '',
|
||||
content: '',
|
||||
attachments: '',
|
||||
contractorLeader: '',
|
||||
contractorDate: '',
|
||||
supervisorLeader: '',
|
||||
supervisorDate: '',
|
||||
ownerRep: '',
|
||||
ownerDate: '',
|
||||
unitName: '',
|
||||
profession: '',
|
||||
applyDate: '',
|
||||
bookName: '',
|
||||
bookNo: '',
|
||||
hasAttachment: '',
|
||||
changeReasons: [],
|
||||
changeContent: '',
|
||||
costEstimate: '',
|
||||
status: ''
|
||||
};
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: currentProject.value?.id,
|
||||
fileName: undefined,
|
||||
fileType: undefined,
|
||||
fileSuffix: undefined,
|
||||
fileStatus: undefined,
|
||||
originalName: undefined,
|
||||
newest: undefined,
|
||||
params: {}
|
||||
}
|
||||
});
|
||||
const safetyInspectionDetail = ref<SafetyInspectionVO>();
|
||||
const handleClose = () => {
|
||||
dialogVisible.visible = false;
|
||||
flowCode.value = '';
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
const { form } = toRefs(data);
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
const checkFileList: any = ref([]);
|
||||
const rectificationFileList: any = ref([]);
|
||||
/** 获取详情 */
|
||||
const getInfo = () => {
|
||||
loading.value = true;
|
||||
buttonLoading.value = false;
|
||||
nextTick(async () => {
|
||||
const res = await getContactnotice(routeParams.value.id);
|
||||
console.log(res.data);
|
||||
const detail = res.data.detail ? JSON.parse(res.data.detail) : {};
|
||||
safetyInspectionDetail.value = { ...res.data, ...detail };
|
||||
if (safetyInspectionDetail.value.checkFile) {
|
||||
const checkFileRes = await listByIds(safetyInspectionDetail.value.checkFile.split(','));
|
||||
checkFileList.value = checkFileRes.data;
|
||||
}
|
||||
if (safetyInspectionDetail.value.rectificationFile) {
|
||||
const rectificationFileRes = await listByIds(safetyInspectionDetail.value.rectificationFile.split(','));
|
||||
rectificationFileList.value = rectificationFileRes.data;
|
||||
}
|
||||
|
||||
Object.assign(form.value, safetyInspectionDetail.value);
|
||||
loading.value = false;
|
||||
buttonLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const submitFlow = async () => {
|
||||
console.log('form.value', form.value);
|
||||
|
||||
handleStartWorkFlow(form.value);
|
||||
dialogVisible.visible = false;
|
||||
};
|
||||
//提交申请
|
||||
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||
console.log('data', data);
|
||||
|
||||
try {
|
||||
submitFormData.value.flowCode = flowCode.value;
|
||||
submitFormData.value.businessId = data.id;
|
||||
//流程变量
|
||||
taskVariables.value = {
|
||||
// leave4/5 使用的流程变量
|
||||
userList: ['1', '3', '4']
|
||||
};
|
||||
submitFormData.value.variables = taskVariables.value;
|
||||
const resp = await startWorkFlow(submitFormData.value);
|
||||
if (submitVerifyRef.value) {
|
||||
buttonLoading.value = false;
|
||||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||
}
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
/** 提交按钮 */
|
||||
const submitForm = (status1: string) => {
|
||||
status.value = status1;
|
||||
submit(status.value, form.value);
|
||||
};
|
||||
//审批记录
|
||||
const handleApprovalRecord = () => {
|
||||
approvalRecordRef.value.init(form.value.id);
|
||||
};
|
||||
//提交回调
|
||||
const submitCallback = async () => {
|
||||
await proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
};
|
||||
|
||||
//审批
|
||||
const approvalVerifyOpen = async () => {
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||
};
|
||||
// 图纸上传成功之后 开始提交
|
||||
const submit = async (status, data) => {
|
||||
form.value = data;
|
||||
if (status === 'draft') {
|
||||
buttonLoading.value = false;
|
||||
proxy?.$modal.msgSuccess('暂存成功');
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
} else {
|
||||
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||
flowCode.value = flowCodeOptions[0].value;
|
||||
dialogVisible.visible = true;
|
||||
return;
|
||||
}
|
||||
//说明启动过先随意穿个参数
|
||||
if (flowCode.value === '' || flowCode.value === null) {
|
||||
flowCode.value = 'xx';
|
||||
}
|
||||
console.log('data', data);
|
||||
await handleStartWorkFlow(data);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
routeParams.value = proxy.$route.query;
|
||||
reset();
|
||||
loading.value = false;
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getInfo();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式 */
|
||||
:root {
|
||||
--primary: #409eff;
|
||||
--primary-light: #66b1ff;
|
||||
--primary-dark: #3a8ee6;
|
||||
--success: #67c23a;
|
||||
--warning: #e6a23c;
|
||||
--danger: #f56c6c;
|
||||
--info: #909399;
|
||||
}
|
||||
|
||||
/* 表单样式优化 */
|
||||
.el-form-item {
|
||||
.el-form-item__label {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-input__inner,
|
||||
.el-select .el-input__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.el-textarea__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-primary {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-light);
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
.el-card {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
/* transform: translateY(-2px); */
|
||||
}
|
||||
}
|
||||
|
||||
/* 对话框样式优化 */
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,94 +1,57 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
|
||||
:leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<!-- <el-form-item label="项目ID" prop="projectId">
|
||||
<el-input v-model="queryParams.projectId" placeholder="请输入项目ID" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item> -->
|
||||
<el-form-item label="合同编号" prop="contractCode">
|
||||
<el-input v-model="queryParams.contractCode" placeholder="请输入合同编号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="供应商" prop="contractSupplier">
|
||||
<el-input v-model="queryParams.contractSupplier" placeholder="请输入供应商" clearable
|
||||
@keyup.enter="handleQuery" />
|
||||
<el-input v-model="queryParams.contractSupplier" placeholder="请输入供应商" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同金额" prop="amount">
|
||||
<el-input v-model="queryParams.amount" placeholder="请输入合同金额" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="招标Id" prop="tenderId">
|
||||
<el-input v-model="queryParams.tenderId" placeholder="请输入招标Id" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item> -->
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<!-- <el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd"
|
||||
v-hasPermi="['ctr:expensesContract:add']">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
|
||||
v-hasPermi="['ctr:expensesContract:edit']">修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
|
||||
v-hasPermi="['ctr:expensesContract:remove']">删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="Download" @click="handleExport"
|
||||
v-hasPermi="['ctr:expensesContract:export']">导出</el-button>
|
||||
</el-col>-->
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" :data="expensesContractList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<!-- <el-table-column label="主键ID" align="center" prop="id" v-if="true" /> -->
|
||||
<el-table-column type="index" width="50" label="序号" />
|
||||
<!-- <el-table-column label="项目ID" align="center" prop="projectId" /> -->
|
||||
<el-table-column label="合同编号" align="center" prop="contractCode" />
|
||||
<el-table-column label="合同类型" align="center" prop="contractType" />
|
||||
<el-table-column label="合同类型" align="center" prop="contractType">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="expenses_contract_type" :value="scope.row.contractType" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="支付方式" align="center" prop="payType">
|
||||
<template #default="scope">
|
||||
<el-tag type="success" v-if="scope.row.payType == '1'">月结算</el-tag>
|
||||
<el-tag type="primary" v-else-if="scope.row.payType == '2'">形象节点</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="供应商" align="center" prop="contractSupplier" />
|
||||
<el-table-column label="分包内容" align="center" prop="contractedContent" />
|
||||
<el-table-column label="合同金额" align="center" prop="amount" />
|
||||
<!-- <el-table-column label="招标Id" align="center" prop="tenderId" /> -->
|
||||
<el-table-column label="预付款比例(%)" align="center" prop="advancePayRatio" />
|
||||
<el-table-column label="尾款比例(%)" align="center" prop="balancePayRatio" />
|
||||
<el-table-column label="质保金比例(%)" align="center" prop="assuranceDepositRatio" />
|
||||
<el-table-column label="付款比例(%)" align="center" prop="payRatio" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<!-- <el-tooltip content="修改" placement="top">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['ctr:expensesContract:edit']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top">
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
|
||||
v-hasPermi="['ctr:expensesContract:remove']"></el-button>
|
||||
</el-tooltip> -->
|
||||
<el-tooltip content="查看附件列表" placement="top">
|
||||
<el-button link type="primary" icon="View" @click="handleShowFileList(scope.row)">查看附件列表</el-button>
|
||||
</el-tooltip>
|
||||
<el-button link type="success" icon="View" @click="handleShowDetail(scope.row)">查看分包内容</el-button>
|
||||
<el-button link type="primary" v-hasPermi="['ctr:expensesContract:query']" icon="View" @click="handleShowFileList(scope.row)"
|
||||
>查看附件列表</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</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-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||
@ -123,20 +86,33 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
<FileList v-model="fileListVisible" :fileList="fileList" />
|
||||
<el-dialog v-model="detailVisible" title="分包内容详情" width="45%">
|
||||
<editor :model-value="detailContent" :min-height="192" readOnly placeholder="" />
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="detailVisible = false"> 关闭 </el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ExpensesContract" lang="ts">
|
||||
import { listExpensesContract, getExpensesContract, delExpensesContract, addExpensesContract, updateExpensesContract, getFileList } from '@/api/ctr/expensesContract';
|
||||
import {
|
||||
listExpensesContract,
|
||||
getExpensesContract,
|
||||
delExpensesContract,
|
||||
addExpensesContract,
|
||||
updateExpensesContract,
|
||||
getFileList
|
||||
} from '@/api/ctr/expensesContract';
|
||||
import { ExpensesContractVO, ExpensesContractQuery, ExpensesContractForm } from '@/api/ctr/expensesContract/types';
|
||||
import FileList from '@/components/FileList/index.vue';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { expenses_contract_type, income_contract_type } = toRefs(
|
||||
proxy?.useDict('income_contract_type', 'expenses_contract_type')
|
||||
);
|
||||
const { expenses_contract_type, income_contract_type } = toRefs(proxy?.useDict('income_contract_type', 'expenses_contract_type'));
|
||||
const expensesContractList = ref<ExpensesContractVO[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
@ -151,6 +127,8 @@ const userStore = useUserStore();
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const expensesContractFormRef = ref<ElFormInstance>();
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const detailContent = ref('');
|
||||
const detailVisible = ref(false); // 控制承包内容详情对话框的显示
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
@ -166,8 +144,8 @@ const initFormData: ExpensesContractForm = {
|
||||
contractedContent: undefined,
|
||||
amount: undefined,
|
||||
tenderId: undefined,
|
||||
remark: undefined,
|
||||
}
|
||||
remark: undefined
|
||||
};
|
||||
const data = reactive<PageData<ExpensesContractForm, ExpensesContractQuery>>({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
@ -180,16 +158,11 @@ const data = reactive<PageData<ExpensesContractForm, ExpensesContractQuery>>({
|
||||
contractedContent: undefined,
|
||||
amount: undefined,
|
||||
tenderId: undefined,
|
||||
params: {
|
||||
}
|
||||
params: {}
|
||||
},
|
||||
rules: {
|
||||
id: [
|
||||
{ required: true, message: "主键ID不能为空", trigger: "blur" }
|
||||
],
|
||||
projectId: [
|
||||
{ required: true, message: "项目ID不能为空", trigger: "blur" }
|
||||
],
|
||||
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
||||
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }]
|
||||
}
|
||||
});
|
||||
|
||||
@ -202,55 +175,55 @@ const getList = async () => {
|
||||
expensesContractList.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
expensesContractFormRef.value?.resetFields();
|
||||
}
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
}
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
};
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: ExpensesContractVO[]) => {
|
||||
ids.value = selection.map(item => item.id);
|
||||
ids.value = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
}
|
||||
};
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加支出合同";
|
||||
}
|
||||
dialog.title = '添加支出合同';
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: ExpensesContractVO) => {
|
||||
reset();
|
||||
const _id = row?.id || ids.value[0]
|
||||
const _id = row?.id || ids.value[0];
|
||||
const res = await getExpensesContract(_id);
|
||||
Object.assign(form.value, res.data);
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改支出合同";
|
||||
}
|
||||
dialog.title = '修改支出合同';
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
@ -258,43 +231,51 @@ const submitForm = () => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.id) {
|
||||
await updateExpensesContract(form.value).finally(() => buttonLoading.value = false);
|
||||
await updateExpensesContract(form.value).finally(() => (buttonLoading.value = false));
|
||||
} else {
|
||||
await addExpensesContract(form.value).finally(() => buttonLoading.value = false);
|
||||
await addExpensesContract(form.value).finally(() => (buttonLoading.value = false));
|
||||
}
|
||||
proxy?.$modal.msgSuccess("操作成功");
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: ExpensesContractVO) => {
|
||||
const _ids = row?.id || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除支出合同编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
|
||||
await proxy?.$modal.confirm('是否确认删除支出合同编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||
await delExpensesContract(_ids);
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
await getList();
|
||||
}
|
||||
};
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.download('ctr/expensesContract/export', {
|
||||
...queryParams.value
|
||||
}, `expensesContract_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
proxy?.download(
|
||||
'ctr/expensesContract/export',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`expensesContract_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
};
|
||||
// 查看附件列表操作
|
||||
const handleShowFileList = async (row: ExpensesContractVO) => {
|
||||
await getFileList({ contractId: row.id }).then(res => {
|
||||
fileList.value = res.rows
|
||||
fileListVisible.value = true;
|
||||
}).catch(() => {
|
||||
proxy?.$modal.error("获取文件列表失败");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
await getFileList({ contractId: row.id })
|
||||
.then((res) => {
|
||||
fileList.value = res.rows;
|
||||
fileListVisible.value = true;
|
||||
})
|
||||
.catch(() => {
|
||||
proxy?.$modal.error('获取文件列表失败');
|
||||
});
|
||||
};
|
||||
const handleShowDetail = (data) => {
|
||||
detailContent.value = data.contractedContent;
|
||||
detailVisible.value = true;
|
||||
};
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
@ -1,89 +1,65 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
|
||||
:leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<!-- <el-form-item label="项目ID" prop="projectId">
|
||||
<el-input v-model="queryParams.projectId" placeholder="请输入项目ID" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item> -->
|
||||
<el-form-item label="合同编号" prop="contractCode">
|
||||
<el-input v-model="queryParams.contractCode" placeholder="请输入合同编号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="业主单位" prop="contractOwner">
|
||||
<el-input v-model="queryParams.contractOwner" placeholder="请输入业主单位" clearable
|
||||
@keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同金额" prop="amount">
|
||||
<el-input v-model="queryParams.amount" placeholder="请输入合同金额" clearable @keyup.enter="handleQuery" />
|
||||
<el-input v-model="queryParams.contractOwner" placeholder="请输入业主单位" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<!-- <el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd"
|
||||
v-hasPermi="['ctr:incomeContract:add']">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
|
||||
v-hasPermi="['ctr:incomeContract:edit']">修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
|
||||
v-hasPermi="['ctr:incomeContract:remove']">删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="Download" @click="handleExport"
|
||||
v-hasPermi="['ctr:incomeContract:export']">导出</el-button>
|
||||
</el-col>-->
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" :data="incomeContractList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<!-- <el-table-column label="主键ID" align="center" prop="id" v-if="true" /> -->
|
||||
<el-table-column type="index" width="50" label="序号" />
|
||||
<!-- <el-table-column label="项目ID" align="center" prop="projectId" /> -->
|
||||
<el-table-column label="合同编号" align="center" prop="contractCode" />
|
||||
<el-table-column label="合同类型" align="center" prop="contractType">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="income_contract_type" :value="scope.row.contractType" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="业主单位" align="center" prop="contractOwner" />
|
||||
<el-table-column label="承包内容" align="center" prop="contractedContent" />
|
||||
<el-table-column label="合同金额" align="center" prop="amount" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<el-table-column label="支付方式" align="center" prop="payType">
|
||||
<template #default="scope">
|
||||
<!-- <el-tooltip content="修改" placement="top">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['ctr:incomeContract:edit']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top">
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
|
||||
v-hasPermi="['ctr:incomeContract:remove']"></el-button>
|
||||
</el-tooltip> -->
|
||||
<el-tooltip content="查看附件列表" placement="top">
|
||||
<el-button link type="primary" icon="View" @click="handleShowFileList(scope.row)">查看附件列表</el-button>
|
||||
</el-tooltip>
|
||||
<el-tag type="success" v-if="scope.row.payType == '1'">月结算</el-tag>
|
||||
<el-tag type="primary" v-else-if="scope.row.payType == '2'">形象节点</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="业主单位" align="center" prop="contractOwner" />
|
||||
<el-table-column label="合同金额" align="center" prop="amount" />
|
||||
<el-table-column label="预付款比例(%)" align="center" prop="advancePayRatio" />
|
||||
<el-table-column label="尾款比例(%)" align="center" prop="balancePayRatio" />
|
||||
<el-table-column label="质保金比例(%)" align="center" prop="assuranceDepositRatio" />
|
||||
<el-table-column label="付款比例(%)" align="center" prop="payRatio" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
v-hasPermi="['ctr:incomeContract:edit']"
|
||||
icon="edit"
|
||||
@click="handleEdit(scope.row)"
|
||||
v-if="scope.row.isUpdate"
|
||||
>修改合同</el-button
|
||||
>
|
||||
<el-button link type="success" icon="View" @click="handleShowDetail(scope.row)">查看合同内容</el-button>
|
||||
<el-button link type="primary" v-hasPermi="['ctr:incomeContract:query']" icon="View" @click="handleShowFileList(scope.row)"
|
||||
>查看附件列表</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</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-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||
@ -115,21 +91,39 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
<FileList v-model="fileListVisible" :fileList="fileList" />
|
||||
<el-dialog v-model="detailVisible" title="合同内容详情" width="45%">
|
||||
<editor :model-value="detailContent" :min-height="192" readOnly placeholder="" />
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="detailVisible = false"> 关闭 </el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="IncomeContract" lang="ts">
|
||||
import { listIncomeContract, getIncomeContract, delIncomeContract, addIncomeContract, updateIncomeContract, getFileList } from '@/api/ctr/incomeContract';
|
||||
import {
|
||||
listIncomeContract,
|
||||
getIncomeContract,
|
||||
delIncomeContract,
|
||||
addIncomeContract,
|
||||
updateIncomeContract,
|
||||
getFileList,
|
||||
getInfoByProjectId
|
||||
} from '@/api/ctr/incomeContract';
|
||||
import { IncomeContractVO, IncomeContractQuery, IncomeContractForm } from '@/api/ctr/incomeContract/types';
|
||||
import FileList from '@/components/FileList/index.vue';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const userStore = useUserStore();
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const router = useRouter();
|
||||
|
||||
const { expenses_contract_type, income_contract_type } = toRefs(
|
||||
proxy?.useDict('income_contract_type', 'expenses_contract_type')
|
||||
);
|
||||
const { expenses_contract_type, income_contract_type } = toRefs(proxy?.useDict('income_contract_type', 'expenses_contract_type'));
|
||||
const incomeContractList = ref<IncomeContractVO[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
@ -146,7 +140,8 @@ const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const detailVisible = ref(false); // 控制承包内容详情对话框的显示
|
||||
const detailContent = ref('');
|
||||
const initFormData: IncomeContractForm = {
|
||||
id: undefined,
|
||||
projectId: undefined,
|
||||
@ -155,8 +150,8 @@ const initFormData: IncomeContractForm = {
|
||||
contractOwner: undefined,
|
||||
contractedContent: undefined,
|
||||
amount: undefined,
|
||||
remark: undefined,
|
||||
}
|
||||
remark: undefined
|
||||
};
|
||||
const data = reactive<PageData<IncomeContractForm, IncomeContractQuery>>({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
@ -168,16 +163,11 @@ const data = reactive<PageData<IncomeContractForm, IncomeContractQuery>>({
|
||||
contractOwner: undefined,
|
||||
contractedContent: undefined,
|
||||
amount: undefined,
|
||||
params: {
|
||||
}
|
||||
params: {}
|
||||
},
|
||||
rules: {
|
||||
id: [
|
||||
{ required: true, message: "主键ID不能为空", trigger: "blur" }
|
||||
],
|
||||
projectId: [
|
||||
{ required: true, message: "项目ID不能为空", trigger: "blur" }
|
||||
],
|
||||
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
||||
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }]
|
||||
}
|
||||
});
|
||||
|
||||
@ -190,55 +180,55 @@ const getList = async () => {
|
||||
incomeContractList.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
incomeContractFormRef.value?.resetFields();
|
||||
}
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
}
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
};
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: IncomeContractVO[]) => {
|
||||
ids.value = selection.map(item => item.id);
|
||||
ids.value = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
}
|
||||
};
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加收入合同";
|
||||
}
|
||||
dialog.title = '添加收入合同';
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: IncomeContractVO) => {
|
||||
reset();
|
||||
const _id = row?.id || ids.value[0]
|
||||
const _id = row?.id || ids.value[0];
|
||||
const res = await getIncomeContract(_id);
|
||||
Object.assign(form.value, res.data);
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改收入合同";
|
||||
}
|
||||
dialog.title = '修改收入合同';
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
@ -246,44 +236,63 @@ const submitForm = () => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.id) {
|
||||
await updateIncomeContract(form.value).finally(() => buttonLoading.value = false);
|
||||
await updateIncomeContract(form.value).finally(() => (buttonLoading.value = false));
|
||||
} else {
|
||||
await addIncomeContract(form.value).finally(() => buttonLoading.value = false);
|
||||
await addIncomeContract(form.value).finally(() => (buttonLoading.value = false));
|
||||
}
|
||||
proxy?.$modal.msgSuccess("操作成功");
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: IncomeContractVO) => {
|
||||
const _ids = row?.id || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除收入合同编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
|
||||
await proxy?.$modal.confirm('是否确认删除收入合同编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||
await delIncomeContract(_ids);
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
await getList();
|
||||
}
|
||||
};
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.download('ctr/incomeContract/export', {
|
||||
...queryParams.value
|
||||
}, `incomeContract_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
proxy?.download(
|
||||
'ctr/incomeContract/export',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`incomeContract_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
};
|
||||
// 查看附件列表操作
|
||||
const handleShowFileList = async (row: IncomeContractVO) => {
|
||||
console.log(row.id);
|
||||
|
||||
await getFileList({ contractId: row.id }).then(res => {
|
||||
fileList.value = res.rows
|
||||
fileListVisible.value = true;
|
||||
}).catch(() => {
|
||||
proxy?.$modal.error("获取文件列表失败");
|
||||
});
|
||||
await getFileList({ contractId: row.id })
|
||||
.then((res) => {
|
||||
fileList.value = res.rows;
|
||||
fileListVisible.value = true;
|
||||
})
|
||||
.catch(() => {
|
||||
proxy?.$modal.error('获取文件列表失败');
|
||||
});
|
||||
};
|
||||
const handleEdit = (row: IncomeContractVO) => {
|
||||
// console.log(router);
|
||||
|
||||
}
|
||||
router.push({
|
||||
path: '/ctr/update',
|
||||
query: {
|
||||
id: row.id
|
||||
}
|
||||
});
|
||||
};
|
||||
const handleShowDetail = (data) => {
|
||||
detailContent.value = data.contractedContent;
|
||||
detailVisible.value = true;
|
||||
};
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
@ -1,408 +1,439 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<el-steps style="max-width: 100%" :active="active" finish-status="success" align-center>
|
||||
<el-step title="选择合同类型" />
|
||||
<el-step title="录入合同内容" />
|
||||
<el-step title="录入收款方式" />
|
||||
</el-steps>
|
||||
<div class="content">
|
||||
<template v-if="active == 0">
|
||||
<div>
|
||||
<el-button type="success" size="large" @click="checkContractType('income')">收入合同</el-button>
|
||||
<el-button type="primary" size="large" @click="checkContractType('expenses')">支出合同</el-button>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<template v-else-if="active == 1">
|
||||
<h1>{{ contract_type == "income" ? "收入合同" : "支出合同" }}</h1>
|
||||
<template v-if="contract_type == 'income'">
|
||||
<el-form ref="incomeContractFormRef" :model="form" :rules="incomeContractFormRules"
|
||||
label-width="80px">
|
||||
<!-- <el-form-item label="项目名称">
|
||||
<div class="container">
|
||||
<el-steps style="max-width: 100%" :active="active" finish-status="success" align-center>
|
||||
<el-step title="选择合同类型" />
|
||||
<el-step title="录入合同内容" />
|
||||
<el-step title="录入收款方式" />
|
||||
</el-steps>
|
||||
<div class="content">
|
||||
<template v-if="active == 0">
|
||||
<div>
|
||||
<el-button type="success" size="large" @click="checkContractType('income')">收入合同</el-button>
|
||||
<el-button type="primary" size="large" @click="checkContractType('expenses')">支出合同</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="active == 1">
|
||||
<h1>{{ contract_type == 'income' ? '收入合同' : '支出合同' }}</h1>
|
||||
<template v-if="contract_type == 'income'">
|
||||
<el-form ref="incomeContractFormRef" :model="form" :rules="incomeContractFormRules" label-width="80px">
|
||||
<!-- <el-form-item label="项目名称">
|
||||
<el-input :model-value="project.name" disabled />
|
||||
</el-form-item> -->
|
||||
<el-form-item label="合同编号" prop="contractCode">
|
||||
<el-input v-model="form.contractCode" placeholder="请输入合同编号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同类型" prop="contractType">
|
||||
<el-select v-model="form.contractType" placeholder="请选择合同类型">
|
||||
<el-option v-for="item in income_contract_type" :key="item.value" :label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="业主单位" prop="contractOwner">
|
||||
<el-input v-model="form.contractOwner" placeholder="请输入业主单位" />
|
||||
</el-form-item>
|
||||
<el-form-item label="承包内容">
|
||||
<editor v-model="form.contractedContent" :min-height="192" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同金额" prop="amount">
|
||||
<el-input v-model="form.amount" placeholder="请输入合同金额"
|
||||
oninput="value=value.replace(/[^0-9.]/g,'').replace(/\.{2,}/g,'.').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
<el-form-item label="附件">
|
||||
<FileUpload :multiple="true" :fileType="['pdf']" :onUploadSuccess="onUploadSuccess"
|
||||
:ref="fileRef" :defaultFileList="tempFileList" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
<template v-else-if="contract_type == 'expenses'">
|
||||
<el-form ref="expensesContractFormRef" :model="form" :rules="expensesContractFormRules"
|
||||
label-width="80px">
|
||||
<!-- <el-form-item label="项目名称">
|
||||
<el-form-item label="合同编号" prop="contractCode">
|
||||
<el-input v-model="form.contractCode" placeholder="请输入合同编号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同类型" prop="contractType">
|
||||
<el-select v-model="form.contractType" placeholder="请选择合同类型">
|
||||
<el-option v-for="item in income_contract_type" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="业主单位" prop="contractOwner">
|
||||
<el-input disabled v-model="form.contractOwner" placeholder="请输入业主单位" />
|
||||
</el-form-item>
|
||||
<el-form-item label="承包内容" v-if="contract_type !== 'income'">
|
||||
<editor v-model="form.contractedContent" :min-height="192" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同内容" v-else>
|
||||
<editor v-model="form.contractedContent" :min-height="192" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同金额" prop="amount">
|
||||
<el-input
|
||||
v-model="form.amount"
|
||||
placeholder="请输入合同金额"
|
||||
oninput="value=value.replace(/[^0-9.]/g,'').replace(/\.{2,}/g,'.').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
<el-form-item label="附件">
|
||||
<FileUpload :multiple="true" :fileType="['pdf']" :onUploadSuccess="onUploadSuccess" :ref="fileRef" :defaultFileList="tempFileList" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
<template v-else-if="contract_type == 'expenses'">
|
||||
<el-form ref="expensesContractFormRef" :model="form" :rules="expensesContractFormRules" label-width="80px">
|
||||
<!-- <el-form-item label="项目名称">
|
||||
<el-input :model-value="projectName" placeholder="请输入项目ID" disabled />
|
||||
</el-form-item> -->
|
||||
<el-form-item label="合同编号" prop="contractCode">
|
||||
<el-input v-model="form.contractCode" placeholder="请输入合同编号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同类型" prop="contractType">
|
||||
<el-select v-model="form.contractType" placeholder="请选择合同类型">
|
||||
<el-option v-for="item in expenses_contract_type" :key="item.value" :label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="招标计划" prop="tenderId">
|
||||
<!-- <el-input v-model="form.tenderId" placeholder="请输入招标Id" /> -->
|
||||
<el-input v-model="form.name" placeholder="请选择招标计划" disabled />
|
||||
<el-button type="primary" @click="handleChoose">选择招标</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="供应商" prop="contractSupplier">
|
||||
<el-input v-model="form.contractSupplier" placeholder="请输入供应商" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="分包内容">
|
||||
<!-- <editor v-model="form.contractedContent" :min-height="192" disabled /> -->
|
||||
<el-input v-model="form.contractedContent" style="width: 300px"
|
||||
:autosize="{ minRows: 2, maxRows: 4 }" type="textarea" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同金额" prop="amount">
|
||||
<el-input
|
||||
oninput="value=value.replace(/[^0-9.]/g,'').replace(/\.{2,}/g,'.').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')"
|
||||
v-model="form.amount" placeholder="请输入合同金额" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同编号" prop="contractCode">
|
||||
<el-input v-model="form.contractCode" placeholder="请输入合同编号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同类型" prop="contractType">
|
||||
<el-select v-model="form.contractType" placeholder="请选择合同类型">
|
||||
<el-option v-for="item in expenses_contract_type" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="招标计划" prop="tenderId">
|
||||
<!-- <el-input v-model="form.tenderId" placeholder="请输入招标Id" /> -->
|
||||
<el-input v-model="form.name" placeholder="请选择招标计划" disabled />
|
||||
<el-button type="primary" @click="handleChoose" v-hasPermi="['ctr:expensesContract:tenderList']">选择招标</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="供应商" prop="contractSupplier">
|
||||
<el-input v-model="form.contractSupplier" placeholder="请输入供应商" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="分包内容">
|
||||
<!-- <editor v-model="form.contractedContent" :min-height="192" disabled /> -->
|
||||
<el-input v-model="form.contractedContent" style="width: 300px" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同金额" prop="amount">
|
||||
<el-input
|
||||
oninput="value=value.replace(/[^0-9.]/g,'').replace(/\.{2,}/g,'.').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')"
|
||||
v-model="form.amount"
|
||||
placeholder="请输入合同金额"
|
||||
disabled
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
<el-form-item label="附件">
|
||||
<FileUpload :multiple="true" :fileType="['pdf']" :onUploadSuccess="onUploadSuccess"
|
||||
:ref="fileRef" :defaultFileList="tempFileList" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
<div>
|
||||
<el-button @click="back(true)">上一步</el-button>
|
||||
<el-button type="primary" @click="next">下一步</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="active == 2">
|
||||
<h1>{{ contract_type == "income" ? "收入合同" : "支出合同" }}</h1>
|
||||
<el-form :model="form" :rules="payMentRules" label-width="150" ref="payMentRef">
|
||||
<el-form-item label="支付方式" placeholder="请选择支付方式" prop="payType">
|
||||
<el-select v-model="form.payType">
|
||||
<el-option :value="1" label="月结算">月结算</el-option>
|
||||
<el-option :value="2" label="形象节点">形象节点</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="预付款比例(%)" prop="advancePayRatio">
|
||||
<el-input v-model="form.advancePayRatio" placeholder="请输入预付款比例"
|
||||
oninput="value=value.replace(/[^0-9.]/g,'').replace(/\.{2,}/g,'.').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="尾款比例(%)" prop="balancePayRatio">
|
||||
<el-input v-model="form.balancePayRatio" placeholder="请输入尾款比例"
|
||||
oninput="value=value.replace(/[^0-9.]/g,'').replace(/\.{2,}/g,'.').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="质保金比例(%)" prop="assuranceDepositRatio;">
|
||||
<el-input v-model="form.assuranceDepositRatio" placeholder="请输入质保金比例"
|
||||
oninput="value=value.replace(/[^0-9.]/g,'').replace(/\.{2,}/g,'.').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="付款比例(%)" prop="payRatio">
|
||||
<el-input v-model="form.payRatio" placeholder="请输入付款比例"
|
||||
oninput="value=value.replace(/[^0-9.]/g,'').replace(/\.{2,}/g,'.').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div>
|
||||
<el-button @click="back(false)">上一步</el-button>
|
||||
<el-button type="success" @click="submitForm">提交</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同附件">
|
||||
<FileUpload :multiple="true" :fileType="['pdf']" :onUploadSuccess="onUploadSuccess" :ref="fileRef" :defaultFileList="tempFileList" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
<div>
|
||||
<el-button @click="back(true)">上一步</el-button>
|
||||
<el-button type="primary" @click="next">下一步</el-button>
|
||||
</div>
|
||||
<el-dialog v-model="dialogVisible" title="选择招标计划" width="45%">
|
||||
<el-table :data="planList">
|
||||
<el-table-column type="index" width="50" label="序号" />
|
||||
<el-table-column label="名称" align="center" prop="name" />
|
||||
<el-table-column label="合同额" align="center" prop="contractPrice" />
|
||||
<el-table-column label="分包内容" align="center" prop="content" />
|
||||
<el-table-column label="中标单位" align="center" prop="winningBidder" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" @click="handleChooseData(scope.row)">选择</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="dialogVisible = false">
|
||||
关闭
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<template v-else-if="active == 2">
|
||||
<h1>{{ contract_type == 'income' ? '收入合同' : '支出合同' }}</h1>
|
||||
<el-form :model="form" :rules="payMentRules" label-width="150" ref="payMentRef">
|
||||
<el-form-item label="支付方式" placeholder="请选择支付方式" prop="payType">
|
||||
<el-select v-model="form.payType">
|
||||
<el-option :value="1" label="月结算">月结算</el-option>
|
||||
<el-option :value="2" label="形象节点">形象节点</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="预付款比例(%)" prop="advancePayRatio">
|
||||
<el-input-number v-model="form.advancePayRatio" :max="100" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="尾款比例(%)" prop="balancePayRatio">
|
||||
<el-input-number v-model="form.balancePayRatio" :max="100" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="质保金比例(%)" prop="assuranceDepositRatio">
|
||||
<el-input-number v-model="form.assuranceDepositRatio" :max="100" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="付款比例(%)" prop="payRatio">
|
||||
<el-input-number v-model="payRatioComputed" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div>
|
||||
<el-button @click="back(false)">上一步</el-button>
|
||||
<el-button type="success" @click="submitForm">提交</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</div>
|
||||
<el-dialog v-model="dialogVisible" title="选择招标计划" width="45%">
|
||||
<el-table :data="planList">
|
||||
<el-table-column type="index" width="50" label="序号" />
|
||||
<el-table-column label="名称" align="center" prop="name" />
|
||||
<el-table-column label="合同额" align="center" prop="contractPrice" />
|
||||
<el-table-column label="分包内容" align="center" prop="content" />
|
||||
<el-table-column label="中标单位" align="center" prop="winningBidder" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" @click="handleChooseData(scope.row)">选择</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="dialogVisible = false"> 关闭 </el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import FileUpload from '@/components/FileUpload';
|
||||
import { listExpensesContract, getExpensesContract, delExpensesContract, addExpensesContract, updateExpensesContract, getTenderPlan } from '@/api/ctr/expensesContract';
|
||||
import { listIncomeContract, getIncomeContract, delIncomeContract, addIncomeContract, updateIncomeContract } from '@/api/ctr/incomeContract';
|
||||
import { addExpensesContract, getTenderPlan } from '@/api/ctr/expensesContract';
|
||||
import { addIncomeContract, getInfoByProjectId } from '@/api/ctr/incomeContract';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
const active = ref(0);
|
||||
const contract_type = ref("")
|
||||
const form = ref({ payType: 1 })
|
||||
const fileList = ref([])
|
||||
const tempFileList = ref([])
|
||||
const contract_type = ref('');
|
||||
const form = ref({ payType: 1 });
|
||||
const fileList = ref([]);
|
||||
const tempFileList = ref([]);
|
||||
const { proxy } = getCurrentInstance();
|
||||
const userStore = useUserStore();
|
||||
const planList = ref([]);
|
||||
const dialogVisible = ref(false);
|
||||
|
||||
const { expenses_contract_type, income_contract_type } = toRefs(
|
||||
proxy?.useDict('income_contract_type', 'expenses_contract_type')
|
||||
);
|
||||
const { expenses_contract_type, income_contract_type } = toRefs(proxy?.useDict('income_contract_type', 'expenses_contract_type'));
|
||||
const fileRef = ref(null);
|
||||
const incomeContractFormRef = ref(null);
|
||||
const expensesContractFormRef = ref(null);
|
||||
const payMentRef = ref(null);
|
||||
const incomeContractFormRules = {
|
||||
contractCode: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
|
||||
contractType: [{ required: true, message: '请选择合同类型', trigger: 'change' }],
|
||||
contractOwner: [{ required: true, message: '请输入业主单位', trigger: 'blur' }],
|
||||
amount: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
|
||||
remark: [{ required: false, message: '请输入备注', trigger: 'blur' }],
|
||||
contractCode: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
|
||||
contractType: [{ required: true, message: '请选择合同类型', trigger: 'change' }],
|
||||
contractOwner: [{ required: true, message: '请输入业主单位', trigger: 'blur' }],
|
||||
amount: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
|
||||
remark: [{ required: false, message: '请输入备注', trigger: 'blur' }]
|
||||
};
|
||||
const expensesContractFormRules = {
|
||||
contractCode: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
|
||||
contractType: [{ required: true, message: '请选择合同类型', trigger: 'change' }],
|
||||
contractCode: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
|
||||
contractType: [{ required: true, message: '请选择合同类型', trigger: 'change' }],
|
||||
|
||||
contractSupplier: [{ required: true, message: '请输入供应商', trigger: 'blur' }],
|
||||
amount: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
|
||||
tenderId: [{ required: true, message: '请选择招标计划', trigger: 'blur' }],
|
||||
contractSupplier: [{ required: true, message: '请输入供应商', trigger: 'blur' }],
|
||||
amount: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
|
||||
tenderId: [{ required: true, message: '请选择招标计划', trigger: 'blur' }],
|
||||
|
||||
remark: [{ required: false, message: '请输入备注', trigger: 'blur' }],
|
||||
remark: [{ required: false, message: '请输入备注', trigger: 'blur' }]
|
||||
};
|
||||
const payMentRules = {
|
||||
payType: [{ required: true, message: '请选择支付方式', trigger: 'change' }],
|
||||
advancePayRatio: [{ required: true, message: '请输入预付款比例', trigger: 'blur' }],
|
||||
balancePayRatio: [{ required: true, message: '请输入尾款比例', trigger: 'blur' }],
|
||||
assuranceDepositRatio: [{ required: true, message: '请输入质保金比例', trigger: 'blur' }],
|
||||
payRatio: [{ required: true, message: '请输入付款比例', trigger: 'blur' }],
|
||||
payType: [{ required: true, message: '请选择支付方式', trigger: 'change' }],
|
||||
advancePayRatio: [{ required: true, message: '请输入预付款比例', trigger: 'blur' }],
|
||||
balancePayRatio: [{ required: true, message: '请输入尾款比例', trigger: 'blur' }],
|
||||
assuranceDepositRatio: [{ required: true, message: '请输入质保金比例', trigger: 'blur' }]
|
||||
};
|
||||
|
||||
const project = computed(() => {
|
||||
console.log(111);
|
||||
console.log(111);
|
||||
|
||||
return JSON.parse(localStorage.getItem("selectedProject"))
|
||||
return JSON.parse(localStorage.getItem('selectedProject'));
|
||||
});
|
||||
|
||||
const payRatioComputed = computed({
|
||||
get: () => {
|
||||
const { advancePayRatio = 0, balancePayRatio = 0, assuranceDepositRatio = 0 } = form.value;
|
||||
const total = 100 - (advancePayRatio + balancePayRatio + assuranceDepositRatio);
|
||||
// form.value.payRatio = total;
|
||||
return total;
|
||||
},
|
||||
// 只读
|
||||
set: () => {}
|
||||
});
|
||||
const checkContractType = (type) => {
|
||||
contract_type.value = type;
|
||||
form.value.contract_type = type;
|
||||
active.value = 1;
|
||||
form.value.step = active.value;
|
||||
contract_type.value = type;
|
||||
form.value.contract_type = type;
|
||||
active.value = 1;
|
||||
form.value.step = active.value;
|
||||
};
|
||||
const onUploadSuccess = (data) => {
|
||||
fileList.value = data
|
||||
}
|
||||
fileList.value = data;
|
||||
};
|
||||
const back = async (reset) => {
|
||||
console.log(active.value);
|
||||
console.log(active.value);
|
||||
|
||||
if (reset) {
|
||||
await ElMessageBox.confirm('返回上一步将清空目前填写的内容,确定返回?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
resetForm();
|
||||
active.value--;
|
||||
}).catch(() => {
|
||||
return;
|
||||
});
|
||||
} else {
|
||||
if (reset) {
|
||||
await ElMessageBox.confirm('返回上一步将清空目前填写的内容,确定返回?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
resetForm();
|
||||
active.value--;
|
||||
}
|
||||
console.log(active.value);
|
||||
|
||||
form.value.step = active.value;
|
||||
})
|
||||
.catch(() => {
|
||||
return;
|
||||
});
|
||||
} else {
|
||||
active.value--;
|
||||
}
|
||||
console.log(active.value);
|
||||
|
||||
form.value.step = active.value;
|
||||
};
|
||||
const next = async () => {
|
||||
if (contract_type.value === 'income') {
|
||||
await incomeContractFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
active.value++;
|
||||
} else {
|
||||
ElMessage.error('请填写完整的收入合同信息');
|
||||
}
|
||||
});
|
||||
} else if (contract_type.value === 'expenses') {
|
||||
await expensesContractFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
active.value++;
|
||||
} else {
|
||||
ElMessage.error('请填写完整的支出合同信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
console.log(active.value);
|
||||
if (contract_type.value === 'income') {
|
||||
await incomeContractFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
active.value++;
|
||||
} else {
|
||||
ElMessage.error('请填写完整的收入合同信息');
|
||||
}
|
||||
});
|
||||
} else if (contract_type.value === 'expenses') {
|
||||
await expensesContractFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
active.value++;
|
||||
} else {
|
||||
ElMessage.error('请填写完整的支出合同信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
console.log(active.value);
|
||||
|
||||
form.value.step = active.value;
|
||||
form.value.step = active.value;
|
||||
};
|
||||
const resetForm = () => {
|
||||
form.value = {
|
||||
payType: 1,
|
||||
contractCode: '',
|
||||
contractType: '',
|
||||
contractOwner: '',
|
||||
contractedContent: '',
|
||||
amount: '',
|
||||
remark: '',
|
||||
advancePayRatio: '',
|
||||
balancePayRatio: '',
|
||||
assuranceDepositRatio: '',
|
||||
payRatio: ''
|
||||
};
|
||||
fileList.value = [];
|
||||
tempFileList.value = [];
|
||||
contract_type.value = '';
|
||||
setTimeout(() => {
|
||||
localStorage.removeItem("tempContractForm");
|
||||
}, 0);
|
||||
form.value = {
|
||||
payType: 1,
|
||||
contractCode: '',
|
||||
contractType: '',
|
||||
contractOwner: '',
|
||||
contractedContent: '',
|
||||
amount: '',
|
||||
remark: '',
|
||||
advancePayRatio: '',
|
||||
balancePayRatio: '',
|
||||
assuranceDepositRatio: '',
|
||||
payRatio: ''
|
||||
};
|
||||
fileList.value = [];
|
||||
tempFileList.value = [];
|
||||
contract_type.value = '';
|
||||
setTimeout(() => {
|
||||
localStorage.removeItem('tempContractForm');
|
||||
}, 0);
|
||||
};
|
||||
|
||||
const submitForm = async () => {
|
||||
console.log(payMentRef.value);
|
||||
|
||||
await payMentRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
// 提交付款信息逻辑
|
||||
console.log('提交付款信息', form.value, fileList.value);
|
||||
// 这里可以调用API提交数据
|
||||
form.value.projectId = project.value.id;
|
||||
form.value.fileList = fileList.value.map((data) => {
|
||||
return {
|
||||
...data,
|
||||
fileName: data.name,
|
||||
fileUrl: data.url,
|
||||
}
|
||||
})
|
||||
if (contract_type.value === 'income') {
|
||||
await addIncomeContract({ ...form.value });
|
||||
} else if (contract_type.value === 'expenses') {
|
||||
await addExpensesContract({ ...form.value });
|
||||
}
|
||||
resetForm();
|
||||
ElMessage.success('合同提交成功');
|
||||
} else {
|
||||
ElMessage.error('请填写完整的付款信息');
|
||||
}
|
||||
});
|
||||
// if (contract_type.value === 'income') {
|
||||
// const incomeContractFormRef = ref(null);
|
||||
// await incomeContractFormRef.value.validate(async (valid) => {
|
||||
// if (valid) {
|
||||
// // 提交收入合同逻辑
|
||||
// console.log('提交收入合同', form.value, fileList.value);
|
||||
// // 这里可以调用API提交数据
|
||||
// resetForm();
|
||||
// ElMessage.success('收入合同提交成功');
|
||||
// } else {
|
||||
// ElMessage.error('请填写完整的收入合同信息');
|
||||
// }
|
||||
// });
|
||||
// } else if (contract_type.value === 'expenses') {
|
||||
// const expensesContractFormRef = ref(null);
|
||||
// await expensesContractFormRef.value.validate(async (valid) => {
|
||||
// if (valid) {
|
||||
// // 提交支出合同逻辑
|
||||
// console.log('提交支出合同', form.value, fileList.value);
|
||||
// // 这里可以调用API提交数据
|
||||
// resetForm();
|
||||
// ElMessage.success('支出合同提交成功');
|
||||
// } else {
|
||||
// ElMessage.error('请填写完整的支出合同信息');
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
}
|
||||
const handleChoose = async () => {
|
||||
if (!form.value.contractType) {
|
||||
ElMessage.error('请先选择合同类型');
|
||||
await payMentRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
if (payRatioComputed.value < 0) {
|
||||
ElMessage.error('四项付款比例之和必须等于100%');
|
||||
return;
|
||||
}
|
||||
const formData = {
|
||||
projectId: userStore.selectedProject.id,
|
||||
dictName: form.value.contractType,
|
||||
status: 1,
|
||||
}
|
||||
const { data } = await getTenderPlan(formData)
|
||||
if (data.length === 0) {
|
||||
ElMessage.warning('当前没有招标计划,请先创建招标计划');
|
||||
return;
|
||||
}
|
||||
planList.value = data
|
||||
dialogVisible.value = true;
|
||||
}
|
||||
form.value.payRatio = payRatioComputed.value;
|
||||
|
||||
}
|
||||
const handleChooseData = (row) => {
|
||||
form.value.tenderId = row.id;
|
||||
form.value.name = row.name;
|
||||
form.value.contractPrice = row.contractPrice;
|
||||
form.value.content = row.content;
|
||||
form.value.winningBidder = row.winningBidder;
|
||||
dialogVisible.value = false;
|
||||
// 提交付款信息逻辑
|
||||
console.log('提交付款信息', form.value, fileList.value);
|
||||
// 这里可以调用API提交数据
|
||||
form.value.projectId = project.value.id;
|
||||
form.value.fileList = fileList.value.map((data) => {
|
||||
return {
|
||||
...data,
|
||||
fileName: data.name,
|
||||
fileUrl: data.url
|
||||
};
|
||||
});
|
||||
if (contract_type.value === 'income') {
|
||||
await addIncomeContract({ ...form.value });
|
||||
} else if (contract_type.value === 'expenses') {
|
||||
await addExpensesContract({ ...form.value });
|
||||
}
|
||||
resetForm();
|
||||
ElMessage.success('合同提交成功');
|
||||
active.value = 0; // 重置步骤
|
||||
if (contract_type.value === 'income') {
|
||||
proxy.$router.push('/ctr/incomeContract');
|
||||
} else {
|
||||
proxy.$router.push('/ctr/expensesContract');
|
||||
}
|
||||
} else {
|
||||
ElMessage.error('请填写完整的付款信息');
|
||||
}
|
||||
});
|
||||
// if (contract_type.value === 'income') {
|
||||
// const incomeContractFormRef = ref(null);
|
||||
// await incomeContractFormRef.value.validate(async (valid) => {
|
||||
// if (valid) {
|
||||
// // 提交收入合同逻辑
|
||||
// console.log('提交收入合同', form.value, fileList.value);
|
||||
// // 这里可以调用API提交数据
|
||||
// resetForm();
|
||||
// ElMessage.success('收入合同提交成功');
|
||||
// } else {
|
||||
// ElMessage.error('请填写完整的收入合同信息');
|
||||
// }
|
||||
// });
|
||||
// } else if (contract_type.value === 'expenses') {
|
||||
// const expensesContractFormRef = ref(null);
|
||||
// await expensesContractFormRef.value.validate(async (valid) => {
|
||||
// if (valid) {
|
||||
// // 提交支出合同逻辑
|
||||
// console.log('提交支出合同', form.value, fileList.value);
|
||||
// // 这里可以调用API提交数据
|
||||
// resetForm();
|
||||
// ElMessage.success('支出合同提交成功');
|
||||
// } else {
|
||||
// ElMessage.error('请填写完整的支出合同信息');
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
};
|
||||
const handleChoose = async () => {
|
||||
if (!form.value.contractType) {
|
||||
ElMessage.error('请先选择合同类型');
|
||||
return;
|
||||
}
|
||||
const formData = {
|
||||
projectId: userStore.selectedProject.id,
|
||||
dictName: form.value.contractType,
|
||||
status: 1
|
||||
};
|
||||
const { data } = await getTenderPlan(formData);
|
||||
if (data.length === 0) {
|
||||
ElMessage.warning('当前没有招标计划,请先创建招标计划');
|
||||
return;
|
||||
}
|
||||
planList.value = data;
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
const handleChooseData = (row) => {
|
||||
form.value.tenderId = row.id;
|
||||
form.value.name = row.name;
|
||||
// form.value.contractPrice = row.contractPrice;
|
||||
form.value.content = row.content;
|
||||
form.value.contractSupplier = row.winningBidder;
|
||||
form.value.amount = row.contractPrice;
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
watch(
|
||||
form,
|
||||
(val) => {
|
||||
localStorage.setItem('tempContractForm', JSON.stringify({ ...val, fileList: fileList.value }));
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
watch(
|
||||
fileList,
|
||||
(val) => {
|
||||
localStorage.setItem('tempContractForm', JSON.stringify({ ...form.value, fileList: val }));
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
// 获取投标列表
|
||||
const getInfoByProjectIdList = async () => {
|
||||
const res = await getInfoByProjectId({ projectId: userStore.selectedProject.id });
|
||||
console.log(res);
|
||||
form.value.contractOwner = res.data.planDuration;
|
||||
};
|
||||
watch(form, (val) => {
|
||||
localStorage.setItem("tempContractForm", JSON.stringify({ ...val, fileList: fileList.value }));
|
||||
}, { deep: true });
|
||||
watch(fileList, (val) => {
|
||||
localStorage.setItem("tempContractForm", JSON.stringify({ ...form.value, fileList: val }));
|
||||
}, { deep: true });
|
||||
onMounted(() => {
|
||||
const tempForm = localStorage.getItem("tempContractForm");
|
||||
if (tempForm) {
|
||||
ElMessageBox.confirm('检测到有未完成的合同录入,是否继续?', '提示', {
|
||||
confirmButtonText: '继续',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
const t = JSON.parse(tempForm);
|
||||
const { fileList: files, ...rest } = JSON.parse(tempForm);
|
||||
form.value = rest;
|
||||
fileList.value = files || [];
|
||||
tempFileList.value = files || [];
|
||||
contract_type.value = form.value.contract_type;
|
||||
active.value = form.value.step || 0;
|
||||
getInfoByProjectIdList();
|
||||
|
||||
}).catch(() => {
|
||||
localStorage.removeItem("tempContractForm");
|
||||
});
|
||||
|
||||
}
|
||||
const tempForm = localStorage.getItem('tempContractForm');
|
||||
if (tempForm) {
|
||||
ElMessageBox.confirm('检测到有未完成的合同录入,是否继续?', '提示', {
|
||||
confirmButtonText: '继续',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
const t = JSON.parse(tempForm);
|
||||
const { fileList: files, ...rest } = JSON.parse(tempForm);
|
||||
form.value = rest;
|
||||
fileList.value = files || [];
|
||||
tempFileList.value = files || [];
|
||||
contract_type.value = form.value.contract_type;
|
||||
active.value = form.value.step || 0;
|
||||
})
|
||||
.catch(() => {
|
||||
localStorage.removeItem('tempContractForm');
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.container {
|
||||
padding: 20px;
|
||||
padding: 20px;
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 30px;
|
||||
flex-direction: column;
|
||||
}
|
||||
.content {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 30px;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
234
src/views/ctr/update/index.vue
Normal file
@ -0,0 +1,234 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<el-steps style="max-width: 100%" :active="active" finish-status="success" align-center>
|
||||
<el-step title="选择合同类型" />
|
||||
<el-step title="修改合同内容" />
|
||||
<el-step title="修改收款方式" />
|
||||
</el-steps>
|
||||
<div class="content">
|
||||
<template v-if="active == 1">
|
||||
<h1>修改收入合同</h1>
|
||||
<el-form ref="incomeContractFormRef" :model="form" :rules="incomeContractFormRules" label-width="80px">
|
||||
<el-form-item label="合同编号" prop="contractCode">
|
||||
<el-input v-model="form.contractCode" placeholder="请输入合同编号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同类型" prop="contractType">
|
||||
<el-select v-model="form.contractType" placeholder="请选择合同类型">
|
||||
<el-option v-for="item in income_contract_type" :key="item.value" :label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="业主单位" prop="contractOwner">
|
||||
<el-input v-model="form.contractOwner" placeholder="请输入业主单位" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="承包内容" v-if="contract_type !== 'income'">
|
||||
<editor v-model="form.contractedContent" :min-height="192" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同内容" v-else>
|
||||
<editor v-model="form.contractedContent" :min-height="192" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同金额" prop="amount">
|
||||
<el-input v-model="form.amount" placeholder="请输入合同金额"
|
||||
oninput="value=value.replace(/[^0-9.]/g,'').replace(/\.{2,}/g,'.').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
<el-form-item label="附件">
|
||||
<FileUpload :multiple="true" :fileType="['pdf']" :onUploadSuccess="onUploadSuccess"
|
||||
:ref="fileRef" :defaultFileList="tempFileList" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div>
|
||||
<el-button type="primary" @click="next">下一步</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="active == 2">
|
||||
<h1>修改收入合同</h1>
|
||||
<el-form :model="form" :rules="payMentRules" label-width="150" ref="payMentRef">
|
||||
<el-form-item label="支付方式" placeholder="请选择支付方式" prop="payType">
|
||||
<el-select v-model="form.payType">
|
||||
<el-option :value="1" label="月结算">月结算</el-option>
|
||||
<el-option :value="2" label="形象节点">形象节点</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="预付款比例(%)" prop="advancePayRatio">
|
||||
<el-input-number v-model="form.advancePayRatio" :max="100" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="尾款比例(%)" prop="balancePayRatio">
|
||||
<el-input-number v-model="form.balancePayRatio" :max="100" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="质保金比例(%)" prop="assuranceDepositRatio">
|
||||
<el-input-number v-model="form.assuranceDepositRatio" :max="100" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="付款比例(%)" prop="payRatio">
|
||||
<el-input-number v-model="payRatioComputed" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div>
|
||||
<el-button @click="back(false)">上一步</el-button>
|
||||
<el-button type="success" @click="submitForm">提交</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import FileUpload from '@/components/FileUpload';
|
||||
import { getTenderPlan } from '@/api/ctr/expensesContract';
|
||||
import { updateIncomeContract } from '@/api/ctr/incomeContract';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
const active = ref(1);
|
||||
const contract_type = ref('income');
|
||||
const form = ref({ payType: 1 });
|
||||
const fileList = ref([]);
|
||||
const tempFileList = ref([]);
|
||||
const { proxy } = getCurrentInstance();
|
||||
const userStore = useUserStore();
|
||||
const planList = ref([]);
|
||||
const dialogVisible = ref(false);
|
||||
const { income_contract_type } = toRefs(proxy?.useDict('income_contract_type', 'expenses_contract_type'));
|
||||
const fileRef = ref(null);
|
||||
const incomeContractFormRef = ref(null);
|
||||
const expensesContractFormRef = ref(null);
|
||||
const payMentRef = ref(null);
|
||||
const incomeContractFormRules = {
|
||||
contractCode: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
|
||||
contractType: [{ required: true, message: '请选择合同类型', trigger: 'change' }],
|
||||
contractOwner: [{ required: true, message: '请输入业主单位', trigger: 'blur' }],
|
||||
amount: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
|
||||
remark: [{ required: false, message: '请输入备注', trigger: 'blur' }]
|
||||
};
|
||||
const expensesContractFormRules = {
|
||||
contractCode: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
|
||||
contractType: [{ required: true, message: '请选择合同类型', trigger: 'change' }],
|
||||
|
||||
contractSupplier: [{ required: true, message: '请输入供应商', trigger: 'blur' }],
|
||||
amount: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
|
||||
tenderId: [{ required: true, message: '请选择招标计划', trigger: 'blur' }],
|
||||
|
||||
remark: [{ required: false, message: '请输入备注', trigger: 'blur' }]
|
||||
};
|
||||
const payMentRules = {
|
||||
payType: [{ required: true, message: '请选择支付方式', trigger: 'change' }],
|
||||
advancePayRatio: [{ required: true, message: '请输入预付款比例', trigger: 'blur' }],
|
||||
balancePayRatio: [{ required: true, message: '请输入尾款比例', trigger: 'blur' }],
|
||||
assuranceDepositRatio: [{ required: true, message: '请输入质保金比例', trigger: 'blur' }]
|
||||
};
|
||||
|
||||
const project = computed(() => {
|
||||
return JSON.parse(localStorage.getItem('selectedProject'));
|
||||
});
|
||||
|
||||
const payRatioComputed = computed({
|
||||
get: () => {
|
||||
const { advancePayRatio = 0, balancePayRatio = 0, assuranceDepositRatio = 0 } = form.value;
|
||||
const total = 100 - (advancePayRatio + balancePayRatio + assuranceDepositRatio);
|
||||
// form.value.payRatio = total;
|
||||
return total;
|
||||
},
|
||||
// 只读
|
||||
set: () => { }
|
||||
});
|
||||
|
||||
const onUploadSuccess = (data) => {
|
||||
fileList.value = data;
|
||||
};
|
||||
|
||||
const next = async () => {
|
||||
if (contract_type.value === 'income') {
|
||||
await incomeContractFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
active.value++;
|
||||
} else {
|
||||
ElMessage.error('请填写完整的收入合同信息');
|
||||
}
|
||||
});
|
||||
} else if (contract_type.value === 'expenses') {
|
||||
await expensesContractFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
active.value++;
|
||||
} else {
|
||||
ElMessage.error('请填写完整的支出合同信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
console.log(active.value);
|
||||
|
||||
form.value.step = active.value;
|
||||
};
|
||||
const submitForm = async () => {
|
||||
await payMentRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
if (payRatioComputed.value < 0) {
|
||||
ElMessage.error('四项付款比例之和必须等于100%');
|
||||
return;
|
||||
}
|
||||
form.value.payRatio = payRatioComputed.value;
|
||||
|
||||
// 提交付款信息逻辑
|
||||
console.log('提交付款信息', form.value, fileList.value);
|
||||
// 这里可以调用API提交数据
|
||||
form.value.projectId = project.value.id;
|
||||
form.value.fileList = fileList.value.map((data) => {
|
||||
return {
|
||||
...data,
|
||||
fileName: data.name,
|
||||
fileUrl: data.url
|
||||
};
|
||||
});
|
||||
if (contract_type.value === 'income') {
|
||||
await updateIncomeContract({ ...form.value });
|
||||
}
|
||||
ElMessage.success('合同修改成功');
|
||||
} else {
|
||||
ElMessage.error('请填写完整的付款信息');
|
||||
}
|
||||
});
|
||||
};
|
||||
const handleChoose = async () => {
|
||||
if (!form.value.contractType) {
|
||||
ElMessage.error('请先选择合同类型');
|
||||
return;
|
||||
}
|
||||
const formData = {
|
||||
projectId: userStore.selectedProject.id,
|
||||
dictName: form.value.contractType,
|
||||
status: 1
|
||||
};
|
||||
const { data } = await getTenderPlan(formData);
|
||||
if (data.length === 0) {
|
||||
ElMessage.warning('当前没有招标计划,请先创建招标计划');
|
||||
return;
|
||||
}
|
||||
planList.value = data;
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
const id = route.query.id;
|
||||
if (id) {
|
||||
const { data } = await getIncomeContract(id);
|
||||
form.value.id = data.id;
|
||||
form.value.contractOwner = data.contractOwner
|
||||
} else {
|
||||
router.push('/ctr/incomeContract');
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.container {
|
||||
padding: 20px;
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 30px;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
128
src/views/demo/components/1.html
Normal file
@ -0,0 +1,128 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!-- 引入图标(这里用的是阿里图标库示例,实际可替换成自己的图标资源) -->
|
||||
<link rel="stylesheet" href="https://at.alicdn.com/t/c/font_4245527_xxxxxx.css">
|
||||
<!-- <link rel="stylesheet" href="style.css"> -->
|
||||
<style>
|
||||
/* 初始化样式 */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
background: #eef5ff;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
/* 时间轴容器 */
|
||||
.weather-timeline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
overflow-x: auto;
|
||||
/* 适配小屏幕横向滚动 */
|
||||
}
|
||||
|
||||
/* 每个时间项 */
|
||||
.time-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0 12px;
|
||||
min-width: 80px;
|
||||
/* 保证 item 最小宽度 */
|
||||
}
|
||||
|
||||
/* 当前时间项特殊样式 */
|
||||
.time-item.current {
|
||||
background: #e3f0ff;
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
transform: scale(1.1);
|
||||
/* 稍微放大突出 */
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* 时间文本 */
|
||||
.time {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
/* 温度文本 */
|
||||
.temp {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* 图标样式(基于阿里图标库,可替换成自己的图标字体或图片) */
|
||||
.iconfont {
|
||||
font-size: 24px;
|
||||
color: #f9b115;
|
||||
/* 太阳/主色调 */
|
||||
}
|
||||
|
||||
.icon-rain {
|
||||
color: #9ec8f2;
|
||||
/* 雨/蓝色系 */
|
||||
}
|
||||
|
||||
.icon-cloud-moon {
|
||||
color: #c9d6e5;
|
||||
/* 多云 moon/浅灰蓝 */
|
||||
}
|
||||
</style>
|
||||
<title>天气时间轴</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="weather-timeline">
|
||||
<div class="time-item">
|
||||
<div class="time">16:00</div>
|
||||
<div class="temp">30°C</div>
|
||||
<i class="iconfont icon-sun"></i> <!-- 太阳图标 -->
|
||||
</div>
|
||||
<div class="time-item">
|
||||
<div class="time">17:00</div>
|
||||
<div class="temp">29°C</div>
|
||||
<i class="iconfont icon-sun"></i>
|
||||
</div>
|
||||
<div class="time-item">
|
||||
<div class="time">18:00</div>
|
||||
<div class="temp">25°C</div>
|
||||
<i class="iconfont icon-rain"></i> <!-- 小雨图标 -->
|
||||
</div>
|
||||
<div class="time-item current">
|
||||
<div class="time">现在</div>
|
||||
<div class="temp">25°C</div>
|
||||
<i class="iconfont icon-rain"></i>
|
||||
</div>
|
||||
<div class="time-item">
|
||||
<div class="time">20:00</div>
|
||||
<div class="temp">25°C</div>
|
||||
<i class="iconfont icon-cloud-moon"></i> <!-- 多云 moon 图标 -->
|
||||
</div>
|
||||
<div class="time-item">
|
||||
<div class="time">21:00</div>
|
||||
<div class="temp">20°C</div>
|
||||
<i class="iconfont icon-cloud-moon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
311
src/views/demo/components/ChartBox.vue
Normal file
@ -0,0 +1,311 @@
|
||||
<template>
|
||||
<div class="chart-container">
|
||||
<!-- 图表标题和时间范围选择器 -->
|
||||
<div class="chart-header">
|
||||
<h2>功率与效率趋势</h2>
|
||||
<div class="chart-actions">
|
||||
<button @click="timeRange = 'day'" :class="{ active: timeRange === 'day' }">今日</button>
|
||||
<button @click="timeRange = 'week'" :class="{ active: timeRange === 'week' }">本周</button>
|
||||
<button @click="timeRange = 'month'" :class="{ active: timeRange === 'month' }">本月</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 图表内容区域 -->
|
||||
<div ref="chartRef" class="chart-content"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
// 图表DOM引用
|
||||
const chartRef = ref(null);
|
||||
// 时间范围状态
|
||||
const timeRange = ref('day');
|
||||
// 图表实例
|
||||
let chartInstance = null;
|
||||
|
||||
// 定义颜色常量
|
||||
const POWER_COLOR = 'rgba(42, 130, 228, 1)';
|
||||
const EFFICIENCY_COLOR = 'rgba(67, 207, 124, 1)';
|
||||
|
||||
// 生成指定范围内的随机数(用于模拟数据)
|
||||
const getRandomValue = (min, max) => {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
};
|
||||
|
||||
// 生成指定范围内的随机浮点数(用于效率数据)
|
||||
const getRandomFloat = (min, max, decimalPlaces = 1) => {
|
||||
const value = Math.random() * (max - min) + min;
|
||||
return parseFloat(value.toFixed(decimalPlaces));
|
||||
};
|
||||
|
||||
// 获取当前月份的天数
|
||||
const getDaysInCurrentMonth = () => {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = now.getMonth() + 1; // 月份从0开始,所以+1
|
||||
return new Date(year, month, 0).getDate();
|
||||
};
|
||||
|
||||
// 根据时间范围返回对应的数据
|
||||
const getChartData = () => {
|
||||
if (timeRange.value === 'day') {
|
||||
return {
|
||||
xAxis: ['00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00'],
|
||||
powerData: [320, 380, 350, 420, 580, 630, 550, 480],
|
||||
efficiencyData: [85.2, 86.5, 87.1, 88.3, 89.5, 89.2, 88.7, 88.1]
|
||||
};
|
||||
} else if (timeRange.value === 'week') {
|
||||
return {
|
||||
xAxis: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
|
||||
powerData: [4200, 4800, 5100, 4900, 5300, 3800, 3200],
|
||||
efficiencyData: [86.2, 87.5, 88.1, 87.8, 89.0, 88.5, 87.9]
|
||||
};
|
||||
} else {
|
||||
// 本月数据 - 按天显示
|
||||
const daysInMonth = getDaysInCurrentMonth();
|
||||
const xAxis = [];
|
||||
const powerData = [];
|
||||
const efficiencyData = [];
|
||||
|
||||
// 生成每天的数据
|
||||
for (let i = 1; i <= daysInMonth; i++) {
|
||||
xAxis.push(`${i}日`);
|
||||
// 生成合理范围内的功率数据(10000-25000之间)
|
||||
powerData.push(getRandomValue(10000, 25000));
|
||||
// 生成合理范围内的效率数据(85-90之间,保留1位小数)
|
||||
efficiencyData.push(getRandomFloat(85, 90));
|
||||
}
|
||||
|
||||
return {
|
||||
xAxis,
|
||||
powerData,
|
||||
efficiencyData
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
if (chartRef.value && !chartInstance) {
|
||||
chartInstance = echarts.init(chartRef.value);
|
||||
}
|
||||
|
||||
const data = getChartData();
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { type: 'cross' }
|
||||
},
|
||||
legend: {
|
||||
data: ['总功率(kW)', '平均效率(%)'],
|
||||
top: 0
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: data.xAxis,
|
||||
// 当月天数较多时,优化X轴标签显示
|
||||
axisLabel: {
|
||||
interval: timeRange.value === 'month' ? 'auto' : 0,
|
||||
rotate: timeRange.value === 'month' ? 45 : 0
|
||||
}
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '总功率(kW)',
|
||||
axisLabel: {
|
||||
formatter: '{value}'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '平均效率(%)',
|
||||
min: 80,
|
||||
max: 95,
|
||||
axisLabel: {
|
||||
formatter: '{value}%'
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '总功率(kW)',
|
||||
type: 'line',
|
||||
data: data.powerData,
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 3,
|
||||
color: POWER_COLOR
|
||||
},
|
||||
symbol: 'circle',
|
||||
symbolSize: 8,
|
||||
itemStyle: {
|
||||
color: POWER_COLOR
|
||||
},
|
||||
markPoint: {
|
||||
data: [
|
||||
{ type: 'max', name: '最大值' },
|
||||
{ type: 'min', name: '最小值' }
|
||||
],
|
||||
itemStyle: {
|
||||
color: POWER_COLOR
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '平均效率(%)',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
data: data.efficiencyData,
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 3,
|
||||
type: 'dashed',
|
||||
color: EFFICIENCY_COLOR
|
||||
},
|
||||
symbol: 'diamond',
|
||||
symbolSize: 8,
|
||||
itemStyle: {
|
||||
color: EFFICIENCY_COLOR
|
||||
},
|
||||
markPoint: {
|
||||
data: [
|
||||
{ type: 'max', name: '最大值' },
|
||||
{ type: 'min', name: '最小值' }
|
||||
],
|
||||
itemStyle: {
|
||||
color: EFFICIENCY_COLOR
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
chartInstance.setOption(option);
|
||||
};
|
||||
|
||||
// 响应窗口大小变化
|
||||
const handleResize = () => {
|
||||
if (chartInstance) {
|
||||
chartInstance.resize();
|
||||
}
|
||||
};
|
||||
|
||||
// 生命周期钩子
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
// 清理函数
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose();
|
||||
chartInstance = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// 监听时间范围变化,更新图表
|
||||
watch(timeRange, () => {
|
||||
initChart();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chart-container {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
overflow: hidden;
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.chart-header h2 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.chart-actions button {
|
||||
background: none;
|
||||
border: 1px solid #e0e0e0;
|
||||
padding: 5px 12px;
|
||||
border-radius: 4px;
|
||||
margin-left: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.chart-actions button.active {
|
||||
background-color: #1890ff;
|
||||
color: white;
|
||||
border-color: #1890ff;
|
||||
}
|
||||
|
||||
.chart-content {
|
||||
width: 100%;
|
||||
height: calc(100% - 54px);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.chart-container {
|
||||
height: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.chart-container {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.chart-actions {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.chart-actions button {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.chart-actions button:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.model {
|
||||
padding: 20px;
|
||||
background-color: rgba(242, 248, 252, 1);
|
||||
}
|
||||
</style>
|
||||
30
src/views/demo/components/TitleComponent.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<el-row>
|
||||
<el-col>
|
||||
<div style="color: rgba(0, 30, 59, 1);;font-family: 'Alibaba-PuHuiTi-Bold';margin: 10px 0 0 0;"
|
||||
:style="{ fontSize: fontLevelMap[props.fontLevel] }">
|
||||
{{ props.title }}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<p style="color: rgba(154, 154, 154, 1);font-size: 14px;">
|
||||
{{ props.subtitle }}
|
||||
</p>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
</template>
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
subtitle: String,
|
||||
fontLevel: {
|
||||
type: Number,
|
||||
default: 1
|
||||
}
|
||||
})
|
||||
const fontLevelMap = {
|
||||
1: "24px",
|
||||
2: "18px"
|
||||
}
|
||||
</script>
|
||||
210
src/views/demo/components/gaojing.vue
Normal file
@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<el-card shadow="never" style="border-radius: 10px;">
|
||||
<div style="margin-bottom: 20px;display: flex;align-items: center;justify-content: right;">
|
||||
<span style="margin-right: 5px;color: rgba(113, 128, 150, 1);font-size: 14px;">
|
||||
查看全部告警信息
|
||||
</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="8" height="8"
|
||||
viewBox="0 0 8 8" fill="none">
|
||||
<path
|
||||
d="M5.94575 4.15722C5.94975 4.14947 5.95624 4.14298 5.95975 4.13497C6.0285 3.99197 6.00599 3.81697 5.88425 3.70197L3.1245 1.09172C2.97399 0.949466 2.73676 0.956216 2.59425 1.10648C2.45199 1.25698 2.4585 1.49422 2.60901 1.63673L5.08526 3.97922L2.61875 6.35647C2.46975 6.50021 2.46525 6.73746 2.60901 6.88672C2.6825 6.96321 2.78076 7.00148 2.87901 7.00148C2.97276 7.00148 3.06651 6.96648 3.13926 6.89648L5.87401 4.26073C5.87927 4.25547 5.88125 4.24823 5.88651 4.24274C5.89052 4.23899 5.89476 4.23623 5.89875 4.23224C5.92 4.20997 5.93124 4.18272 5.94575 4.15722Z"
|
||||
fill="#718096">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="notice">
|
||||
<div class="item">
|
||||
<div class="icon">
|
||||
<img src="/assets/demo/zgjxx.png" alt="">
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>总告警信息</p>
|
||||
<p style="color: rgba(42, 130, 228, 1);">1,921条</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="icon">
|
||||
<img src="/assets/demo/ycl.png" alt="">
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>已处理</p>
|
||||
<p style="color:rgba(0, 184, 122, 1);">500条</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="icon">
|
||||
<img src="/assets/demo/zzcl.png" alt="">
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>正在处理</p>
|
||||
<p style="color: rgba(255, 141, 26, 1);">200条</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="icon">
|
||||
<img src="/assets/demo/wcl.png" alt="">
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>未处理</p>
|
||||
<p style="color: rgba(227, 39, 39, 1);">1,221</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="list">
|
||||
<div class="item waring">
|
||||
<div class="left">
|
||||
<p class="title">
|
||||
逆变器温度过高
|
||||
</p>
|
||||
<p class="text">INV-2023-003 温度达到52℃,超过阈值48℃</p>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="time">
|
||||
10分钟前
|
||||
</div>
|
||||
<el-text type="warning" size="small">正在处理</el-text>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item danger">
|
||||
<div class="left">
|
||||
<p class="title">
|
||||
通信中断
|
||||
</p>
|
||||
<p class="text">INV-2023-003 与监控系统通信中断</p>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="time">
|
||||
20分钟前
|
||||
</div>
|
||||
<el-text type="primary" size="small">查看详情</el-text>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item danger">
|
||||
<div class="left">
|
||||
<p class="title">
|
||||
通信中断
|
||||
</p>
|
||||
<p class="text">INV-2023-003 与监控系统通信中断</p>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="time">
|
||||
1小时前
|
||||
</div>
|
||||
<el-text type="primary" size="small">查看详情</el-text>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item grey">
|
||||
<div class="left">
|
||||
<p class="title">
|
||||
逆变器温度过高
|
||||
</p>
|
||||
<p class="text">INV-2023-003 温度达到52℃,超过阈值48℃</p>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="time">
|
||||
2小时前
|
||||
</div>
|
||||
<!-- <el-text type="primary" size="small">查看详情</el-text> -->
|
||||
<el-button type="info" size="small" disabled>已处理</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
.notice {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid rgba(32, 32, 32, 0.05);
|
||||
padding-bottom: 20px;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
p {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin-right: 10px;
|
||||
|
||||
img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.content p:nth-child(2) {
|
||||
font-size: 14px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
.item {
|
||||
border-radius: 10px;
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.text {
|
||||
color: rgba(125, 133, 146, 1);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.right {
|
||||
font-size: 12px;
|
||||
color: rgba(125, 133, 146, 1);
|
||||
|
||||
.time {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.waring {
|
||||
background-color: #FFFCE6;
|
||||
border: 1px solid #FFF0E1;
|
||||
|
||||
.title {
|
||||
color: #FFA408;
|
||||
}
|
||||
}
|
||||
|
||||
.danger {
|
||||
background-color: #FFE9E5;
|
||||
border: 1px solid #FFEFEB;
|
||||
|
||||
.title {
|
||||
color: rgba(255, 87, 51, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.grey {
|
||||
background-color: #F3F3F3;
|
||||
border: 1px solid #FCFCFC;
|
||||
|
||||
.right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: rgba(102, 102, 102, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script setup></script>
|
||||
224
src/views/demo/components/qixiang.vue
Normal file
@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<div class="cardItem">
|
||||
<el-card>
|
||||
<div class="tianqi"
|
||||
style="display: flex;flex-direction: column;align-items: center;background-color: #FAFAFA;border-radius: 10px;padding-bottom: 40px;">
|
||||
<div>
|
||||
<img src="/assets/demo/Sunny.png" style="display: block; width: 100px;height: 100px;" alt="">
|
||||
</div>
|
||||
<div style="font-family: 'Alibaba-PuHuiTi-Bold';font-size: 24px;">
|
||||
31℃
|
||||
</div>
|
||||
<div>晴朗</div>
|
||||
<div style="color: rgba(154, 154, 154, 1);font-size: 14px;">
|
||||
紫外线强度:<span>高</span>
|
||||
</div>
|
||||
<div class="tianqi2">
|
||||
<div class="item">
|
||||
<div>
|
||||
<img src="/assets/demo/shidu.png" alt="">
|
||||
</div>
|
||||
<div class="text">相对湿度: <span>45%</span></div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div>
|
||||
<img src="/assets/demo/qiangdu.png" alt="">
|
||||
</div>
|
||||
<div class="text">光照强度: <span>45%</span></div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div>
|
||||
<img src="/assets/demo/fengshu.png" alt="">
|
||||
</div>
|
||||
<div class="text">风速: <span>2.3m/s</span></div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div>
|
||||
<img src="/assets/demo/riluo.png" alt="">
|
||||
</div>
|
||||
<div class="text">日落时间: <span>19.45</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="weather-timeline">
|
||||
<div class="time-box">
|
||||
<div class="time-item">
|
||||
<div class="time">16:00</div>
|
||||
<div class="temp">30°C</div>
|
||||
<div class="img-box">
|
||||
<img src="/assets/demo/sunny_s.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="time-item">
|
||||
<div class="time">17:00</div>
|
||||
<div class="temp">29°C</div>
|
||||
<div class="img-box">
|
||||
<img src="/assets/demo/sunny_s.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="time-item">
|
||||
<div class="child">
|
||||
<div class="time">18:00</div>
|
||||
<div class="temp">25°C</div>
|
||||
<div class="img-box">
|
||||
<img src="/assets/demo/rain.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="time-item show">
|
||||
<div class="time">现在</div>
|
||||
<div class="temp">25°C</div>
|
||||
<div class="img-box">
|
||||
<img src="/assets/demo/rain_show.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="time-item">
|
||||
<div class="time">20:00</div>
|
||||
<div class="temp">25°C</div>
|
||||
<div class="img-box">
|
||||
<img src="/assets/demo/yin.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="time-item">
|
||||
<div class="time">21:00</div>
|
||||
<div class="temp">20°C</div>
|
||||
<div class="img-box">
|
||||
<img src="/assets/demo/yin.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
.cardItem {
|
||||
padding: -20px !important;
|
||||
}
|
||||
|
||||
.tianqi2 {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 50px;
|
||||
|
||||
img {
|
||||
width: 40px;
|
||||
height: 40x;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
|
||||
.text {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.weather-timeline {
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
margin: 15px 0;
|
||||
|
||||
.time {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.img-box {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
// img[src*='Sunny'] {
|
||||
// width: 50px;
|
||||
// height: 50px;
|
||||
// }
|
||||
|
||||
// img[src*='rain'] {
|
||||
// width: 60px;
|
||||
// height: 60px;
|
||||
// }
|
||||
|
||||
|
||||
padding: 15px;
|
||||
background: linear-gradient(to right, #D6E2FF, #DEEBFF);
|
||||
border-radius: 15px;
|
||||
|
||||
.time-box {
|
||||
background: linear-gradient(to right, #447BFF, #67A3FD);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-radius: 10px;
|
||||
padding: 10px 20px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.time-item.show {
|
||||
color: rgba(24, 109, 245, 1);
|
||||
position: relative;
|
||||
// z-index: 888;
|
||||
background-color: #fff;
|
||||
padding: 0 5px;
|
||||
|
||||
}
|
||||
|
||||
.show::after {
|
||||
// color: rgba(24, 109, 245, 1);
|
||||
// position: relative;
|
||||
// z-index: 888;
|
||||
// background-color: #fff;
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 25px;
|
||||
// background-color: red;
|
||||
background-color: #fff;
|
||||
left: 0;
|
||||
border-radius: 0 0 25px 25px;
|
||||
}
|
||||
|
||||
.show::before {
|
||||
// color: rgba(24, 109, 245, 1);
|
||||
// position: relative;
|
||||
// z-index: 888;
|
||||
// background-color: #fff;
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 25px;
|
||||
// background-color: red;
|
||||
background-color: #fff;
|
||||
left: 0;
|
||||
top: -25px;
|
||||
border-radius: 25px 25px 0 0;
|
||||
}
|
||||
|
||||
// .show::after {
|
||||
// content: '';
|
||||
// position: absolute;
|
||||
// height: 155px;
|
||||
// background-color: #fff;
|
||||
// z-index: 999;
|
||||
// width: 100%;
|
||||
// top: -25px;
|
||||
// left: 0;
|
||||
// border-radius: 20px;
|
||||
// }
|
||||
}
|
||||
</style>
|
||||
<script setup>
|
||||
</script>
|
||||
107
src/views/demo/components/status.vue
Normal file
@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<el-card shadow="never" style="border-radius: 10px;">
|
||||
<el-form :inline="true" :model="formInline" label-width="120" style="display: flex; justify-content: center;">
|
||||
<el-form-item label="规则编号">
|
||||
<el-input v-model="formInline.user" placeholder="请输入规则编号" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="formInline.region" placeholder="请输入状态" clearable>
|
||||
<el-option label="Zone one" value="shanghai" />
|
||||
<el-option label="Zone two" value="beijing" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="更新时间">
|
||||
<el-date-picker v-model="formInline.date" type="date" placeholder="请选择时间" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="onSubmit">搜索</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="refresh" type="default" @click="onSubmit">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table v-loading="loading" :data="listData" @selection-change="handleSelectionChange">
|
||||
<!-- <el-table-column type="index" width="50" label="序号" /> -->
|
||||
<el-table-column label="逆变器编号" align="center" prop="id" />
|
||||
<!-- <el-table-column label="合同类型" align="center" prop="contractType">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="income_contract_type" :value="scope.row.contractType" />
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<el-table-column label="输出功率" align="center" prop="shuchu" />
|
||||
<el-table-column label="效率" align="center" prop="xiaolv" />
|
||||
<el-table-column label="温度" align="center" prop="wendu" />
|
||||
<el-table-column label="今日发电量" align="center" prop="fadian" />
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<!-- <el-button link type="primary">详情</el-button>
|
||||
<el-button link type="danger">处理</el-button>
|
||||
<el-button link type="warning">维护记录</el-button> -->
|
||||
<el-tag :type="statusMap[scope.row.status].type">{{ statusMap[scope.row.status].label }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary">详情</el-button>
|
||||
<el-button link type="danger">处理</el-button>
|
||||
<el-button link type="warning">维护记录</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize" @pagination="getList" /> -->
|
||||
<pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList" />
|
||||
</el-card>
|
||||
</template>
|
||||
<script setup>
|
||||
const formInline = ref({})
|
||||
const total = ref(0);
|
||||
const loading = ref(false);
|
||||
const listData = [
|
||||
{ id: "INV-2023-001", shuchu: "12.8kw", xiaolv: "98.2%", wendu: "42℃", fadian: "158.5kWh", status: 1 },
|
||||
{ id: "INV-2023-001", shuchu: "12.8kw", xiaolv: "98.2%", wendu: "42℃", fadian: "158.5kWh", status: 1 },
|
||||
{ id: "INV-2023-001", shuchu: "12.8kw", xiaolv: "98.2%", wendu: "42℃", fadian: "158.5kWh", status: 2 },
|
||||
{ id: "INV-2023-001", shuchu: "12.8kw", xiaolv: "98.2%", wendu: "42℃", fadian: "158.5kWh", status: 2 },
|
||||
{ id: "INV-2023-001", shuchu: "12.8kw", xiaolv: "98.2%", wendu: "42℃", fadian: "158.5kWh", status: 3 },
|
||||
{ id: "INV-2023-001", shuchu: "12.8kw", xiaolv: "98.2%", wendu: "42℃", fadian: "158.5kWh", status: 3 }
|
||||
]
|
||||
const statusMap = {
|
||||
1: {
|
||||
label: "正常运行",
|
||||
type: "success"
|
||||
},
|
||||
2: {
|
||||
label: "异常",
|
||||
type: "danger"
|
||||
},
|
||||
3: {
|
||||
label: "维护中",
|
||||
type: "warning"
|
||||
}
|
||||
}
|
||||
const initFormData = {
|
||||
|
||||
};
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
|
||||
},
|
||||
});
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection) => {
|
||||
ids.value = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
const getList = async () => {
|
||||
// loading.value = true;
|
||||
// const res = await listIncomeContract(queryParams.value);
|
||||
// incomeContractList.value = res.rows;
|
||||
// total.value = res.total;
|
||||
// loading.value = false;
|
||||
};
|
||||
</script>
|
||||
148
src/views/demo/components/zhiban.vue
Normal file
226
src/views/demo/index.vue
Normal file
186
src/views/demo1/components/sbqk.vue
Normal file
@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<el-card>
|
||||
<div class="container">
|
||||
<div class="item">
|
||||
<div class="top">
|
||||
<div class="icon">
|
||||
<img src="/assets/demo/sb1.png" alt="">
|
||||
</div>
|
||||
<div class="content">
|
||||
<p class="t1">运行中</p>
|
||||
<p class="t2">当前状态</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<span class="icon"><svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" width="17.4462890625" height="4.361663818359375"
|
||||
viewBox="0 0 17.4462890625 4.361663818359375" fill="none">
|
||||
<path
|
||||
d="M14.43 2.05L14.43 0.4C14.43 0.32495 14.5049 0.25 14.58 0.25L14.66 0.25L17.14 2.05C17.2151 2.12505 17.2151 2.20495 17.14 2.28L14.66 4.08C14.585 4.15505 14.505 4.08 14.43 4.08L14.43 2.5L0.55 2.5C0.399897 2.6501 0.25 2.4301 0.25 2.28C0.25 2.12988 0.399897 1.98 0.55 1.98L14.43 1.98L14.43 2.05Z"
|
||||
stroke="rgba(67, 207, 124, 1)" stroke-width="0.5" fill="#43CF7C">
|
||||
</path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="t1">平稳运行</span>
|
||||
<span class="t2">(30 days)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="top">
|
||||
<div class="icon">
|
||||
<img src="/assets/demo/sb2.png" alt="">
|
||||
</div>
|
||||
<div class="content">
|
||||
<p class="t1">128小时</p>
|
||||
<p class="t2">运行时长</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<span class="icon"><svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" width="17.4462890625" height="4.361663818359375"
|
||||
viewBox="0 0 17.4462890625 4.361663818359375" fill="none">
|
||||
<path
|
||||
d="M14.43 2.05L14.43 0.4C14.43 0.32495 14.5049 0.25 14.58 0.25L14.66 0.25L17.14 2.05C17.2151 2.12505 17.2151 2.20495 17.14 2.28L14.66 4.08C14.585 4.15505 14.505 4.08 14.43 4.08L14.43 2.5L0.55 2.5C0.399897 2.6501 0.25 2.4301 0.25 2.28C0.25 2.12988 0.399897 1.98 0.55 1.98L14.43 1.98L14.43 2.05Z"
|
||||
stroke="rgba(67, 207, 124, 1)" stroke-width="0.5" fill="#43CF7C">
|
||||
</path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="t1">平稳运行</span>
|
||||
<span class="t2">(30 days)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="top">
|
||||
<div class="icon">
|
||||
<img src="/assets/demo/sb3.png" alt="">
|
||||
</div>
|
||||
<div class="content">
|
||||
<p class="t1">5/8</p>
|
||||
<p class="t2">已完成步骤</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<span class="icon"><svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" width="12.393798828125" height="7.42498779296875"
|
||||
viewBox="0 0 12.393798828125 7.42498779296875" fill="none">
|
||||
<path
|
||||
d="M12.2438 0.225L12.2438 0.150012L12.2438 0.0750058L12.1688 0.0750058C12.1688 0.0750058 12.0937 0.0750058 12.0188 0L8.34376 0C7.96876 0 7.66876 0.300006 7.66876 0.675C7.66876 1.05001 7.96876 1.35 8.34376 1.35L10.2188 1.35L6.61876 4.95L4.81876 3.15C4.44375 2.775 3.69376 2.775 3.31875 3.15L0.16875 6.3C-0.05625 6.525 -0.05625 6.975 0.16875 7.2C0.318762 7.35001 0.468756 7.425 0.61875 7.425C0.768762 7.425 0.918756 7.425 1.06875 7.2L3.99375 4.275L5.79375 6.075C6.16876 6.45001 6.91875 6.45001 7.29376 6.075L11.0438 2.32501L11.0438 4.20001C11.0438 4.575 11.3438 4.87501 11.7188 4.87501C12.0937 4.87501 12.3938 4.575 12.3938 4.20001L12.3938 0.825011L12.3938 0.600011L12.2438 0.225Z"
|
||||
fill="#00B87A">
|
||||
</path>
|
||||
</svg>
|
||||
|
||||
</span>
|
||||
<span class="t1">完成率98%</span>
|
||||
<span class="t2">(30 days)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="top">
|
||||
<div class="icon">
|
||||
<img src="/assets/demo/sb4.png" alt="">
|
||||
</div>
|
||||
<div class="content">
|
||||
<p class="t1" style="color: rgba(255, 153, 0, 1);">2条</p>
|
||||
<p class="t2">告警信息</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<span class="icon"><svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" width="12.393798828125" height="7.42498779296875"
|
||||
viewBox="0 0 12.393798828125 7.42498779296875" fill="none">
|
||||
<path
|
||||
d="M12.2438 0.225L12.2438 0.150012L12.2438 0.0750058L12.1688 0.0750058C12.1688 0.0750058 12.0937 0.0750058 12.0188 0L8.34376 0C7.96876 0 7.66876 0.300006 7.66876 0.675C7.66876 1.05001 7.96876 1.35 8.34376 1.35L10.2188 1.35L6.61876 4.95L4.81876 3.15C4.44375 2.775 3.69376 2.775 3.31875 3.15L0.16875 6.3C-0.05625 6.525 -0.05625 6.975 0.16875 7.2C0.318762 7.35001 0.468756 7.425 0.61875 7.425C0.768762 7.425 0.918756 7.425 1.06875 7.2L3.99375 4.275L5.79375 6.075C6.16876 6.45001 6.91875 6.45001 7.29376 6.075L11.0438 2.32501L11.0438 4.20001C11.0438 4.575 11.3438 4.87501 11.7188 4.87501C12.0937 4.87501 12.3938 4.575 12.3938 4.20001L12.3938 0.825011L12.3938 0.600011L12.2438 0.225Z"
|
||||
fill="#00B87A">
|
||||
</path>
|
||||
</svg>
|
||||
|
||||
</span>
|
||||
<span class="t1">4%</span>
|
||||
<span class="t2">(30 days)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="back">
|
||||
<span>34522天</span>
|
||||
<span>已安全运行</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
.content {
|
||||
font-family: "Alibaba-PuHuiTi-Bold";
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.item {
|
||||
background-color: rgba(240, 249, 255, 1);
|
||||
padding: 20px 40px 20px 20px;
|
||||
border-radius: 20px;
|
||||
text-align: center;
|
||||
|
||||
.top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: left;
|
||||
|
||||
.icon {
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
margin-top: -20px;
|
||||
}
|
||||
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.t1 {
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
.t2 {
|
||||
font-size: 18px;
|
||||
color: rgba(62, 73, 84, 1);
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.t1 {
|
||||
color: rgba(0, 184, 122, 1);
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.t2 {
|
||||
color: rgba(150, 155, 160, 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.back {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
<script setup>
|
||||
|
||||
</script>
|
||||
23
src/views/demo1/index.vue
Normal file
@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div style="padding: 20px;">
|
||||
<el-row>
|
||||
<el-col :span="15">
|
||||
<TitleComponent title="设备情况" subtitle="电站一次监控数据" />
|
||||
<sbqk />
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<style scoped>
|
||||
.el-card {
|
||||
border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
<script setup>
|
||||
import TitleComponent from '@/views/demo/components/TitleComponent.vue';
|
||||
import sbqk from './components/sbqk.vue';
|
||||
|
||||
</script>
|
||||
@ -19,7 +19,7 @@
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||
<el-button type="primary" plain icon="Plus" v-hasPermi="['design:extract:add']" @click="handleAdd">新增</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
@ -37,8 +37,23 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center">
|
||||
<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="Download" @click="handleDownload(scope.row)" v-hasPermi="['design:extract:export']">导出</el-button
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
v-if="scope.row.status == 'draft'"
|
||||
icon="Edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['design:extract:query']"
|
||||
>审核</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
|
||||
link
|
||||
type="warning"
|
||||
@ -65,15 +80,17 @@
|
||||
<el-table :loading="loadingFlie" :data="fileList" style="width: 100%" border>
|
||||
<el-table-column prop="fileName" label="文件名称" align="center">
|
||||
<template #default="scope">
|
||||
<el-link
|
||||
<!-- <el-link
|
||||
:key="scope.row.fileId"
|
||||
:href="scope.row.fileUrl"
|
||||
target="_blank"
|
||||
:type="scope.row.status == '1' ? 'primary' : 'info'"
|
||||
:underline="false"
|
||||
disabled
|
||||
>
|
||||
{{ scope.row.fileName }}
|
||||
</el-link>
|
||||
</el-link> -->
|
||||
<span>{{ scope.row.fileName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="版本号" align="center" width="120" prop="version"> </el-table-column>
|
||||
@ -187,7 +204,7 @@ const handleDownload = (row) => {
|
||||
{
|
||||
id: row.id
|
||||
},
|
||||
`互提资料.zip`
|
||||
`互提资料.docx`
|
||||
);
|
||||
};
|
||||
const handleViewFile = (row) => {
|
||||
|
||||
@ -445,7 +445,9 @@ const getMajor = async () => {
|
||||
let res = await extractUserMajor({ userId: userId.value, projectId: currentProject.value?.id });
|
||||
if (res.code == 200) {
|
||||
des_user_major.value = res.data;
|
||||
console.log(des_user_major.value);
|
||||
if (res.data.length > 0) {
|
||||
form.user_major = res.data[0].userMajor;
|
||||
}
|
||||
}
|
||||
};
|
||||
/** 回显表单数据(编辑/查看/审批场景) */
|
||||
|
||||
809
src/views/design/appointment/index copy 2.vue
Normal file
@ -0,0 +1,809 @@
|
||||
<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"
|
||||
v-hasPermi="['design:user:list']"
|
||||
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>
|
||||
@ -6,7 +6,7 @@
|
||||
<el-card v-if="index < 3" shadow="always">
|
||||
<el-form :model="state.queryForm" :inline="true">
|
||||
<el-form-item label="版本号" prop="versions">
|
||||
<el-select v-model="state.queryForm.versions" placeholder="选择版本号">
|
||||
<el-select v-model="state.queryForm.versions" placeholder="选择版本号" @change="handleChangeVersion">
|
||||
<el-option v-for="item in state.options" :key="item.versions" :label="item.versions" :value="item.versions" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@ -16,10 +16,10 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="openTable(true, index)">一键展开</el-button>
|
||||
<el-button type="primary" @click="openTable(index)">{{ isExpandAll ? '一键收起' : '一键展开' }}</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="openTable(false, index)">一键收起</el-button>
|
||||
<el-button type="success" @click="downloadTemplate(1)">下载模板</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-upload ref="uploadRef" class="upload-demo" :http-request="importExcel" :show-file-list="false">
|
||||
@ -51,20 +51,21 @@
|
||||
<el-option v-for="item in state.options" :key="item.versions" :label="item.versions" :value="item.versions" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="success" @click="downloadTemplate(2)">下载模板</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-upload ref="uploadRef" class="upload-demo" :http-request="importExcel" :show-file-list="false" style="margin-right: 10px">
|
||||
<template #trigger>
|
||||
<el-button type="primary">导入excel</el-button>
|
||||
</template>
|
||||
</el-upload>
|
||||
<el-button v-if="state.versionsData.status == 'draft'" type="primary" con="edit" @click="clickApprovalSheet()">审核</el-button>
|
||||
<el-button
|
||||
v-if="state.versionsData.status == 'waiting' || state.versionsData.status == 'finish'"
|
||||
icon="view"
|
||||
@click="lookApprovalFlow()"
|
||||
type="warning"
|
||||
>查看流程</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="state.versionsData.status == 'draft'">
|
||||
<el-button type="primary" con="edit" @click="clickApprovalSheet()">审核</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="state.versionsData.status == 'waiting' || state.versionsData.status == 'finish'">
|
||||
<el-button icon="view" @click="lookApprovalFlow()" type="warning">查看流程</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
@ -117,6 +118,7 @@ const { proxy } = getCurrentInstance();
|
||||
const { work_order_type } = toRefs(proxy?.useDict('work_order_type'));
|
||||
const tableRef = ref({});
|
||||
console.log(work_order_type);
|
||||
const isExpandAll = ref(true);
|
||||
|
||||
// tableData
|
||||
// 版本号
|
||||
@ -146,6 +148,7 @@ const state = reactive({
|
||||
});
|
||||
// tab切换
|
||||
const handleTabChange = (tab) => {
|
||||
isExpandAll.value = true;
|
||||
console.log('tab', tab);
|
||||
state.tableData = [];
|
||||
state.options = [];
|
||||
@ -163,6 +166,7 @@ const handleTabChange = (tab) => {
|
||||
onMounted(async () => {
|
||||
await getVersionNums();
|
||||
});
|
||||
|
||||
// 获取版本号
|
||||
async function getVersionNums(isSheet = true) {
|
||||
try {
|
||||
@ -239,10 +243,10 @@ async function handleSheetName() {
|
||||
|
||||
// 获取列表
|
||||
async function handleQueryList(isSheet = true) {
|
||||
if (isSheet && !state.queryForm.sheet) {
|
||||
console.warn('表名不存在,无法获取列表数据');
|
||||
return;
|
||||
}
|
||||
// if (isSheet && !state.queryForm) {
|
||||
// console.warn('表名不存在,无法获取列表数据');
|
||||
// return;
|
||||
// }
|
||||
|
||||
try {
|
||||
state.loading.list = true;
|
||||
@ -300,18 +304,19 @@ function handleChange(sheet) {
|
||||
function handleChangeVersion(versions) {
|
||||
state.queryForm.versions = versions;
|
||||
state.versionsData = state.options.find((e) => e.versions == versions);
|
||||
console.log('state.versionsData', state.versionsData);
|
||||
// console.log('state.versionsData', state.versionsData);
|
||||
state.sheets = [];
|
||||
handleQueryList();
|
||||
}
|
||||
// 在 openTable 方法中通过索引获取对应的表格实例
|
||||
function openTable(flag, index) {
|
||||
function openTable(index) {
|
||||
isExpandAll.value = !isExpandAll.value;
|
||||
nextTick(() => {
|
||||
// 通过索引获取当前标签页的表格实例
|
||||
const currentTable = tableRef.value[index];
|
||||
console.log(currentTable, index);
|
||||
if (currentTable) {
|
||||
handleArr(state.tableData, flag, currentTable);
|
||||
handleArr(state.tableData, isExpandAll.value, currentTable);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -345,6 +350,34 @@ function lookApprovalFlow(row) {
|
||||
}
|
||||
});
|
||||
}
|
||||
// 下载模板
|
||||
const downloadTemplate = (type) => {
|
||||
// 导出模版文件
|
||||
try {
|
||||
let linkurl = '';
|
||||
let name = '';
|
||||
if (type == 1) {
|
||||
linkurl = '/billOfQuantities.xlsx';
|
||||
name = '工程量清单模板.xlsx';
|
||||
} else {
|
||||
linkurl = '/materialsEquipment.xlsx';
|
||||
name = '物资设备清单模板.xlsx';
|
||||
}
|
||||
// 创建a标签
|
||||
const link = document.createElement('a');
|
||||
// 设置PDF文件路径 - 相对于public目录
|
||||
link.href = linkurl;
|
||||
// 设置下载后的文件名
|
||||
link.download = name;
|
||||
// 触发点击
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
} catch (error) {
|
||||
alert('下载失败,请重试');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.billof-quantities {
|
||||
|
||||