This commit is contained in:
ljx
2025-08-22 11:43:23 +08:00
67 changed files with 4935 additions and 681 deletions

View File

@ -5,7 +5,7 @@ VITE_APP_TITLE = 煤科建管平台
VITE_APP_ENV = 'development' VITE_APP_ENV = 'development'
# 开发环境 # 开发环境
VITE_APP_BASE_API = 'http://192.168.110.149:8899' VITE_APP_BASE_API = 'http://192.168.110.180:8899'
# 无人机接口地址 # 无人机接口地址

View File

@ -53,3 +53,18 @@ export const sheetList = (query) => {
params: query params: query
}); });
}; };
//获取sheet
export const obtainAllVersionNumbers = (query) => {
return request({
url: '/bidding/biddingLimitList/obtainAllVersionNumbers',
method: 'get',
params: query
});
};
//获取sheet
export const getVersionDetail = (id) => {
return request({
url: '/bidding/biddingLimitList/getVersionDetail/' + id,
method: 'get'
});
};

View File

@ -8,7 +8,7 @@ import { ListOfWinningBidsVO, ListOfWinningBidsForm, ListOfWinningBidsQuery } fr
* @returns {*} * @returns {*}
*/ */
export const listListOfWinningBids = (query?: ListOfWinningBidsQuery): AxiosPromise<ListOfWinningBidsVO[]> => { export const listListOfWinningBids = (query) => {
return request({ return request({
url: '/bidding/listOfWinningBids/list', url: '/bidding/listOfWinningBids/list',
method: 'get', method: 'get',

View File

@ -0,0 +1,83 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { ExpensesContractVO, ExpensesContractForm, ExpensesContractQuery } from '@/api/ctr/expensesContract/types';
/**
* 查询支出合同列表
* @param query
* @returns {*}
*/
export const listExpensesContract = (query?: ExpensesContractQuery): AxiosPromise<ExpensesContractVO[]> => {
return request({
url: '/ctr/expensesContract/list',
method: 'get',
params: query
});
};
/**
* 查询支出合同详细
* @param id
*/
export const getExpensesContract = (id: string | number): AxiosPromise<ExpensesContractVO> => {
return request({
url: '/ctr/expensesContract/' + id,
method: 'get'
});
};
/**
* 新增支出合同
* @param data
*/
export const addExpensesContract = (data: ExpensesContractForm) => {
return request({
url: '/ctr/expensesContract',
method: 'post',
data: data
});
};
/**
* 修改支出合同
* @param data
*/
export const updateExpensesContract = (data: ExpensesContractForm) => {
return request({
url: '/ctr/expensesContract',
method: 'put',
data: data
});
};
/**
* 删除支出合同
* @param id
*/
export const delExpensesContract = (id: string | number | Array<string | number>) => {
return request({
url: '/ctr/expensesContract/' + id,
method: 'delete'
});
};
/**
* 查看支出合同附件列表
* @param id
*/
export const getFileList = (data) => {
return request({
url: '/ctr/expensesContract/file/list',
method: 'get',
params: data
})
}
// 获取招标计划
export const getTenderPlan = (data) => {
return request({
url: '/ctr/expensesContract/tender/list',
method: 'get',
params: data
})
}

View File

@ -0,0 +1,141 @@
export interface ExpensesContractVO {
/**
* 主键ID
*/
id: string | number;
/**
* 项目ID
*/
projectId: string | number;
/**
* 合同编号
*/
contractCode: string;
/**
* 合同类型
*/
contractType: string;
/**
* 供应商
*/
contractSupplier: string;
/**
* 分包内容
*/
contractedContent: string;
/**
* 合同金额
*/
amount: number;
/**
* 招标Id
*/
tenderId: string | number;
/**
* 备注
*/
remark: string;
}
export interface ExpensesContractForm extends BaseEntity {
/**
* 主键ID
*/
id?: string | number;
/**
* 项目ID
*/
projectId?: string | number;
/**
* 合同编号
*/
contractCode?: string;
/**
* 合同类型
*/
contractType?: string;
/**
* 供应商
*/
contractSupplier?: string;
/**
* 分包内容
*/
contractedContent?: string;
/**
* 合同金额
*/
amount?: number;
/**
* 招标Id
*/
tenderId?: string | number;
/**
* 备注
*/
remark?: string;
}
export interface ExpensesContractQuery extends PageQuery {
/**
* 项目ID
*/
projectId?: string | number;
/**
* 合同编号
*/
contractCode?: string;
/**
* 合同类型
*/
contractType?: string;
/**
* 供应商
*/
contractSupplier?: string;
/**
* 分包内容
*/
contractedContent?: string;
/**
* 合同金额
*/
amount?: number;
/**
* 招标Id
*/
tenderId?: string | number;
/**
* 日期范围参数
*/
params?: any;
}

View File

@ -0,0 +1,74 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { IncomeContractVO, IncomeContractForm, IncomeContractQuery } from '@/api/ctr/incomeContract/types';
/**
* 查询收入合同列表
* @param query
* @returns {*}
*/
export const listIncomeContract = (query?: IncomeContractQuery): AxiosPromise<IncomeContractVO[]> => {
return request({
url: '/ctr/incomeContract/list',
method: 'get',
params: query
});
};
/**
* 查询收入合同详细
* @param id
*/
export const getIncomeContract = (id: string | number): AxiosPromise<IncomeContractVO> => {
return request({
url: '/ctr/incomeContract/' + id,
method: 'get'
});
};
/**
* 新增收入合同
* @param data
*/
export const addIncomeContract = (data: IncomeContractForm) => {
return request({
url: '/ctr/incomeContract',
method: 'post',
data: data
});
};
/**
* 修改收入合同
* @param data
*/
export const updateIncomeContract = (data: IncomeContractForm) => {
return request({
url: '/ctr/incomeContract',
method: 'put',
data: data
});
};
/**
* 删除收入合同
* @param id
*/
export const delIncomeContract = (id: string | number | Array<string | number>) => {
return request({
url: '/ctr/incomeContract/' + id,
method: 'delete'
});
};
/**
* 查看收入合同附件列表
* @param id
*/
export const getFileList = (data) => {
return request({
url: '/ctr/incomeContract/file/list',
method: 'get',
params: data
})
}

View File

@ -0,0 +1,126 @@
export interface IncomeContractVO {
/**
* 主键ID
*/
id: string | number;
/**
* 项目ID
*/
projectId: string | number;
/**
* 合同编号
*/
contractCode: string;
/**
* 合同类型
*/
contractType: string;
/**
* 业主单位
*/
contractOwner: string;
/**
* 承包内容
*/
contractedContent: string;
/**
* 合同金额
*/
amount: number;
/**
* 备注
*/
remark: string;
}
export interface IncomeContractForm extends BaseEntity {
/**
* 主键ID
*/
id?: string | number;
/**
* 项目ID
*/
projectId?: string | number;
/**
* 合同编号
*/
contractCode?: string;
/**
* 合同类型
*/
contractType?: string;
/**
* 业主单位
*/
contractOwner?: string;
/**
* 承包内容
*/
contractedContent?: string;
/**
* 合同金额
*/
amount?: number;
/**
* 备注
*/
remark?: string;
}
export interface IncomeContractQuery extends PageQuery {
/**
* 项目ID
*/
projectId?: string | number;
/**
* 合同编号
*/
contractCode?: string;
/**
* 合同类型
*/
contractType?: string;
/**
* 业主单位
*/
contractOwner?: string;
/**
* 承包内容
*/
contractedContent?: string;
/**
* 合同金额
*/
amount?: number;
/**
* 日期范围参数
*/
params?: any;
}

View File

@ -31,3 +31,11 @@ export const getFileList = (id) => {
method: 'get' method: 'get'
}); });
}; };
// 获取专业
export const extractUserMajor = (params) => {
return request({
url: '/design/extract/userMajor',
method: 'get',
params
});
};

View File

@ -82,7 +82,10 @@ export interface MaterialsInventoryForm extends BaseEntity {
* 主键id * 主键id
*/ */
id?: string | number; id?: string | number;
/**
* 使用部位
*/
usePart?: string;
/** /**
* 材料id * 材料id
*/ */

View File

@ -124,7 +124,7 @@ export const logisticsDetial = (id) => {
export const getDetailBASE = (id) => { export const getDetailBASE = (id) => {
return request({ return request({
url: '/cailiaoshebei/purchaseDoc/pic/' + id, url: '/cailiaoshebei/purchaseDoc/pdf/' + id,
method: 'get' method: 'get'
}); });
}; };

BIN
src/assets/large/down.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

BIN
src/assets/large/top1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
src/assets/large/top2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
src/assets/large/top3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
src/assets/large/top4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
src/assets/large/up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

View File

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="440" height="1" viewBox="0 0 440 1" fill="none">
<path fill="url(#linear_border_216_180_0)" d="M440 0L439 0L439 1L440 1L440 0ZM437 0L435 0L435 1L437 1L437 0ZM433 0L431 0L431 1L433 1L433 0ZM429 0L427 0L427 1L429 1L429 0ZM425 0L423 0L423 1L425 1L425 0ZM421 0L419 0L419 1L421 1L421 0ZM417 0L415 0L415 1L417 1L417 0ZM413 0L411 0L411 1L413 1L413 0ZM409 0L407 0L407 1L409 1L409 0ZM405 0L403 0L403 1L405 1L405 0ZM401 0L399 0L399 1L401 1L401 0ZM397 0L395 0L395 1L397 1L397 0ZM393 0L391 0L391 1L393 1L393 0ZM389 0L387 0L387 1L389 1L389 0ZM385 0L383 0L383 1L385 1L385 0ZM381 0L379 0L379 1L381 1L381 0ZM377 0L375 0L375 1L377 1L377 0ZM373 0L371 0L371 1L373 1L373 0ZM369 0L367 0L367 1L369 1L369 0ZM365 0L363 0L363 1L365 1L365 0ZM361 0L359 0L359 1L361 1L361 0ZM357 0L355 0L355 1L357 1L357 0ZM353 0L351 0L351 1L353 1L353 0ZM349 0L347 0L347 1L349 1L349 0ZM345 0L343 0L343 1L345 1L345 0ZM341 0L339 0L339 1L341 1L341 0ZM337 0L335 0L335 1L337 1L337 0ZM333 0L331 0L331 1L333 1L333 0ZM329 0L327 0L327 1L329 1L329 0ZM325 0L323 0L323 1L325 1L325 0ZM321 0L319 0L319 1L321 1L321 0ZM317 0L315 0L315 1L317 1L317 0ZM313 0L311 0L311 1L313 1L313 0ZM309 0L307 0L307 1L309 1L309 0ZM305 0L303 0L303 1L305 1L305 0ZM301 0L299 0L299 1L301 1L301 0ZM297 0L295 0L295 1L297 1L297 0ZM293 0L291 0L291 1L293 1L293 0ZM289 0L287 0L287 1L289 1L289 0ZM285 0L283 0L283 1L285 1L285 0ZM281 0L279 0L279 1L281 1L281 0ZM277 0L275 0L275 1L277 1L277 0ZM273 0L271 0L271 1L273 1L273 0ZM269 0L267 0L267 1L269 1L269 0ZM265 0L263 0L263 1L265 1L265 0ZM261 0L259 0L259 1L261 1L261 0ZM257 0L255 0L255 1L257 1L257 0ZM253 0L251 0L251 1L253 1L253 0ZM249 0L247 0L247 1L249 1L249 0ZM245 0L243 0L243 1L245 1L245 0ZM241 0L239 0L239 1L241 1L241 0ZM237 0L235 0L235 1L237 1L237 0ZM233 0L231 0L231 1L233 1L233 0ZM229 0L227 0L227 1L229 1L229 0ZM225 0L223 0L223 1L225 1L225 0ZM221 0L219 0L219 1L221 1L221 0ZM217 0L215 0L215 1L217 1L217 0ZM213 0L211 0L211 1L213 1L213 0ZM209 0L207 0L207 1L209 1L209 0ZM205 0L203 0L203 1L205 1L205 0ZM201 0L199 0L199 1L201 1L201 0ZM197 0L195 0L195 1L197 1L197 0ZM193 0L191 0L191 1L193 1L193 0ZM189 0L187 0L187 1L189 1L189 0ZM185 0L183 0L183 1L185 1L185 0ZM181 0L179 0L179 1L181 1L181 0ZM177 0L175 0L175 1L177 1L177 0ZM173 0L171 0L171 1L173 1L173 0ZM169 0L167 0L167 1L169 1L169 0ZM165 0L163 0L163 1L165 1L165 0ZM161 0L159 0L159 1L161 1L161 0ZM157 0L155 0L155 1L157 1L157 0ZM153 0L151 0L151 1L153 1L153 0ZM149 0L147 0L147 1L149 1L149 0ZM145 0L143 0L143 1L145 1L145 0ZM141 0L139 0L139 1L141 1L141 0ZM137 0L135 0L135 1L137 1L137 0ZM133 0L131 0L131 1L133 1L133 0ZM129 0L127 0L127 1L129 1L129 0ZM125 0L123 0L123 1L125 1L125 0ZM121 0L119 0L119 1L121 1L121 0ZM117 0L115 0L115 1L117 1L117 0ZM113 0L111 0L111 1L113 1L113 0ZM109 0L107 0L107 1L109 1L109 0ZM105 0L103 0L103 1L105 1L105 0ZM101 0L99 0L99 1L101 1L101 0ZM97 0L95 0L95 1L97 1L97 0ZM93 0L91 0L91 1L93 1L93 0ZM89 0L87 0L87 1L89 1L89 0ZM85 0L83 0L83 1L85 1L85 0ZM81 0L79 0L79 1L81 1L81 0ZM77 0L75 0L75 1L77 1L77 0ZM73 0L71 0L71 1L73 1L73 0ZM69 0L67 0L67 1L69 1L69 0ZM65 0L63 0L63 1L65 1L65 0ZM61 0L59 0L59 1L61 1L61 0ZM57 0L55 0L55 1L57 1L57 0ZM53 0L51 0L51 1L53 1L53 0ZM49 0L47 0L47 1L49 1L49 0ZM45 0L43 0L43 1L45 1L45 0ZM41 0L39 0L39 1L41 1L41 0ZM37 0L35 0L35 1L37 1L37 0ZM33 0L31 0L31 1L33 1L33 0ZM29 0L27 0L27 1L29 1L29 0ZM25 0L23 0L23 1L25 1L25 0ZM21 0L19 0L19 1L21 1L21 0ZM17 0L15 0L15 1L17 1L17 0ZM13 0L11 0L11 1L13 1L13 0ZM9 0L7 0L7 1L9 1L9 0ZM5 0L3 0L3 1L5 1L5 0ZM1 0L0 0L0 1L1 1L1 0Z">
</path>
<defs>
<linearGradient id="linear_border_216_180_0" x1="440" y1="0.5" x2="0" y2="0.5" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#1DD6FF" stop-opacity="0" />
<stop offset="1" stop-color="#1DD6FF" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 370 KiB

View File

@ -0,0 +1,33 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="42.20001220703125" height="44.0025634765625" viewBox="0 0 42.20001220703125 44.0025634765625" fill="none">
<g opacity="0.8">
<ellipse transform="matrix(0.9915240406990051, -0.12992359697818756, 0.13317112624645233, 0.9910931587219238, 0, 4.8818359375)" cx="18.787446539492898" cy="18.56099636814998" rx="18.787446539492898" ry="18.56099636814998" fill="url(#linear_fill_216_484)" >
</ellipse>
</g>
<g clip-path="url(#clip-path-216_485)">
<g filter="url(#filter_216_487)">
<path d="M18.4577 26.933C16.6094 26.933 14.8691 26.2223 13.5609 24.9334C12.2528 23.6445 11.5316 21.9297 11.5316 20.1085C11.5316 18.2873 12.2528 16.5755 13.5609 15.2866C14.8691 13.9976 16.6094 13.287 18.4577 13.287C20.306 13.287 22.0463 13.9976 23.3545 15.2866C24.6626 16.5755 25.3839 18.2902 25.3839 20.1114C25.3839 21.9326 24.6626 23.6473 23.3545 24.9363C22.0463 26.2252 20.306 26.933 18.4577 26.933ZM18.4577 15.5886C15.9261 15.5886 13.8675 17.617 13.8675 20.1114C13.8675 22.6058 15.9261 24.6342 18.4577 24.6342C20.9893 24.6342 23.0479 22.6058 23.0479 20.1114C23.0479 17.617 20.9893 15.5886 18.4577 15.5886ZM29.2353 42.6332C28.59 42.6332 28.0673 42.1182 28.0673 41.4823L28.0673 35.5326C28.0673 33.1129 26.1606 31.122 23.7487 30.9436L21.0185 32.8597C19.4972 33.9271 17.4532 33.93 15.929 32.8684L13.1667 30.9436C10.7549 31.122 8.84812 33.1129 8.84812 35.5326L8.84812 41.4823C8.84812 42.1182 8.32544 42.6332 7.68013 42.6332C7.03482 42.6332 6.51215 42.1182 6.51215 41.4823L6.51215 35.5326C6.51215 33.6883 7.24214 31.9535 8.56488 30.6502C9.88762 29.3468 11.6484 28.6276 13.5201 28.6276C13.7624 28.6276 13.996 28.7024 14.1946 28.8376L17.278 30.9868C17.9934 31.4845 18.9512 31.4816 19.6637 30.9839L22.7179 28.8405C22.9165 28.7024 23.153 28.6276 23.3954 28.6276C25.2671 28.6276 27.0278 29.3468 28.3505 30.6502C29.6733 31.9535 30.4033 33.6883 30.4033 35.5326L30.4033 41.4823C30.4033 42.1182 29.8806 42.6332 29.2353 42.6332Z" fill="#FFFFFF" >
</path>
</g>
<path d="M11.7564 42.6332C11.1111 42.6332 10.5884 42.1182 10.5884 41.4824L10.5884 38.7204C10.5884 38.0845 11.1111 37.5695 11.7564 37.5695C12.4017 37.5695 12.9244 38.0845 12.9244 38.7204L12.9244 41.4824C12.9244 42.1182 12.4017 42.6332 11.7564 42.6332ZM25.159 42.6332C24.5137 42.6332 23.991 42.1182 23.991 41.4824L23.991 38.7204C23.991 38.0845 24.5137 37.5695 25.159 37.5695C25.8043 37.5695 26.327 38.0845 26.327 38.7204L26.327 41.4824C26.327 42.1182 25.8043 42.6332 25.159 42.6332ZM23.7283 20.2093L8.39845 20.2093C7.75314 20.2093 7.23047 19.6943 7.23047 19.0584C7.23047 18.4226 7.75314 17.9076 8.39845 17.9076L23.7283 17.9076C24.3736 17.9076 24.8962 18.4226 24.8962 19.0584C24.8962 19.6943 24.3736 20.2093 23.7283 20.2093Z" fill="#FFFFFF" >
</path>
</g>
<defs>
<radialGradient id="linear_fill_216_484" cx="0" cy="0" r="1" gradientTransform="translate(31.006426019848288 5.783235248388171) rotate(-151.06468116612422) scale(28.374047672813088, 28.374047672813088)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#1DD6FF" stop-opacity="0.78" />
<stop offset="0.9861" stop-color="#1DD6FF" stop-opacity="0" />
</radialGradient>
<clipPath id="clip-path-216_485">
<path d="M2.54681 44.0025L34.2695 44.0025L34.2695 12.2961L2.54681 12.2961L2.54681 44.0025Z" fill="white"/>
</clipPath>
<filter id="filter_216_487" x="4.51214599609375" y="11.2869873046875" width="27.89111328125" height="33.34619140625" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="feFloodId_216_487"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha_216_487"/>
<feOffset dx="0" dy="0"/>
<feGaussianBlur stdDeviation="1"/>
<feComposite in2="hardAlpha_216_487" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0.7450980392156863 0 0 0 0 0.9686274509803922 0 0 0 0.8 0"/>
<feBlend mode="normal" in2="feFloodId_216_487" result="dropShadow_1_216_487"/>
<feBlend mode="normal" in="SourceGraphic" in2="dropShadow_1_216_487" result="shape_216_487"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.4189453125" height="12" viewBox="0 0 12.4189453125 12" fill="none">
<ellipse cx="6.20947265625" cy="6" rx="6.20947265625" ry="6" fill="#1DD6FF" fill-opacity="0.2">
</ellipse>
<ellipse cx="6.209228515625" cy="6" rx="3.104736328125" ry="3" fill="#1DD6FF" >
</ellipse>
</svg>

After

Width:  |  Height:  |  Size: 370 B

View File

@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="15" height="35" viewBox="0 0 15 35" fill="none">
<rect x="1" y="0" width="14" height="35" fill="url(#linear_fill_216_187)" fill-opacity="1">
</rect>
<rect x="0" y="0" width="4" height="35" fill="#1DD6FF" >
</rect>
<defs>
<linearGradient id="linear_fill_216_187" x1="1" y1="17.5" x2="13.62772" y2="17.5" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#43E2CB" stop-opacity="0.4" />
<stop offset="1" stop-color="#43E2CB" stop-opacity="0" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

View File

@ -0,0 +1,52 @@
<template>
<el-dialog v-model="dialogVisible" title="附件列表" width="45%">
<el-table :data="fileList" style="width: 100%">
<el-table-column prop="fileName" label="文件名" />
<el-table-column prop="type" label="操作">
<template #default="scope">
<el-button link type="success" @click="viewFile(scope.row)" icon="View">查看文件</el-button>
<el-button link type="primary" @click="downloadFile(scope.row)" icon="download">下载文件</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>
<el-dialog width="80%" v-model="viewFileVisible" title="查看文件" append-to-body>
<iframe :src="fileUrl" frameborder="0" width="100%" height="800"></iframe>
<template #footer>
<div class="dialog-footer">
<el-button @click="viewFileVisible = false" type="primary">关闭</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
const { proxy } = getCurrentInstance();
const dialogVisible = defineModel();
const props = defineProps(['fileList']);
const viewFileVisible = ref(false);
const fileUrl = ref('');
const downloadFile = async (data) => {
// 这里可以添加下载文件的逻辑
await proxy?.downloadFile(data.fileUrl, data.fileName);
// proxy?.$message({
// message: '下载成功',
// type: 'success'
// });
};
const viewFile = (data) => {
// 这里可以添加查看文件的逻辑
fileUrl.value = data.fileUrl;
viewFileVisible.value = true;
};
const adjustIframe = () => {
const iframe = document.querySelector('iframe');
if (iframe) {
iframe.style.height = `${iframe.contentWindow.document.body.scrollHeight}px`;
}
};
</script>

View File

@ -1,28 +1,11 @@
<template> <template>
<div class="upload-file"> <div class="upload-file">
<el-upload <el-upload ref="fileUploadRef" multiple :action="realUploadUrl" :before-upload="handleBeforeUpload"
ref="fileUploadRef" :file-list="fileList" :limit="limit" :on-error="handleUploadError" :on-exceed="handleExceed"
multiple :on-success="handleUploadSuccess" :show-file-list="showFileList" :headers="headers" class="upload-file-uploader"
:action="realUploadUrl" :list-type="isConstruction ? 'picture-card' : 'text'" :accept="accept" :drag="isDarg" :data="data"
:before-upload="handleBeforeUpload" :auto-upload="autoUpload" :on-change="handleChange" :on-remove="handleRemove" :method="method"
:file-list="fileList" :http-request="customUpload">
: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"
>
<slot> <slot>
<div> <div>
<!-- 上传按钮 --> <!-- 上传按钮 -->
@ -41,14 +24,10 @@
的文件 的文件
</div> </div>
<!-- 文件列表 --> <!-- 文件列表 -->
<transition-group <transition-group v-if="!isConstruction && !isImportInfo"
v-if="!isConstruction && !isImportInfo" class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul" @click.stop>
class="upload-file-list el-upload-list el-upload-list--text" <li style="margin-top: 10px" v-for="(file, index) in fileList" :key="file.uid"
name="el-fade-in-linear" class="el-upload-list__item ele-upload-list__item-content">
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">
<el-link :href="`${file.url}`" :underline="false" target="_blank"> <el-link :href="`${file.url}`" :underline="false" target="_blank">
<span class="el-icon-document"> {{ getFileName(file.name) }} </span> <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
</el-link> </el-link>
@ -60,7 +39,9 @@
</div> </div>
</slot> </slot>
<el-icon v-if="isConstruction"><Plus /></el-icon> <el-icon v-if="isConstruction">
<Plus />
</el-icon>
<template #file="{ file }"> <template #file="{ file }">
<div class="pdf" v-if="isConstruction"> <div class="pdf" v-if="isConstruction">
<img src="@/assets/icons/svg/pdf.png" alt="" /> <img src="@/assets/icons/svg/pdf.png" alt="" />
@ -69,10 +50,14 @@
</el-text> </el-text>
<div class="Shadow"> <div class="Shadow">
<a :href="file.url" target="_blank"> <a :href="file.url" target="_blank">
<el-icon class="mr"><View /></el-icon> <el-icon class="mr">
<View />
</el-icon>
</a> </a>
<a href="#"> <a href="#">
<el-icon @click="handleDelete((file as any).ossId, 'ossId')"><Delete /></el-icon> <el-icon @click="handleDelete((file as any).ossId, 'ossId')">
<Delete />
</el-icon>
</a> </a>
</div> </div>
</div> </div>
@ -112,6 +97,11 @@ const props = defineProps({
autoUpload: propTypes.bool.def(true), autoUpload: propTypes.bool.def(true),
// 是否显示文件列表 // 是否显示文件列表
showFileList: propTypes.bool.def(false), showFileList: propTypes.bool.def(false),
// 默认显示的文件列表
defaultFileList: {
type: Array as any,
default: () => []
},
// 其他参数 // 其他参数
data: propTypes.object.def({}), data: propTypes.object.def({}),
// 成功回调 // 成功回调
@ -155,7 +145,6 @@ const fileUploadRef = ref<ElUploadInstance>();
const accept = computed(() => { const accept = computed(() => {
return props.fileType.map((value) => `.${value}`).join(','); return props.fileType.map((value) => `.${value}`).join(',');
}); });
watch( watch(
() => props.modelValue, () => props.modelValue,
async (val) => { async (val) => {
@ -169,6 +158,8 @@ watch(
} else { } else {
const res = await listByIds(val as any); const res = await listByIds(val as any);
list = res.data.map((oss) => { list = res.data.map((oss) => {
console.log(oss);
return { return {
name: oss.originalName, name: oss.originalName,
url: oss.url, url: oss.url,
@ -189,7 +180,13 @@ watch(
}, },
{ deep: true, immediate: true } { 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) => { const handleBeforeUpload = (file: any) => {
// 校检文件类型 // 校检文件类型
@ -416,14 +413,17 @@ defineExpose({ submitUpload });
border-radius: 6px; border-radius: 6px;
position: relative; position: relative;
width: 100%; width: 100%;
img { img {
width: 40%; width: 40%;
} }
&:hover { &:hover {
.Shadow { .Shadow {
opacity: 1; opacity: 1;
} }
} }
>span { >span {
width: 100%; width: 100%;
} }
@ -431,6 +431,7 @@ defineExpose({ submitUpload });
.upload-file-list { .upload-file-list {
margin: 0; margin: 0;
.el-upload-list__item { .el-upload-list__item {
border: 1px solid #e4e7ed; border: 1px solid #e4e7ed;
line-height: 2; line-height: 2;
@ -445,6 +446,7 @@ defineExpose({ submitUpload });
align-items: center; align-items: center;
color: inherit; color: inherit;
} }
.Shadow { .Shadow {
align-items: center; align-items: center;
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
@ -466,6 +468,7 @@ defineExpose({ submitUpload });
.ele-upload-list__item-content-action .el-link { .ele-upload-list__item-content-action .el-link {
margin-right: 10px; margin-right: 10px;
} }
.el-icon.avatar-uploader-icon { .el-icon.avatar-uploader-icon {
border: 1px dashed #cdd0d6; border: 1px dashed #cdd0d6;
border-radius: 6px; border-radius: 6px;

View File

@ -75,6 +75,11 @@ export const constantRoutes: RouteRecordRaw[] = [
component: () => import('@/views/error/401.vue'), component: () => import('@/views/error/401.vue'),
hidden: true hidden: true
}, },
{
path: '/ProjectScreen',
component: () => import('@/views/ProjectScreen/index.vue'),
hidden: true
},
{ {
path: '/user', path: '/user',
component: Layout, component: Layout,

View File

@ -0,0 +1,174 @@
<template>
<div class="centerPage">
<div class="topPage">
<!-- 暂无 -->
</div>
<div class="endPage">
<Title title="AI安全巡检" :prefix="true" />
<div class="swiper">
<div class="arrow" :class="{ 'canUse': canLeft }" @click="swiperClick('left')">
<el-icon size="16" color="skyblue">
<ArrowLeft />
</el-icon>
</div>
<div class="swiper_content" ref="swiperContent">
<div class="swiper_item" v-for="(item, index) in swiperList" :key="index">
<img src="@/assets/projectLarge/swiper.png" alt="" class="swiper_img">
<div class="swiper_date">{{ item.date }}</div>
<div class="swiper_tip">{{ item.tip }}</div>
</div>
</div>
<div class="arrow" :class="{ 'canUse': canRight }" @click="swiperClick('right')">
<el-icon size="16">
<ArrowRight />
</el-icon>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue"
import Title from './title.vue'
const swiperList = ref([
{ date: '03-18 15:00', tip: '未佩戴安全帽1' },
{ date: '03-18 15:00', tip: '未佩戴安全帽2' },
{ date: '03-18 15:00', tip: '未佩戴安全帽3' },
{ date: '03-18 15:00', tip: '未佩戴安全帽4' },
{ date: '03-18 15:00', tip: '未佩戴安全帽5' },
{ date: '03-18 15:00', tip: '未佩戴安全帽6' },
{ date: '03-18 15:00', tip: '未佩戴安全帽7' },
{ date: '03-18 15:00', tip: '未佩戴安全帽8' },
{ date: '03-18 15:00', tip: '未佩戴安全帽9' },
{ date: '03-18 15:00', tip: '未佩戴安全帽10' },
{ date: '03-18 15:00', tip: '未佩戴安全帽11' },
{ date: '03-18 15:00', tip: '未佩戴安全帽12' },
])
const swiperContent = ref<HTMLDivElement>()
const swiperItemWidth = ref(100)
const canLeft = ref(false)
const canRight = ref(true)
const swiperClick = (direction: 'left' | 'right') => {
if (direction === 'right') {
if (swiperContent.value.scrollLeft >= swiperContent.value.scrollWidth - swiperContent.value.clientWidth) {
canRight.value = false
canLeft.value = true
return
}
swiperContent.value.scrollLeft += swiperItemWidth.value
} else {
if (swiperContent.value.scrollLeft <= 0) {
canLeft.value = false
canRight.value = true
return
}
swiperContent.value.scrollLeft -= swiperItemWidth.value
}
}
onMounted(() => {
swiperItemWidth.value = swiperContent.value.children[0].clientWidth + 20
})
</script>
<style scoped lang="scss">
.centerPage {
display: flex;
flex-direction: column;
width: 50vw;
height: 100%;
.topPage,
.endPage {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
padding: 15px 0;
border: 1px solid rgba(29, 214, 255, 0.1);
box-sizing: border-box;
}
.topPage {
flex: 1;
margin-bottom: 23px;
}
}
.swiper {
width: 100%;
display: flex;
align-items: center;
gap: 20px;
padding: 20px 20px 10px 20px;
.swiper_content {
width: 100%;
display: flex;
gap: 20px;
transition: all 0.3s ease-in-out;
overflow-x: auto;
&::-webkit-scrollbar {
display: none;
}
}
.swiper_item {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
width: 133px;
height: 84px;
.swiper_img {
width: 133px;
height: 84px;
object-fit: cover;
}
.swiper_date {
position: absolute;
top: 4px;
right: 4px;
font-size: 14px;
font-weight: 400;
color: rgba(230, 247, 255, 1);
}
.swiper_tip {
position: absolute;
bottom: 0;
width: 100%;
padding: 5px 0;
text-align: center;
font-size: 12px;
font-weight: 400;
color: rgba(230, 247, 255, 1);
background-color: rgba(0, 0, 0, 0.5);
}
}
}
.arrow {
display: grid;
place-items: center;
width: 20px;
height: 20px;
border-radius: 50%;
border: 1px solid skyblue;
color: skyblue;
&:canUse {
color: #000 !important;
}
}
</style>

View File

@ -0,0 +1,198 @@
<template>
<div class="header">
<div class="header_left">
<div class="header_left_img">
<img src="@/assets/large/secure.png" style="width: 100%; height: 100%" />
</div>
<div style="font-size: 12px; padding-left: 10px">安全生产天数</div>
<div class="header_left_text">
1,235
<span style="font-size: 12px"></span>
</div>
</div>
<div class="title">
<div>XXX智慧工地管理平台</div>
<div>XXX Smart Construction Stic Management Dashboard</div>
</div>
<div class="right">
<div class="top-bar">
<!-- 左侧天气图标 + 日期文字 -->
<div class="left-section">
<img src="@/assets/large/weather.png" alt="天气图标" />
<span>
<span>多云 9°/18°</span>
<span style="padding-left: 20px"> {{ week[date.week] }} ({{ date.ymd }})</span>
</span>
</div>
<!-- 分割线 -->
<div class="divider">
<div class="top-block"></div>
<div class="bottom-block"></div>
</div>
<!-- 右侧管理系统图标 + 文字 -->
<div class="right-section">
<img src="@/assets/large/setting.png" alt="设置图标" />
<span>管理系统</span>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
const week = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
const date = ref({
ymd: '',
hms: '',
week: 0
});
const setTime = () => {
let date1 = new Date();
let year: any = date1.getFullYear();
let month: any = date1.getMonth() + 1;
let day: any = date1.getDate();
let hours: any = date1.getHours();
if (hours < 10) {
hours = '0' + hours;
}
let minutes: any = date1.getMinutes();
if (minutes < 10) {
minutes = '0' + minutes;
}
let seconds: any = date1.getSeconds();
if (seconds < 10) {
seconds = '0' + seconds;
}
date.value.ymd = year + '-' + month + '-' + day;
date.value.hms = hours + ':' + minutes + ':' + seconds;
date.value.week = date1.getDay();
};
// 添加定时器,每秒更新一次时间
const timer = setInterval(setTime, 1000);
// 组件卸载时清除定时器
onUnmounted(() => {
clearInterval(timer);
});
</script>
<style scoped lang="scss">
.header {
width: 100%;
height: 80px;
box-sizing: border-box;
padding: 10px;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
color: #fff;
}
.header_left {
display: flex;
align-items: center;
.header_left_img {
width: 48px;
height: 48px;
box-sizing: border-box;
// padding-right: 10px;
}
.header_left_text {
font-weight: 500;
text-shadow: 0px 1.24px 6.21px rgba(25, 179, 250, 1);
}
}
.title {
color: #fff;
font-family: 'AlimamaShuHeiTi', sans-serif;
text-align: center;
}
.title>div:first-child {
/* 第一个子元素的样式 */
font-size: 38px;
letter-spacing: 0.1em;
}
.title>div:last-child {
/* 最后一个子元素的样式 */
font-size: 14px;
}
.right {
width: 100%;
height: 100%;
display: flex;
}
/* 顶部栏容器Flex 水平布局 + 垂直居中 */
.top-bar {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
// background-color: #1e2128;
color: #fff;
padding: 8px 16px;
font-size: 14px;
}
/* 左侧区域(天气 + 日期):自身也用 Flex 水平排列,确保元素在一行 */
.left-section {
display: flex;
align-items: center;
// margin-right: auto; /* 让右侧元素(管理系统)居右 */
}
.left-section img {
width: 32px;
height: 32px;
margin-right: 8px;
/* 图标与文字间距 */
}
/* 分割线(视觉分隔,可根据需求调整样式) */
.divider {
display: grid;
grid-template-rows: 1fr 1fr;
height: 100%;
/* 根据需要调整高度 */
padding: 14px 10px;
}
.divider .top-block {
width: 2px;
height: 7px;
background: #19b5fb;
align-self: start;
}
.divider .bottom-block {
width: 2px;
height: 7px;
background: #19b5fb;
align-self: end;
}
/* 右侧区域(管理系统):图标 + 文字水平排列 */
.right-section {
display: flex;
align-items: center;
font-family: 'AlimamaShuHeiTi', sans-serif;
font-size: 20px;
cursor: pointer;
}
.right-section img {
width: 20px;
height: 20px;
margin-right: 6px;
/* 图标与文字间距 */
}
</style>

View File

@ -0,0 +1,204 @@
<template>
<div class="leftPage">
<div class="topPage">
<Title title="项目公告" />
<div class="content">
<div class="content_item" v-for="item in 6" :key="item">
<div class="round">
<div class="sub_round"></div>
</div>
<div class="ellipsis">2025年6月23日 重庆市两江新区广场前期准备与审批完毕区广场前期准备与审批完毕前期准备与审批完毕区广场前期准备与审批完毕</div>
</div>
</div>
</div>
<div class="endPage">
<Title title="人员情况" />
<div class="map">
<img src="@/assets/projectLarge/map.svg" alt="">
</div>
<div class="attendance_tag">
<div class="tag_item" v-for="(item, index) in tagList" :key="index">
<img src="@/assets/projectLarge/people.svg" alt="">
<div class="tag_title">{{ item.title }}</div>
<div class="tag_info">
{{ item.number }}
<span style="font-size: 14px;">{{ index === 2 ? '%' : '人' }}</span>
</div>
</div>
</div>
<div class="attendance_list">
<div class="attendance_item subfont">
<div class="attendance_item_title"></div>
<div class="attendance_item_title">在岗人数</div>
<div class="attendance_item_title">出勤率</div>
<div class="attendance_item_title">出勤时间</div>
</div>
<div v-for="item in list" :key="item.title" class="attendance_item">
<div class="attendance_item_title">{{ item.title }}</div>
<div class="attendance_item_number">{{ item.number }} <span class="subfont">/{{ item.number }}</span></div>
<div class="attendance_item_rate">{{ item.attendanceRate }} %</div>
<div class="attendance_item_date subfont">{{ item.date }}</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue"
import Title from './title.vue'
const list = ref([
{ title: '智慧系统运维', number: 30, attendanceRate: 100, date: '2025-08-05 08:10' },
{ title: '智慧系统运维', number: 30, attendanceRate: 100, date: '2025-08-05 08:10' },
{ title: '智慧系统运维', number: 30, attendanceRate: 100, date: '2025-08-05 08:10' },
{ title: '智慧系统运维', number: 30, attendanceRate: 100, date: '2025-08-05 08:10' },
{ title: '智慧系统运维', number: 30, attendanceRate: 100, date: '2025-08-05 08:10' },
{ title: '智慧系统运维', number: 30, attendanceRate: 100, date: '2025-08-05 08:10' },
])
const tagList = ref([
{ title: '出勤人数', number: 259 },
{ title: '在岗人数', number: 100 },
{ title: '出勤率', number: 100 },
])
</script>
<style scoped lang="scss">
.leftPage {
display: flex;
flex-direction: column;
width: calc(25vw - 30px);
margin: 0 15px;
height: 100%;
.topPage,
.endPage {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
padding: 15px 0;
border: 1px solid rgba(29, 214, 255, 0.1);
box-sizing: border-box;
}
.endPage {
flex: 1;
margin-top: 23px;
}
}
.content {
max-height: 100px;
margin: 0 15px;
padding: 0 10px;
margin-top: 15px;
box-sizing: border-box;
overflow-y: auto;
&::-webkit-scrollbar-track {
background: rgba(204, 204, 204, 0.1);
border-radius: 10px;
}
&::-webkit-scrollbar-thumb {
background: rgba(29, 214, 255, 0.78);
border-radius: 10px;
}
.content_item {
display: flex;
align-items: flex-start;
gap: 10px;
// position: relative;
margin-bottom: 20px;
font-size: 14px;
font-weight: 400;
color: rgba(230, 247, 255, 1);
.ellipsis {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.5;
}
&:last-child {
margin-bottom: 0;
}
.round {
display: grid;
place-items: center;
margin-top: 3px;
width: 12px;
height: 12px;
border-radius: 50%;
background: rgba(29, 214, 255, 0.3);
.sub_round {
width: 6px;
height: 6px;
border-radius: 50%;
background: #1DD6FF;
}
}
}
}
.map {
margin-top: 15px;
}
.attendance_tag {
width: 100%;
display: flex;
justify-content: space-between;
padding: 0 30px;
margin-top: 15px;
.tag_item {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
border: 1px dashed rgba(29, 214, 255, 0.3);
padding: 10px 25px;
.tag_info {
font-size: 20px;
font-weight: 700;
color: rgba(230, 247, 255, 1);
text-shadow: 0px 1.24px 6.21px rgba(0, 190, 247, 1);
}
.tag_title {
font-size: 14px;
font-weight: 400;
color: rgba(230, 247, 255, 1);
}
}
}
.attendance_list {
padding: 0px 30px;
font-size: 14px;
.attendance_item {
display: grid;
grid-template-columns: 3fr 2fr 2fr 3fr;
margin-top: 20px;
}
}
.subfont {
color: rgba(138, 149, 165, 1);
}
</style>

View File

@ -0,0 +1,274 @@
<template>
<div class="leftPage">
<div class="topPage">
<Title title="项目概况" />
<div class="content">
<div class="content_item">项目名称智慧生态工地社区开发项目</div>
<div class="content_item">项目位置贵州省贵阳市乌当区具体地块编号01-123-11</div>
<div class="content_item">占地面积约10000亩</div>
<div class="content_item"> 土地性质城镇住宅用地兼容商业用地容积率2.5</div>
</div>
</div>
<div class="endPage">
<!-- 饼图容器 -->
<Title title="形象进度" />
<div ref="pieChartRef" class="echart" />
<!-- 折线图容器 -->
<div ref="lineChartRef" class="echart" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, nextTick } from "vue"
import Title from './title.vue'
import * as echarts from 'echarts';
// 饼图相关
const pieChartRef = ref<HTMLDivElement | null>(null);
let pieChart: any = null;
// 折线图相关
const lineChartRef = ref<HTMLDivElement | null>(null);
let lineChart: any = null;
// 饼图数据
const pieData = [
{ name: '桩点浇筑', value: 13 },
{ name: '水泥灌注', value: 7 },
{ name: '箱变安装', value: 40 },
{ name: '支架安装', value: 20 },
{ name: '组件安装', value: 20 },
]
// 折线图数据
const barData = {
xAxis: ['地块1', '地块2', '地块3', '地块4', '地块5', '地块6'],
series: [
{
name: '计划流转面积',
data: [70, 25, 45, 115, 70, 85]
},
{
name: '已流转面积',
data: [105, 30, 150, 65, 80, 200]
}
]
}
// 饼图配置
const pieOption = {
series: {
type: 'pie',
data: pieData,
radius: [50, 80],
itemStyle: {
borderColor: '#fff',
borderWidth: 1
},
label: {
alignTo: 'edge',
formatter: '{name|{b}}\n{percent|{c} %}',
minMargin: 10,
edgeDistance: 20,
lineHeight: 15,
rich: {
name: {
fontSize: 12,
color: '#fff'
},
percent: {
fontSize: 12,
color: '#fff'
}
}
},
legend: {
top: 'bottom'
},
}
};
// 柱状图配置
const barOption = {
legend: {
data: ['计划流转面积', '已流转面积'],
top: 0
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: barData.xAxis
},
yAxis: {
name: '单位m²',
type: 'value',
axisLabel: {
formatter: '{value}'
}
},
series: [
{
type: 'bar',
data: [], // 空数据仅用于承载markArea
markArea: {
silent: true, // 背景不响应交互
data: (() => {
const groupCount = 3; // 共3组6个月 ÷ 2
const groupWidth = 1.8; // 每组背景宽度覆盖2根柱子
const bgData = [];
for (let i = 0; i < groupCount; i++) {
const startX = i * 2 - 0.9; // 每组起始位置
const endX = startX + groupWidth; // 每组结束位置
bgData.push([
{ xAxis: startX, yAxis: 0 },
{ xAxis: endX, yAxis: 100 }
]);
}
return bgData;
})(),
itemStyle: {
color: 'rgba(255, 255, 255, 0.05)',
borderRadius: 4
}
}
},
{
name: '计划流转面积',
type: 'bar',
data: barData.series[0].data,
barWidth: 15, // 柱形宽度
itemStyle: {
color: 'rgb(29, 253, 253)'
},
},
{
name: '已流转面积',
type: 'bar',
data: barData.series[1].data,
barWidth: 15,
itemStyle: {
color: '#rgb(25, 181, 251)'
},
}
]
};
// 初始化饼图
const initPieChart = () => {
if (!pieChartRef.value) {
console.error('未找到饼图容器元素');
return;
}
pieChart = echarts.init(pieChartRef.value, null, {
renderer: 'canvas',
useDirtyRect: false
});
pieChart.setOption(pieOption);
}
// 初始化折线图
const initLineChart = () => {
if (!lineChartRef.value) {
console.error('未找到折线图容器元素');
return;
}
lineChart = echarts.init(lineChartRef.value, null, {
renderer: 'canvas',
useDirtyRect: false
});
lineChart.setOption(barOption);
}
// 响应窗口大小变化
const handleResize = () => {
if (pieChart) pieChart.resize();
if (lineChart) lineChart.resize();
};
// 组件挂载时初始化图表
onMounted(() => {
nextTick(() => {
initPieChart();
initLineChart();
window.addEventListener('resize', handleResize);
});
});
// 组件卸载时清理
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
if (pieChart) {
pieChart.dispose();
pieChart = null;
}
if (lineChart) {
lineChart.dispose();
lineChart = null;
}
});
</script>
<style scoped lang="scss">
.leftPage {
display: flex;
flex-direction: column;
width: calc(25vw - 30px);
margin: 0 15px;
height: 100%;
.topPage,
.endPage {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
padding: 15px 0;
border: 1px solid rgba(29, 214, 255, 0.1);
box-sizing: border-box;
}
.endPage {
flex: 1;
margin-top: 23px;
.echart {
width: 100%;
height: 100%;
}
}
}
.content {
margin: 10px 35px;
.content_item {
font-size: 14px;
font-weight: 400;
color: rgba(230, 247, 255, 1);
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
}
}
.ellipse {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.subfont {
color: rgba(138, 149, 165, 1);
}
</style>

View File

@ -0,0 +1,45 @@
<template>
<div class="title">
<div class="title_icon">
<img src="@/assets/projectLarge/section.svg" alt="">
<img src="@/assets/projectLarge/border.svg" alt="">
</div>
<div v-if="prefix">
<img src="@/assets/projectLarge/robot.svg" alt="" style="width: 20px; height: 20px;margin-right: 5px;">
</div>
<div>{{ title }}</div>
</div>
</template>
<script setup lang="ts">
defineProps({
title: {
type: String,
default: '标题'
},
prefix: {
type: Boolean,
default: false
}
})
</script>
<style scoped lang="scss">
.title {
width: 100%;
display: flex;
align-items: center;
gap: 3px;
font-family: 'AlimamaShuHeiTi', sans-serif;
.title_icon {
position: relative;
&>img:last-child {
position: absolute;
bottom: 4px;
left: 0;
}
}
}
</style>

View File

@ -0,0 +1,46 @@
<template>
<div class="large-screen">
<Header />
<div class="nav">
<leftPage />
<centerPage />
<rightPage />
</div>
</div>
</template>
<script setup lang="ts">
import Header from './components/header.vue';
import leftPage from './components/leftPage.vue';
import centerPage from './components/centerPage.vue';
import rightPage from './components/rightPage.vue';
</script>
<style lang="scss" scoped>
.large-screen {
width: 100vw;
height: 100vh;
background: url('@/assets/large/bg.png') no-repeat;
background-size: 100% 100%;
background-color: rgba(4, 7, 17, 1);
}
.nav {
display: flex;
gap: 15rpx;
width: 100%;
height: calc(100vh - 100px);
box-sizing: border-box;
color: #fff;
}
.nav_left,
.nav_right {
margin: 0 15px 15px 15px;
}
.nav_center {
margin-bottom: 15px;
}
</style>

View File

@ -3,6 +3,11 @@
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<el-card shadow="always"> <el-card shadow="always">
<el-form :model="queryForm" :inline="true"> <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-select>
</el-form-item>
<el-form-item label="表名" prop="sheet"> <el-form-item label="表名" prop="sheet">
<el-select v-model="queryForm.sheet" placeholder="选择表名" @change="changeSheet"> <el-select v-model="queryForm.sheet" placeholder="选择表名" @change="changeSheet">
<el-option v-for="item in sheets" :key="item" :label="item" :value="item" /> <el-option v-for="item in sheets" :key="item" :label="item" :value="item" />
@ -27,6 +32,26 @@
<el-form-item> <el-form-item>
<el-button type="primary" @click="handleExport()" v-hasPermi="['bidding:biddingLimitList:export']">导出excel</el-button> <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'"
icon="Edit"
@click="handleAudit"
v-hasPermi="['desibiddinggn:biddingLimitList:query']"
>审核</el-button
>
</el-form-item>
<el-form-item>
<el-button
type="primary"
icon="view"
@click="handleViewInfo"
v-hasPermi="['desibiddinggn:biddingLimitList:query']"
v-if="versionObj.status != 'draft'"
>查看流程</el-button
>
</el-form-item> -->
</el-form> </el-form>
</el-card> </el-card>
</transition> </transition>
@ -72,8 +97,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useUserStoreHook } from '@/store/modules/user'; import { useUserStoreHook } from '@/store/modules/user';
import { obtainAllVersionNumbers } from '@/api/contract/index'; import { BiddingImportExcelFile, getTreeLimit, biddingLimitListUpdate, sheetList, obtainAllVersionNumbers } from '@/api/bidding/biddingLimit';
import { BiddingImportExcelFile, getTreeLimit, biddingLimitListUpdate, sheetList } from '@/api/bidding/biddingLimit';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const userStore = useUserStoreHook(); const userStore = useUserStoreHook();
@ -87,7 +111,8 @@ const options = ref<any[]>([]);
const sheets = ref<any[]>([]); const sheets = ref<any[]>([]);
const tableData = ref<any[]>([]); const tableData = ref<any[]>([]);
const isExpandAll = ref(true); const isExpandAll = ref(true);
const versionObj = ref({});
const versionMap = new Map();
//获取版本号 //获取版本号
const getVersionNums = async () => { const getVersionNums = async () => {
try { try {
@ -96,15 +121,19 @@ const getVersionNums = async () => {
pageSize: 1000, pageSize: 1000,
pageNum: 1 pageNum: 1
}; };
const res = await obtainAllVersionNumbers(params); const res = await obtainAllVersionNumbers(params);
if (res.code == 200) { if (res.code == 200) {
options.value = res.data; options.value = res.data;
if (res.data.length > 0) { if (res.data.length > 0) {
queryForm.value.versions = res.data[0]; res.data.forEach((item: any) => {
versionMap.set(item.versions, item);
});
queryForm.value.versions = res.data[0].versions;
versionObj.value = res.data[0];
getSheetName(); getSheetName();
} else { } else {
queryForm.value.versions = ''; queryForm.value.versions = '';
versionObj.value = {};
} }
} }
} catch (error) { } catch (error) {
@ -112,7 +141,7 @@ const getVersionNums = async () => {
} }
}; };
//选择版本号 //选择版本号
const changeVersions = () => { const changeVersions = (val) => {
getSheetName(); getSheetName();
}; };
@ -123,10 +152,9 @@ const changeSheet = () => {
//获取表名 //获取表名
const getSheetName = async () => { const getSheetName = async () => {
try {
const params = { const params = {
projectId: currentProject.value?.id projectId: currentProject.value?.id,
// versions: queryForm.value.versions versions: queryForm.value.versions
}; };
const res = await sheetList(params); const res = await sheetList(params);
if (res.code == 200) { if (res.code == 200) {
@ -138,13 +166,10 @@ const getSheetName = async () => {
} }
getTableData(); getTableData();
} }
} catch (error) {}
}; };
//获取表格 //获取表格
const getTableData = async () => { const getTableData = async () => {
loading.value = true; loading.value = true;
console.log(212121);
const params = { const params = {
projectId: currentProject.value?.id, projectId: currentProject.value?.id,
sheet: queryForm.value.sheet sheet: queryForm.value.sheet
@ -152,9 +177,12 @@ const getTableData = async () => {
const res = await getTreeLimit(params); const res = await getTreeLimit(params);
loading.value = false; loading.value = false;
if (res.code == 200) { if (res.code == 200) {
if (res.data && res.data.length > 0) {
tableData.value = [res.data[0]]; tableData.value = [res.data[0]];
} else {
tableData.value = [];
}
} }
console.log(loading.value);
}; };
//修改单价 //修改单价
const handleSave = (row: any) => { const handleSave = (row: any) => {
@ -216,6 +244,7 @@ const listeningProject = watch(
() => currentProject.value?.id, () => currentProject.value?.id,
(nid, oid) => { (nid, oid) => {
getVersionNums(); getVersionNums();
// getSheetName();
} }
); );
const handleExport = () => { const handleExport = () => {
@ -228,11 +257,40 @@ const handleExport = () => {
`限价一览表${queryForm.value.sheet}.xlsx` `限价一览表${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: 'add',
sheets: sheets.value,
versions: versionObj.value
}
});
};
// 查看审核
const handleViewInfo = () => {
proxy.$tab.closePage(proxy.$route);
let id = versionMap.get(queryForm.value.versions).id;
proxy.$router.push({
path: `/approval/biddingLimit/indexEdit`,
query: {
id,
type: 'view',
sheets: sheets.value,
versions: versionObj.value
}
});
};
onUnmounted(() => { onUnmounted(() => {
listeningProject(); listeningProject();
}); });
onMounted(() => { onMounted(() => {
getSheetName(); getVersionNums();
// getSheetName();
}); });
</script> </script>

View 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 ComponentInternalInstance;
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 + '_costAccounting',
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>

View File

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

View File

@ -1,94 +1,53 @@
<template> <template>
<div class="p-2"> <div class="p-4 bg-gray-50 min-h-screen">
<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" class="max-w-6xl mx-auto rounded-xl overflow-hidden border-0" style="background-color: #ffffff">
<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> <template #header>
<el-row :gutter="10" class="mb8"> <div class="bg-blue-50 px-6 py-4 rounded-t-xl mb-0">
<el-col :span="1.5"> <h3 class="el-card__header-title text-lg font-semibold text-blue-800">投标项目信息填写</h3>
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['bidding:listOfWinningBids:add']">新增</el-button> <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>
</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>
<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-col :span="12">
<el-form-item label="项目名称" prop="projectName"> <el-input v-model="form.projectName" placeholder="请输入项目名称" /> </el-form-item <el-form-item label="汇率" prop="exchangeRate" class="rounded-lg border border-gray-100 p-1 mb-5">
></el-col> <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-col :span="12">
<el-form-item label="中标价" prop="winningBidOriginal"> <el-form-item label="币种" prop="currency" class="rounded-lg border border-gray-100 p-1 mb-5">
<el-input v-model="form.winningBidOriginal" placeholder="请输入中标价" /> </el-form-item <el-input v-model="form.currency" placeholder="请输入币种" />
></el-col> </el-form-item>
</el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="汇率" prop="exchangeRate"> <el-input v-model="form.exchangeRate" placeholder="请输入汇率" /> </el-form-item <el-form-item label="中标价(人民币)" prop="winningBid" class="rounded-lg border border-gray-100 p-1 mb-5">
></el-col> <!-- 人民币输入框添加readonly禁止手动修改 -->
<el-input v-model="form.winningBid" type="number" placeholder="根据美元中标价和汇率自动计算" readonly />
</el-form-item>
</el-col>
<!-- 其他表单项保持不变 -->
<el-col :span="12"> <el-col :span="12">
<el-form-item label="币种" prop="currency"> <el-input v-model="form.currency" placeholder="请输入币种" /> </el-form-item <el-form-item label="中标日期" prop="bidWinningDate" class="rounded-lg border border-gray-100 p-1 mb-5">
></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 <el-date-picker
clearable clearable
v-model="form.bidWinningDate" v-model="form.bidWinningDate"
@ -96,32 +55,49 @@
format="YYYY-MM-DD" format="YYYY-MM-DD"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
placeholder="请选择中标日期" placeholder="请选择中标日期"
> />
</el-date-picker> </el-form-item </el-form-item>
></el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="投标保证金" prop="bidDeposit"> <el-input v-model="form.bidDeposit" placeholder="请输入投标保证金" /> </el-form-item <el-form-item label="投标保证金(人民币)" prop="bidDeposit" class="rounded-lg border border-gray-100 p-1 mb-5">
></el-col> <el-input v-model="form.bidDeposit" type="number" placeholder="请输入投标保证金" />
</el-form-item>
</el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="是否退还" prop="whetherSendBack"> <el-form-item label="是否退还" prop="whetherSendBack" class="rounded-lg border border-gray-100 p-1 mb-5">
<el-input v-model="form.whetherSendBack" placeholder="请输入是否退还" /> </el-form-item <el-radio-group v-model="form.whetherSendBack">
></el-col> <el-radio label="是" border></el-radio>
<el-col :span="12" <el-radio label="否" border></el-radio>
><el-form-item label="建设单位" prop="construction"> <el-input v-model="form.construction" placeholder="请输入建设单位" /> </el-form-item </el-radio-group>
></el-col> </el-form-item>
</el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="总造价" prop="totalCost"> <el-input v-model="form.totalCost" placeholder="请输入总造价" /> </el-form-item <el-form-item label="所属主体" prop="subject" class="rounded-lg border border-gray-100 p-1 mb-5">
></el-col> <el-input v-model="form.subject" placeholder="请输入所属主体" />
</el-form-item>
</el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="立项申请人" prop="projectApplicant"> <el-form-item label="建设单位" prop="construction" class="rounded-lg border border-gray-100 p-1 mb-5">
<el-input v-model="form.projectApplicant" placeholder="请输入立项申请人" /> </el-form-item <el-input v-model="form.construction" placeholder="请输入建设单位" />
></el-col> </el-form-item>
<el-col :span="12" </el-col>
><el-form-item label="立项部门" prop="projectApplicantDept"> <el-col :span="12">
<el-input v-model="form.projectApplicantDept" placeholder="请输入立项部门" /> </el-form-item <el-form-item label="总造价" prop="totalCost" class="rounded-lg border border-gray-100 p-1 mb-5">
></el-col> <el-input v-model="form.totalCost" placeholder="请输入总造价" />
<el-col :span="12" </el-form-item>
><el-form-item label="立项申请日期" prop="projectApplicantTime"> </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 <el-date-picker
clearable clearable
v-model="form.projectApplicantTime" v-model="form.projectApplicantTime"
@ -129,57 +105,61 @@
format="YYYY-MM-DD" format="YYYY-MM-DD"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
placeholder="请选择立项申请日期" 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="projectStatus" class="rounded-lg border border-gray-100 p-1 mb-5">
<el-input v-model="form.projectStatus" placeholder="请输入项目状态(如:进行中/已完成)" />
</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-date-picker> </el-form-item 确认提交
></el-col> </el-button>
<el-col :span="12" <el-button type="default" @click="resetForm" class="ml-6 rounded-full px-8" size="large"> 重置 </el-button>
><el-form-item label="项目编号" prop="projectNumbering"> </el-col>
<el-input v-model="form.projectNumbering" placeholder="请输入项目编号" /> </el-form-item
></el-col>
</el-row> </el-row>
</el-form> </el-form>
<template #footer> </el-card>
<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> </div>
</template> </template>
<script setup name="ListOfWinningBids" lang="ts"> <script setup name="ListOfWinningBidsForm" lang="ts">
import { import { ref, reactive, toRefs, watch, onMounted, onUnmounted, getCurrentInstance, ComponentInternalInstance, computed } from 'vue';
listListOfWinningBids, import { addListOfWinningBids, updateListOfWinningBids, listListOfWinningBids, getListOfWinningBids } from '@/api/bidding/listOfWinningBids';
getListOfWinningBids, import { ListOfWinningBidsVO, ListOfWinningBidsForm } from '@/api/bidding/listOfWinningBids/types';
delListOfWinningBids,
addListOfWinningBids,
updateListOfWinningBids
} from '@/api/bidding/listOfWinningBids';
import { ListOfWinningBidsVO, ListOfWinningBidsQuery, ListOfWinningBidsForm } from '@/api/bidding/listOfWinningBids/types';
import { useUserStoreHook } from '@/store/modules/user'; import { useUserStoreHook } from '@/store/modules/user';
import { ElFormInstance, ElMessage } from 'element-plus';
// 获取组件实例
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// 获取用户 store // 用户状态管理
const userStore = useUserStoreHook(); const userStore = useUserStoreHook();
// 从 store 中获取当前选中的项目 // 当前选中项目从store获取
const currentProject = computed(() => userStore.selectedProject); 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 listOfWinningBidsFormRef = ref<ElFormInstance>();
// 加载状态
const dialog = reactive<DialogOption>({ const buttonLoading = ref(false);
visible: false, const isDisabled = ref(false);
title: '' // 表单初始数据
});
const initFormData: ListOfWinningBidsForm = { const initFormData: ListOfWinningBidsForm = {
id: undefined, id: undefined,
projectId: currentProject.value?.id, projectId: currentProject.value?.id,
@ -201,144 +181,165 @@ const initFormData: ListOfWinningBidsForm = {
processStatus: undefined, processStatus: undefined,
projectNumbering: undefined projectNumbering: undefined
}; };
const data = reactive<PageData<ListOfWinningBidsForm, ListOfWinningBidsQuery>>({
form: { ...initFormData }, // 表单数据与验证规则
queryParams: { const data = reactive({
pageNum: 1, form: { ...initFormData } as ListOfWinningBidsForm,
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: { rules: {
id: [{ required: true, message: '不能为空', trigger: 'blur' }], projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
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 { queryParams, form, rules } = toRefs(data); // 解构响应式数据
const { form, rules } = toRefs(data);
/**
* 计算人民币中标价
* 显式触发的计算函数,确保执行时机可靠
*/
const calculateWinningBid = () => {
// 确保数据类型正确
const dollarAmount = Number(form.value.winningBidOriginal);
const rate = Number(form.value.exchangeRate);
/** 查询中标项目一览列表 */ // 验证输入有效性
const getList = async () => { if (isNaN(dollarAmount) || isNaN(rate) || dollarAmount <= 0 || rate <= 0) {
loading.value = true; form.value.winningBid = undefined;
const res = await listListOfWinningBids(queryParams.value); return;
listOfWinningBidsList.value = res.rows; }
total.value = res.total;
loading.value = false; // 计算并保留2位小数
const result = dollarAmount * rate;
form.value.winningBid = Number(result.toFixed(2));
}; };
/** 取消按钮 */ /**
const cancel = () => { * 页面初始化 - 获取已有数据(如存在)
reset(); */
dialog.visible = false; const initData = async () => {
}; try {
if (currentProject.value?.id) {
/** 表单重置 */ const res = await listListOfWinningBids({ projectId: currentProject.value.id });
const reset = () => { if (res.code == 200) {
form.value = { ...initFormData }; console.log(res.data);
listOfWinningBidsFormRef.value?.resetFields(); resetForm();
}; if (!res.data) {
isDisabled.value = false;
/** 搜索按钮操作 */ return;
const handleQuery = () => { } else {
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); Object.assign(form.value, res.data);
dialog.visible = true; }
dialog.title = '修改中标项目一览'; isDisabled.value = true;
}
}
} catch (error) {
// ElMessage.error('初始化数据失败');
}
}; };
/** 提交按钮 */ /**
* 提交表单
*/
const submitForm = () => { const submitForm = () => {
listOfWinningBidsFormRef.value?.validate(async (valid: boolean) => { listOfWinningBidsFormRef.value?.validate(async (valid: boolean) => {
if (valid) { if (valid) {
buttonLoading.value = true; buttonLoading.value = true;
if (form.value.id) { try {
await updateListOfWinningBids(form.value).finally(() => (buttonLoading.value = false)); // 提交前确保计算正确
} else { calculateWinningBid();
await addListOfWinningBids(form.value).finally(() => (buttonLoading.value = false)); form.value.projectId = currentProject.value?.id;
await addListOfWinningBids(form.value);
isDisabled.value = true;
ElMessage.success('提交成功');
} catch (error) {
ElMessage.error('提交失败,请重试');
console.error('提交表单失败:', error);
} finally {
buttonLoading.value = false;
} }
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
} }
}); });
}; };
/**
/** 删除按钮操作 */ * 重置表单
const handleDelete = async (row?: ListOfWinningBidsVO) => { */
const _ids = row?.id || ids.value; const resetForm = () => {
await proxy?.$modal.confirm('是否确认删除中标项目一览编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false)); form.value = { ...initFormData, projectId: currentProject.value?.id };
await delListOfWinningBids(_ids); listOfWinningBidsFormRef.value?.resetFields();
proxy?.$modal.msgSuccess('删除成功');
await getList();
}; };
/**
/** 导出按钮操作 */ * 监听项目ID变化 - 重新初始化数据
const handleExport = () => { */
proxy?.download( const projectIdWatcher = watch(
'bidding/listOfWinningBids/export',
{
...queryParams.value
},
`listOfWinningBids_${new Date().getTime()}.xlsx`
);
};
//监听项目id刷新数据
const listeningProject = watch(
() => currentProject.value?.id, () => currentProject.value?.id,
(nid, oid) => { (newId) => {
getList(); if (newId) {
form.value.projectId = newId;
initData();
}
} }
); );
onUnmounted(() => { // 页面挂载时初始化
listeningProject();
});
onMounted(() => { onMounted(() => {
getList(); initData();
});
// 页面卸载时清除监听
onUnmounted(() => {
projectIdWatcher();
}); });
</script> </script>
<style scoped>
/* 全局背景色:柔和灰色,区分页面与卡片 */
.bg-gray-50 {
background-color: #f9fafb;
}
/* 表单项优化hover效果+边框过渡,提升交互感 */
.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);
}
/* 输入框/选择器统一圆角 */
.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;
}
</style>

View File

@ -0,0 +1,314 @@
<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">
<!-- <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-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="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="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>
</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="500px" append-to-body>
<el-form ref="expensesContractFormRef" :model="form" :rules="rules" label-width="80px">
<!-- <el-form-item label="项目ID" prop="projectId">
<el-input v-model="form.projectId" placeholder="请输入项目ID" />
</el-form-item> -->
<el-form-item label="合同编号" prop="contractCode">
<el-input v-model="form.contractCode" placeholder="请输入合同编号" />
</el-form-item>
<el-form-item label="供应商" prop="contractSupplier">
<el-input v-model="form.contractSupplier" 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="请输入合同金额" />
</el-form-item>
<el-form-item label="招标Id" prop="tenderId">
<el-input v-model="form.tenderId" placeholder="请输入招标Id" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</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>
<FileList v-model="fileListVisible" :fileList="fileList" />
</div>
</template>
<script setup name="ExpensesContract" lang="ts">
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 expensesContractList = ref<ExpensesContractVO[]>([]);
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 fileListVisible = ref(false); // 控制附件列表对话框的显示
const fileList = ref<Array<any>>([]); // 文件列表
const userStore = useUserStore();
const queryFormRef = ref<ElFormInstance>();
const expensesContractFormRef = ref<ElFormInstance>();
const currentProject = computed(() => userStore.selectedProject);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: ExpensesContractForm = {
id: undefined,
projectId: undefined,
contractCode: undefined,
contractType: undefined,
contractSupplier: undefined,
contractedContent: undefined,
amount: undefined,
tenderId: undefined,
remark: undefined,
}
const data = reactive<PageData<ExpensesContractForm, ExpensesContractQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
projectId: currentProject.value?.id,
contractCode: undefined,
contractType: undefined,
contractSupplier: undefined,
contractedContent: undefined,
amount: undefined,
tenderId: undefined,
params: {
}
},
rules: {
id: [
{ required: true, message: "主键ID不能为空", trigger: "blur" }
],
projectId: [
{ required: true, message: "项目ID不能为空", trigger: "blur" }
],
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询支出合同列表 */
const getList = async () => {
loading.value = true;
const res = await listExpensesContract(queryParams.value);
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);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = "添加支出合同";
}
/** 修改按钮操作 */
const handleUpdate = async (row?: ExpensesContractVO) => {
reset();
const _id = row?.id || ids.value[0]
const res = await getExpensesContract(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = "修改支出合同";
}
/** 提交按钮 */
const submitForm = () => {
expensesContractFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateExpensesContract(form.value).finally(() => buttonLoading.value = false);
} else {
await addExpensesContract(form.value).finally(() => buttonLoading.value = false);
}
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 delExpensesContract(_ids);
proxy?.$modal.msgSuccess("删除成功");
await getList();
}
/** 导出按钮操作 */
const handleExport = () => {
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("获取文件列表失败");
});
}
onMounted(() => {
getList();
});
// 监听项目id刷新数据
const listeningProject = watch(
() => currentProject.value?.id,
(nid, oid) => {
queryParams.value.projectId = nid;
form.value.projectId = nid;
getList();
}
);
onUnmounted(() => {
listeningProject();
});
</script>

View File

@ -0,0 +1,303 @@
<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">
<!-- <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-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">
<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>
</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="500px" append-to-body>
<el-form ref="incomeContractFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="项目ID" prop="projectId">
<el-input v-model="form.projectId" placeholder="请输入项目ID" />
</el-form-item>
<el-form-item label="合同编号" prop="contractCode">
<el-input v-model="form.contractCode" placeholder="请输入合同编号" />
</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="请输入合同金额" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</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>
<FileList v-model="fileListVisible" :fileList="fileList" />
</div>
</template>
<script setup name="IncomeContract" lang="ts">
import { listIncomeContract, getIncomeContract, delIncomeContract, addIncomeContract, updateIncomeContract, getFileList } 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';
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
const currentProject = computed(() => userStore.selectedProject);
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);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const fileListVisible = ref(false); // 控制附件列表对话框的显示
const queryFormRef = ref<ElFormInstance>();
const incomeContractFormRef = ref<ElFormInstance>();
const fileList = ref<Array<any>>([]); // 文件列表
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: IncomeContractForm = {
id: undefined,
projectId: undefined,
contractCode: undefined,
contractType: undefined,
contractOwner: undefined,
contractedContent: undefined,
amount: undefined,
remark: undefined,
}
const data = reactive<PageData<IncomeContractForm, IncomeContractQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
projectId: currentProject.value?.id,
contractCode: undefined,
contractType: undefined,
contractOwner: undefined,
contractedContent: undefined,
amount: undefined,
params: {
}
},
rules: {
id: [
{ required: true, message: "主键ID不能为空", trigger: "blur" }
],
projectId: [
{ required: true, message: "项目ID不能为空", trigger: "blur" }
],
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询收入合同列表 */
const getList = async () => {
loading.value = true;
const res = await listIncomeContract(queryParams.value);
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);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = "添加收入合同";
}
/** 修改按钮操作 */
const handleUpdate = async (row?: IncomeContractVO) => {
reset();
const _id = row?.id || ids.value[0]
const res = await getIncomeContract(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = "修改收入合同";
}
/** 提交按钮 */
const submitForm = () => {
incomeContractFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateIncomeContract(form.value).finally(() => buttonLoading.value = false);
} else {
await addIncomeContract(form.value).finally(() => buttonLoading.value = false);
}
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 delIncomeContract(_ids);
proxy?.$modal.msgSuccess("删除成功");
await getList();
}
/** 导出按钮操作 */
const handleExport = () => {
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("获取文件列表失败");
});
}
onMounted(() => {
getList();
});
// 监听项目id刷新数据
const listeningProject = watch(
() => currentProject.value?.id,
(nid, oid) => {
queryParams.value.projectId = nid;
form.value.projectId = nid;
getList();
}
);
onUnmounted(() => {
listeningProject();
});
</script>

408
src/views/ctr/index.vue Normal file
View File

@ -0,0 +1,408 @@
<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="项目名称">
<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-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="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>
</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 { 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 { 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 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' }],
payRatio: [{ required: true, message: '请输入付款比例', trigger: 'blur' }],
};
const project = computed(() => {
console.log(111);
return JSON.parse(localStorage.getItem("selectedProject"))
});
const checkContractType = (type) => {
contract_type.value = type;
form.value.contract_type = type;
active.value = 1;
form.value.step = active.value;
};
const onUploadSuccess = (data) => {
fileList.value = data
}
const back = async (reset) => {
console.log(active.value);
if (reset) {
await ElMessageBox.confirm('返回上一步将清空目前填写的内容,确定返回?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
resetForm();
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);
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);
};
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('请先选择合同类型');
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.winningBidder = row.winningBidder;
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 });
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;
}).catch(() => {
localStorage.removeItem("tempContractForm");
});
}
});
</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>

View File

@ -31,7 +31,7 @@
</el-form-item> </el-form-item>
<el-form-item label="专业" prop="user_major" class="mb-4"> <el-form-item label="专业" prop="user_major" class="mb-4">
<el-select v-model="form.user_major" placeholder="请选择专业" class="transition-all duration-300 border-gray-300"> <el-select v-model="form.user_major" placeholder="请选择专业" class="transition-all duration-300 border-gray-300">
<el-option v-for="item in des_user_major" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in des_user_major" :key="item.userMajor" :label="item.userMajorName" :value="item.userMajor" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="电话" prop="phone" class="mb-4"> <el-form-item label="电话" prop="phone" class="mb-4">
@ -42,7 +42,6 @@
</el-form-item> </el-form-item>
</div> </div>
</div> </div>
<!-- 资料文件区域单独表单校验 --> <!-- 资料文件区域单独表单校验 -->
<div class="mb-6"> <div class="mb-6">
<div class="flex items-center justify-between mb-4"> <div class="flex items-center justify-between mb-4">
@ -152,7 +151,7 @@ import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
import { ComponentInternalInstance, nextTick, ref, reactive, computed, toRefs, onMounted } from 'vue'; import { ComponentInternalInstance, nextTick, ref, reactive, computed, toRefs, onMounted } from 'vue';
import { useUserStoreHook } from '@/store/modules/user'; import { useUserStoreHook } from '@/store/modules/user';
import { systemUserList } from '@/api/design/appointment'; import { systemUserList } from '@/api/design/appointment';
import { extractBatch, extractDetail } from '@/api/design/Professional'; import { extractBatch, extractDetail, extractUserMajor } from '@/api/design/Professional';
import { listVolumeCatalog } from '@/api/design/volumeCatalog'; import { listVolumeCatalog } from '@/api/design/volumeCatalog';
import { catalogList } from '@/api/design/designChange'; import { catalogList } from '@/api/design/designChange';
import { getUser } from '@/api/system/user'; import { getUser } from '@/api/system/user';
@ -197,7 +196,8 @@ const userInfo = ref({
phonenumber: '', phonenumber: '',
userId: '' userId: ''
}); });
const { des_user_major } = toRefs<any>(proxy?.useDict('des_user_major')); // const { des_user_major } = toRefs<any>(proxy?.useDict('des_user_major'));
const des_user_major = ref([]);
const buttonLoading = ref(false); const buttonLoading = ref(false);
const loading = ref(true); const loading = ref(true);
const disableAll = ref(false); const disableAll = ref(false);
@ -440,7 +440,14 @@ const getDeptAllUser = async (deptId: any) => {
ElMessage.error('获取用户列表失败'); ElMessage.error('获取用户列表失败');
} }
}; };
// 获取专业
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);
}
};
/** 回显表单数据(编辑/查看/审批场景) */ /** 回显表单数据(编辑/查看/审批场景) */
const byProjectIdAll = async () => { const byProjectIdAll = async () => {
loading.value = true; loading.value = true;
@ -532,6 +539,7 @@ onMounted(() => {
// 编辑/查看/审批场景:加载已有数据 // 编辑/查看/审批场景:加载已有数据
const { type } = routeParams.value; const { type } = routeParams.value;
await getMajor();
if (type === 'update' || type === 'view' || type === 'approval') { if (type === 'update' || type === 'view' || type === 'approval') {
await getDeptAllUser(userStore.deptId); await getDeptAllUser(userStore.deptId);
await byProjectIdAll(); await byProjectIdAll();

View File

@ -220,23 +220,17 @@
</div> </div>
<!-- 提交按钮区域 --> <!-- 提交按钮区域 -->
<div class="flex justify-center space-x-6 mt-8 pt-6 border-t border-gray-100"> <div v-if="!disabledForm" class="flex justify-center space-x-6 mt-8 pt-6 border-t border-gray-100">
<el-button <el-button
type="primary" type="primary"
size="large" size="large"
v-hasPermi="['design:user:batch']" v-hasPermi="['design:user:batch']"
@click="submitForm" @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" 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>确认提交 <i class="el-icon-check mr-2"></i>确认提交
</el-button> </el-button>
<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">
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>重置 <i class="el-icon-refresh mr-2"></i>重置
</el-button> </el-button>
</div> </div>

View File

@ -7,8 +7,7 @@
<el-form :model="state.queryForm" :inline="true"> <el-form :model="state.queryForm" :inline="true">
<el-form-item label="版本号" prop="versions"> <el-form-item label="版本号" prop="versions">
<el-select v-model="state.queryForm.versions" placeholder="选择版本号"> <el-select v-model="state.queryForm.versions" placeholder="选择版本号">
<el-option v-for="item in state.options" :key="item.versions" :label="item.versions" <el-option v-for="item in state.options" :key="item.versions" :label="item.versions" :value="item.versions" />
:value="item.versions" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="表名" prop="sheet"> <el-form-item label="表名" prop="sheet">
@ -25,13 +24,23 @@
<el-form-item> <el-form-item>
<el-upload ref="uploadRef" class="upload-demo" :http-request="importExcel" :show-file-list="false"> <el-upload ref="uploadRef" class="upload-demo" :http-request="importExcel" :show-file-list="false">
<template #trigger> <template #trigger>
<el-button v-if="Object.keys(state.versionsData).length === 0 || state.versionsData.status == 'cancel' ||state.versionsData.status == 'back'" type="primary">导入excel</el-button> <el-button
v-if="
Object.keys(state.versionsData).length === 0 || state.versionsData.status == 'cancel' || state.versionsData.status == 'back'
"
type="primary"
>导入excel</el-button
>
</template> </template>
</el-upload> </el-upload>
<el-button v-if="state.versionsData.status == 'draft'" type="primary" con="edit" <el-button v-if="state.versionsData.status == 'draft'" type="primary" con="edit" @click="clickApprovalSheet()">审核</el-button>
@click="clickApprovalSheet()">审核</el-button> <el-button
<el-button v-if="state.versionsData.status == 'waiting' || state.versionsData.status == 'finish'" v-if="state.versionsData.status == 'waiting' || state.versionsData.status == 'finish'"
icon="view" @click="lookApprovalFlow()" type="warning">查看流程</el-button> icon="view"
@click="lookApprovalFlow()"
type="warning"
>查看流程</el-button
>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
@ -39,36 +48,47 @@
<el-form :model="state.queryForm" :inline="true"> <el-form :model="state.queryForm" :inline="true">
<el-form-item label="版本号" prop="versions"> <el-form-item label="版本号" prop="versions">
<el-select v-model="state.queryForm.versions" placeholder="选择版本号" @change="handleChangeVersion"> <el-select v-model="state.queryForm.versions" placeholder="选择版本号" @change="handleChangeVersion">
<el-option v-for="item in state.options" :key="item.versions" :label="item.versions" <el-option v-for="item in state.options" :key="item.versions" :label="item.versions" :value="item.versions" />
:value="item.versions" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-upload ref="uploadRef" class="upload-demo" :http-request="importExcel" :show-file-list="false" style="margin-right: 10px;"> <el-upload ref="uploadRef" class="upload-demo" :http-request="importExcel" :show-file-list="false" style="margin-right: 10px">
<template #trigger> <template #trigger>
<el-button type="primary">导入excel</el-button> <el-button type="primary">导入excel</el-button>
</template> </template>
</el-upload> </el-upload>
<el-button v-if="state.versionsData.status == 'draft'" type="primary" con="edit" <el-button v-if="state.versionsData.status == 'draft'" type="primary" con="edit" @click="clickApprovalSheet()">审核</el-button>
@click="clickApprovalSheet()">审核</el-button> <el-button
<el-button v-if="state.versionsData.status == 'waiting' || state.versionsData.status == 'finish'" v-if="state.versionsData.status == 'waiting' || state.versionsData.status == 'finish'"
icon="view" @click="lookApprovalFlow()" type="warning">查看流程</el-button> icon="view"
@click="lookApprovalFlow()"
type="warning"
>查看流程</el-button
>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
<el-table v-if="index < 3" :ref="(el) => (tableRef[index] = el)" :data="state.tableData" <el-table
v-loading="state.loading.list" stripe :row-class-name="state.tableData.length === 0 ? 'table-null' : ''" v-if="index < 3"
style="width: 100%; margin-bottom: 20px; height: calc(100vh - 305px)" row-key="id" lazy border :ref="(el) => (tableRef[index] = el)"
:default-expand-all="true"> :data="state.tableData"
v-loading="state.loading.list"
stripe
:row-class-name="state.tableData.length === 0 ? 'table-null' : ''"
style="width: 100%; margin-bottom: 20px; height: calc(100vh - 305px)"
row-key="id"
lazy
border
:default-expand-all="true"
>
<el-table-column prop="num" label="编号" /> <el-table-column prop="num" label="编号" />
<el-table-column prop="name" label="工程或费用名称" /> <el-table-column prop="name" label="工程或费用名称" />
<el-table-column prop="unit" label="单位" />
<el-table-column prop="specification" label="规格" /> <el-table-column prop="specification" label="规格" />
<el-table-column prop="unit" label="单位" />
<el-table-column prop="quantity" label="数量" /> <el-table-column prop="quantity" label="数量" />
<el-table-column prop="remark" label="备注" /> <el-table-column prop="remark" label="备注" />
</el-table> </el-table>
<el-table v-if="index == 3" :data="state.tableData" <el-table v-if="index == 3" :data="state.tableData" style="width: 100%; margin-bottom: 20px; height: calc(100vh - 305px)" row-key="id" border>
style="width: 100%; margin-bottom: 20px; height: calc(100vh - 305px)" row-key="id" border>
<el-table-column prop="num" label="编号" /> <el-table-column prop="num" label="编号" />
<el-table-column prop="name" label="名称" /> <el-table-column prop="name" label="名称" />
<el-table-column prop="specification" label="规格" /> <el-table-column prop="specification" label="规格" />

View File

@ -31,9 +31,9 @@
placeholder="请选择实际完成时间" placeholder="请选择实际完成时间"
/> />
</el-form-item> </el-form-item>
<el-form-item label="手续材料" prop="formalitiesUrl"> <!-- <el-form-item label="手续材料" prop="formalitiesUrl">
<el-input v-model="queryParams.formalitiesUrl" placeholder="请输入手续材料" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.formalitiesUrl" placeholder="请输入手续材料" clearable @keyup.enter="handleQuery" />
</el-form-item> </el-form-item> -->
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button> <el-button icon="Refresh" @click="resetQuery">重置</el-button>

View File

@ -4,16 +4,12 @@
<span class="progress_title">{{ title }}</span> <span class="progress_title">{{ title }}</span>
<span :class="percentageClass" class="roboto">{{ percentageChange }}</span> <span :class="percentageClass" class="roboto">{{ percentageChange }}</span>
</div> </div>
<div class="roboto"> <div class="roboto" v-if="isShowPrice">
<span>{{ value }}</span> <span>{{ value }}</span>
<span>{{ unit }}</span> <span>{{ unit }}</span>
</div> </div>
<div class="my_el_progress"> <div class="my_el_progress">
<el-progress <el-progress :percentage="progressPercentage" :color="progressColor" :show-text="false" />
:percentage="progressPercentage"
:color="progressColor"
:show-text="false"
/>
</div> </div>
</div> </div>
</template> </template>
@ -56,6 +52,11 @@ const props = defineProps({
progressColor: { progressColor: {
type: String, type: String,
default: 'rgba(255, 77, 79, 1)' default: 'rgba(255, 77, 79, 1)'
},
// 是否显示价格
isShowPrice: {
type: Boolean,
default: true
} }
}); });
@ -72,6 +73,7 @@ const percentageClass = computed(() => {
.progress_component { .progress_component {
width: 100%; width: 100%;
height: 100%; height: 100%;
margin-bottom: 10px;
:deep(.el-progress-bar__outer) { :deep(.el-progress-bar__outer) {
background-color: transparent; background-color: transparent;
@ -117,4 +119,3 @@ const percentageClass = computed(() => {
} }
} }
</style> </style>

View File

@ -0,0 +1,167 @@
<template>
<div class="stat-card" :style="customStyles">
<!-- 标题区域 -->
<div class="stat-card__title">{{ title }}</div>
<!-- 数值区域 -->
<div class="stat-card__value-container">
<span class="stat-card__value">{{ formattedValue }}</span>
<span class="stat-card__unit">{{ unit }}</span>
</div>
<!-- 底部信息区域 -->
<div class="stat-card__footer">
<div class="stat-card__trend">
<img
class="stat-card__trend-icon"
:src="'/src/assets/large/' + trendIcon+'.png'"
:alt="trendDirection === 'up' ? '上升' : '下降'"
>
<span class="stat-card__trend-text">{{ trendText }}</span>
</div>
<img
class="stat-card__badge"
:src="'/src/assets/large/'+badgeIcon+'.png'"
alt="徽章图标"
>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue';
// 定义组件属性
const props = defineProps({
// 卡片标题
title: {
type: String,
default: '收入合同'
},
// 数值
value: {
type: Number,
default: 205805.17
},
// 单位
unit: {
type: String,
default: '万元'
},
// 增长率
growthRate: {
type: Number,
default: 3.2
},
// 增长对比周期
period: {
type: String,
default: '较上月'
},
// 趋势方向 (up/down)
trendDirection: {
type: String,
default: 'up',
validator: (value) => ['up', 'down'].includes(value)
},
// 趋势图标
trendIcon: {
type: String,
default: 'up'
},
// 徽章图标
badgeIcon: {
type: String,
default: 'top1'
},
// 卡片自定义样式
customStyles: {
type: Object,
default: () => ({})
}
});
// 格式化数值为带千分位的字符串
const formattedValue = computed(() => {
return props.value.toLocaleString('zh-CN', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
});
// 生成趋势文本
const trendText = computed(() => {
return `${props.growthRate}% ${props.period}`;
});
</script>
<style lang="scss" scoped>
.stat-card {
width: 225px;
height: 147px;
background-color: rgba(29, 214, 255, 0.1);
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 20px;
box-sizing: border-box;
border: 1px solid rgba(29, 214, 255, 0.1);
border-radius: 4px; // 增加轻微圆角,提升视觉效果
&__title {
font-size: 14px;
color: #8FABBF;
line-height: 20px;
}
&__value-container {
display: flex;
align-items: baseline;
}
&__value {
font-size: 24px;
color: #fff;
line-height: 30px;
margin-right: 5px;
font-weight: bold;
}
&__unit {
color: #8FABBF;
font-size: 14px;
}
&__footer {
display: flex;
justify-content: space-between;
align-items: center;
}
&__trend {
display: flex;
align-items: center;
}
&__trend-icon {
width: 12px;
height: 12px;
margin-right: 4px;
}
&__trend-text {
font-size: 14px;
color: #8FABBF;
}
&__badge {
width: 40px;
height: 40px;
}
}
// 为下降趋势添加不同颜色
:deep(.stat-card__trend-text) {
color: v-bind('trendDirection === "up" ? "#8FABBF" : "#ff4d4f"');
}
</style>

View File

@ -0,0 +1,45 @@
<template>
<div class="bottom_box">
<div class="bottom_box_title">收入合同</div>
<div>
<span class="bottom_box_number">205,805.17</span>
<span>万元</span>
</div>
<div class="bottom_box_bottom">
<el-progress :percentage="50" color="rgba(255, 147, 42, 1)" />
</div>
<div class="bottom_box_text">
成本率
</div>
</div>
</template>
<script setup>
</script>
<style lang="scss">
.bottom_box {
width: 225px;
height: 147px;
height: 100%;
padding: 10px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-around;
.bottom_box_title,
.bottom_box_text {
color: rgba(143, 171, 191, 1);
font-size: 14px;
line-height: 20px;
}
.bottom_box_number {
font-size: 24px;
color: #fff;
line-height: 30px;
}
}
</style>

View File

@ -1,8 +1,55 @@
<template> <template>
<div class="centerPage"> <div class="centerPage">
<div>
<div style="height: 147px;width: 100%;display: flex;justify-content: space-between;">
<!-- <div class="top_box">
<div class="top_box_title">收入合同</div>
<div>
<span class="top_box_number">205,805.17</span>
<span>万元</span>
</div>
<div class="top_box_bottom">
<div>
<img class="up_img" src="@/assets/large/up.png" alt=""></img>
<span class="top_box_title"> 3.2% 较上月</span>
</div>
<img class="top_img" src="@/assets/large/top1.png" alt=""></img>
</div>
</div> -->
<RevenueContractCard title="收入合同" :value="156234.89" :growthRate="-1.5" trendDirection="up" trendIcon="up"
badgeIcon="top1" period="较上月" />
<RevenueContractCard title="支出合同" :value="156234.89" :growthRate="-1.5" trendDirection="up" trendIcon="up"
badgeIcon="top2" period="较上月" />
<RevenueContractCard title="合同利润" :value="156234.89" :growthRate="-1.5" trendDirection="up" trendIcon="down"
badgeIcon="top3" period="较上月" />
<RevenueContractCard title="工程变更" :value="156234.89" :growthRate="-1.5" trendDirection="up" trendIcon="up"
badgeIcon="top4" period="较上月" />
</div>
</div>
<div class="centerPage_map"> <div class="centerPage_map">
<div ref="mapRef" class="map-container" style="width: 100%; height: 100%" /> <div ref="mapRef" class="map-container" style="width: 100%; height: 100%" />
</div> </div>
<div>
<div style="height: 147px;width: 100%;display: flex;justify-content: space-between;">
<!-- <div class="bottom_box">
<div class="bottom_box_title">收入合同</div>
<div>
<span class="bottom_box_number">205,805.17</span>
<span>万元</span>
</div>
<div class="bottom_box_bottom">
<el-progress :percentage="50" color="rgba(255, 147, 42, 1)" />
</div>
<div class="bottom_box_text">
成本率
</div>
</div> -->
<bottomboxconpoent> </bottomboxconpoent>
<bottomboxconpoent> </bottomboxconpoent>
<bottomboxconpoent> </bottomboxconpoent>
<bottomboxconpoent> </bottomboxconpoent>
</div>
</div>
</div> </div>
</template> </template>
@ -10,6 +57,8 @@
// import { getPowerStationOverview } from '@/api/large'; // import { getPowerStationOverview } from '@/api/large';
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import china from '@/assets/china.json'; import china from '@/assets/china.json';
import RevenueContractCard from './RevenueContractCard.vue';
import bottomboxconpoent from './bottomboxconpoent.vue';
const data = ref<any>({}); const data = ref<any>({});
// 地图容器引用 // 地图容器引用
@ -168,9 +217,12 @@ onUnmounted(() => {
padding: 0 10px 10px 10px; padding: 0 10px 10px 10px;
box-sizing: border-box; box-sizing: border-box;
.centerPage_map { .centerPage_map {
width: 100%; width: 100%;
height: 100%; height: 60%;
} }
} }
</style> </style>

View File

@ -2,36 +2,72 @@
<div class="leftPage"> <div class="leftPage">
<!-- --> <!-- -->
<div class="kpi_box"> <div class="kpi_box">
<TitleComponent :title="'支付KPI'"/> <TitleComponent :title="'支付KPI'" style="margin-bottom: 20px;"/>
<div style="height: 100px;"></div>
<ProgressComponent <ProgressComponent
title="营业收入" title="应收账款"
value="123,456.78" value="123,456.78"
percentageChange="+25.30%" percentageChange="+25.30%"
progressPercentage="75" progressPercentage="75"
progressColor="rgba(255, 77, 79, 1)"
/>
<ProgressComponent
title="应付账款"
value="123,456.78"
percentageChange="+25.30%"
progressPercentage="25"
progressColor="rgba(29, 214, 255, 1)"
/>
<ProgressComponent
title="本月付款"
value="123,456.78"
percentageChange="+25.30%"
progressPercentage="45"
progressColor="rgba(0, 227, 150, 1)" progressColor="rgba(0, 227, 150, 1)"
/> />
<ProgressComponent
title="本月收款"
value="123,456.78"
percentageChange="+25.30%"
progressPercentage="10"
progressColor="rgba(255, 147, 42, 1)"
/>
</div>
<div class="contract_box">
<EchartBox :option="barOption" />
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, reactive, onMounted, computed, toRefs, getCurrentInstance, nextTick } from 'vue'; import { ref, reactive, onMounted, computed, toRefs, getCurrentInstance, nextTick } from 'vue';
// import echarts from 'echarts';
import TitleComponent from './TitleComponent.vue'; import TitleComponent from './TitleComponent.vue';
import ProgressComponent from './ProgressComponent.vue'; import ProgressComponent from './ProgressComponent.vue';
import EchartBox from '@/components/EchartBox/index.vue';
import { getBarOptions2 } from './optionList';
const barOption = ref();
const getCapitalData = (data) => {
barOption.value = getBarOptions2();
};
onMounted(() => {
getCapitalData();
});
</script> </script>
<style lang="scss"> <style lang="scss">
.leftPage { .leftPage {
width: 100%; width: 100%;
height: 100%; height: 100%;
background: #0c1e35;
.kpi_box{ .kpi_box{
margin-bottom: 10px;
}
.contract_box{
height: 35vh;
}
.kpi_box,.contract_box {
padding: 10px; padding: 10px;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid rgba(29, 214, 255, 0.3);
} }
} }
</style> </style>

View File

@ -1,4 +1,5 @@
import * as echarts from 'echarts/core'; import * as echarts from 'echarts/core';
import { text } from 'stream/consumers';
// import { PictorialBarChart } from 'echarts/charts' // import { PictorialBarChart } from 'echarts/charts'
// 客流量图 // 客流量图
export const getOption = (xData: any, yData: any) => { export const getOption = (xData: any, yData: any) => {
@ -857,3 +858,62 @@ export const getBarOptions = (data: any) => {
}; };
return option; return option;
}; };
// 收支合同分析
export const getBarOptions2 = (data: any) => {
const option = {
color:['#FF932A', '#678FE6', '#1DD6FF', '#00E396'],
title: {
text: '数量(个)',
subtext: '16',
bottom: 'center',
left: 'center',
textStyle: {
color: '#9DADB7',
fontSize: 16
},
subtextStyle:{
color: '#707070',
fontSize: 32,
fontWeight: 'bold'
}
},
tooltip: {
trigger: 'item'
},
legend: {
top: '5%',
left: 'center'
},
series: [
{
name: 'Access From',
type: 'pie',
radius: ['50%', '60%'],
avoidLabelOverlap: false,
padAngle: 5,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: false,
fontSize: 40,
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{ value: 3, name: '100万一下' },
{ value: 4, name: '100-500万' },
{ value: 5, name: '500-1000万' },
{ value: 4, name: '1000万以上' },
]
}
]
};
return option;
}

View File

@ -29,10 +29,12 @@
<EchartBox :option="barOption" /> <EchartBox :option="barOption" />
</div> </div>
<div class="progress"> <div class="progress">
<div class="progress_item"> <!-- <div class="progress_item">
<div class="title">项目进度</div> <div class="title">项目进度</div>
<div class="number">100%</div> <div class="number">100%</div>
</div> </div> -->
<ProgressComponent title="现金比率" value="123,456.78" percentageChange="3479.61%" :progressPercentage="100"
progressColor="rgba(29, 214, 255, 1)" :isShowPrice="false" class="progress_text" />
</div> </div>
</div> </div>
</div> </div>
@ -42,6 +44,7 @@
import TitleComponent from './TitleComponent.vue'; import TitleComponent from './TitleComponent.vue';
import EchartBox from '@/components/EchartBox/index.vue'; import EchartBox from '@/components/EchartBox/index.vue';
import { getLineOption, getBarOptions } from './optionList'; import { getLineOption, getBarOptions } from './optionList';
import ProgressComponent from './ProgressComponent.vue';
const lineOption = ref(); const lineOption = ref();
const barOption = ref(); const barOption = ref();
@ -90,10 +93,10 @@ onMounted(() => {
.rightPage { .rightPage {
width: 100%; width: 100%;
height: 100%; height: 100%;
background: #0c1e35;
box-sizing: border-box; box-sizing: border-box;
// padding: 5px; // padding: 5px;
} }
.funds { .funds {
width: 100%; width: 100%;
// height: 40%; // height: 40%;
@ -101,19 +104,22 @@ onMounted(() => {
box-sizing: border-box; box-sizing: border-box;
padding: 10px 5px; padding: 10px 5px;
} }
.funds_echarts { .funds_echarts {
width: 100%; width: 100%;
height: 25vh; height: 25vh;
padding: 10px 0 0 0; padding: 10px 0 0 0;
} }
.cashFlow { .cashFlow {
width: 100%; width: 100%;
// height: 50%; // height: 50%;
border: 1px solid rgba(29, 214, 255, 0.3); border: 1px solid rgba(29, 214, 255, 0.3);
box-sizing: border-box; box-sizing: border-box;
padding: 10px 5px; padding: 10px 5px;
margin-top: 20px; margin-top: 10px;
} }
.inflowData { .inflowData {
width: 100%; width: 100%;
height: 12vh; height: 12vh;
@ -122,6 +128,7 @@ onMounted(() => {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
grid-gap: 10px; grid-gap: 10px;
.inflow { .inflow {
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -141,12 +148,14 @@ onMounted(() => {
color: #fff; color: #fff;
padding-bottom: 10px; padding-bottom: 10px;
} }
.number { .number {
font-size: 24px; font-size: 24px;
// font-weight: 500; // font-weight: 500;
color: #fff; color: #fff;
padding-bottom: 10px; padding-bottom: 10px;
} }
.unit { .unit {
font-size: 12px; font-size: 12px;
// font-weight: 500; // font-weight: 500;
@ -154,12 +163,21 @@ onMounted(() => {
} }
} }
} }
.inflow_echarts { .inflow_echarts {
width: 100%; width: 100%;
height: 25vh; height: 25vh;
margin-top: 20px; margin-top: 20px;
} }
.progress { .progress {
width: 100%; width: 100%;
margin-top: 10px;
}
:deep(.progress_text) {
.roboto {
color: #fff;
}
} }
</style> </style>

View File

@ -24,13 +24,16 @@
<el-form-item label="处理方式" prop="disposition"> <el-form-item label="处理方式" prop="disposition">
<el-input v-model="form.disposition" placeholder="请输入处理方式" /> <el-input v-model="form.disposition" placeholder="请输入处理方式" />
</el-form-item> </el-form-item>
<el-form-item v-if="form.outPut === '1'" label="使用部位" prop="usePart">
<el-input v-model="form.usePart" placeholder="请输入使用部位" />
</el-form-item>
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" /> <el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item> </el-form-item>
<el-form-item label="操作时间" prop="outPutTime"> <!-- <el-form-item label="操作时间" prop="outPutTime">
<el-date-picker clearable v-model="form.outPutTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择操作时间"> <el-date-picker clearable v-model="form.outPutTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择操作时间">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item> -->
<el-form-item label="材料出入证明" prop="path"> <el-form-item label="材料出入证明" prop="path">
<file-upload v-model="form.path" :limit="1" :file-size="50" :file-type="['pdf']" /> <file-upload v-model="form.path" :limit="1" :file-size="50" :file-type="['pdf']" />
</el-form-item> </el-form-item>

View File

@ -79,7 +79,7 @@
<tbody> <tbody>
<tr> <tr>
<td colspan="7"> <td colspan="7">
<div style="margin-bottom: 10px;">缺陷情况:</div> <div style="margin-bottom: 10px">缺陷情况:</div>
{{ formData.defectDescription }} {{ formData.defectDescription }}
</td> </td>
</tr> </tr>
@ -90,10 +90,10 @@
<td colspan="8"> <td colspan="8">
<span>是否附带以下随机资料</span> <span>是否附带以下随机资料</span>
<div class="file_detail"> <div class="file_detail">
<span>(1) 合格证 {{ formData.certCountFile ? formData.certCountFile.length : 0 }} </span> <span>(1) 合格证 {{ formData.certCount ? formData.certCount : 0 }} </span>
<span>(2) 出厂报告 {{ formData.reportCountFileId ? formData.reportCountFileId.length : 0 }} </span> <span>(2) 出厂报告 {{ formData.reportCount ? formData.reportCount : 0 }} </span>
<span>(3) 技术资料文件 {{ formData.techDocCountFileId ? formData.techDocCountFileId.length : 0 }} </span> <span>(3) 技术资料文件 {{ formData.techDocCount ? formData.techDocCount : 0 }} </span>
<span>(4) 厂家资质文件 {{ formData.licenseCountFileId ? formData.licenseCountFileId.length : 0 }} </span> <span>(4) 厂家资质文件 {{ formData.licenseCount ? formData.licenseCount : 0 }} </span>
</div> </div>
</td> </td>
</tr> </tr>
@ -249,7 +249,6 @@ defineExpose({
} }
} }
.file_detail { .file_detail {
> span { > span {
width: 40%; width: 40%;
display: inline-block; display: inline-block;

View File

@ -81,10 +81,10 @@
<td colspan="8"> <td colspan="8">
<span>是否附带以下随机资料</span> <span>是否附带以下随机资料</span>
<div class="file_detail"> <div class="file_detail">
<span>(1) 合格证 {{ formData.certCountFile ? formData.certCountFile.length : 0 }} </span> <span>(1) 合格证 {{ formData.certCount ? formData.certCount : 0 }} </span>
<span>(2) 出厂报告 {{ formData.reportCountFileId ? formData.reportCountFile.length : 0 }} </span> <span>(2) 出厂报告 {{ formData.reportCount ? formData.reportCount : 0 }} </span>
<span>(3) 技术资料文件 {{ formData.techDocCountFileId ? formData.techDocCountFile.length : 0 }} </span> <span>(3) 技术资料文件 {{ formData.techDocCount ? formData.techDocCount : 0 }} </span>
<span>(4) 厂家资质文件 {{ formData.licenseCountFileId ? formData.licenseCountFile.length : 0 }} </span> <span>(4) 厂家资质文件 {{ formData.licenseCount ? formData.licenseCount : 0 }} </span>
</div> </div>
</td> </td>
</tr> </tr>

View File

@ -56,6 +56,7 @@
</el-table-column> </el-table-column>
<el-table-column label="出库登记" align="center"> <el-table-column label="出库登记" align="center">
<el-table-column label="交接单位" align="center" prop="recipient" /> <el-table-column label="交接单位" align="center" prop="recipient" />
<el-table-column label="使用部位" align="center" prop="usePart" />
<el-table-column label="数量" align="center" prop="number"> <el-table-column label="数量" align="center" prop="number">
<template #default="scope"> <template #default="scope">
<span v-if="scope.row.outPut === '1'">{{ scope.row.number }}</span> <span v-if="scope.row.outPut === '1'">{{ scope.row.number }}</span>

View File

@ -268,7 +268,6 @@ import { listContractor } from '@/api/project/contractor';
import { useUserStoreHook } from '@/store/modules/user'; import { useUserStoreHook } from '@/store/modules/user';
import { getToken } from '@/utils/auth'; import { getToken } from '@/utils/auth';
import logisticsDetail from './comm/logisticsDetail.vue'; import logisticsDetail from './comm/logisticsDetail.vue';
import type { DrawerProps } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
@ -385,12 +384,19 @@ const cancel = () => {
}; };
const handleDetail = async (row?: PurchaseDocVO) => { const handleDetail = async (row?: PurchaseDocVO) => {
detailBASEVisble.value = true; proxy?.$modal.loading('加载中');
try {
const res = await getDetailBASE(row.id); const res = await getDetailBASE(row.id);
detailBASE.value = res.data; if (res.data) {
window.open(res.data);
console.log('🚀 ~ handleDetail ~ res:', res); } else {
proxy?.$modal.msgError('查看失败');
}
} catch (error) {
proxy?.$modal.msgError('查看失败');
} finally {
proxy?.$modal.closeLoading();
}
}; };
/** 表单重置 */ /** 表单重置 */

View File

@ -75,20 +75,7 @@
</el-table> </el-table>
<!-- 分页 --> <!-- 分页 -->
<div class="flex items-center justify-between p-4 border-t"> <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="fetchData" />
<div class="text-gray-500 text-sm">
{{ total }} 条记录当前显示第 {{ (currentPage - 1) * pageSize + 1 }} {{ Math.min(currentPage * pageSize, total) }}
</div>
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="total"
layout="prev, pager, next, jumper, sizes"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</div> </div>
<!-- 新增/编辑对话框 --> <!-- 新增/编辑对话框 -->
<el-dialog <el-dialog
@ -210,7 +197,12 @@ const saveLoading = ref(false);
const deleteLoading = ref(false); const deleteLoading = ref(false);
const currentRow = ref(null); const currentRow = ref(null);
const submitLoading = ref(false); const submitLoading = ref(false);
const queryParams = reactive({
pageSize: 10,
pageNum: 1,
findType: 2,
projectId: currentProject.value?.id
});
// 表单数据 // 表单数据
const formData = reactive({ const formData = reactive({
id: '', id: '',
@ -272,11 +264,7 @@ const tableRowClassName = ({ row, rowIndex }) => {
const fetchData = async () => { const fetchData = async () => {
loading.value = true; loading.value = true;
try { try {
const res = await useMaterialsQueryList({ const res = await useMaterialsQueryList(queryParams);
projectId: currentProject.value?.id,
findType: 2
});
tableData.value = res.rows; tableData.value = res.rows;
total.value = res.total; total.value = res.total;
loading.value = false; loading.value = false;

View File

@ -168,9 +168,14 @@
</el-table> </el-table>
<!-- 分页 --> <!-- 分页 -->
<div class="flex flex-wrap items-center justify-between p-4 border-t gap-4"> <div class="flex flex-wrap items-center justify-between p-4 border-t gap-4">
<div class="text-gray-500 text-sm"> <pagination
{{ total }} 条记录当前显示第 {{ (currentPage - 1) * pageSize + 1 }} {{ Math.min(currentPage * pageSize, total) }} v-show="total > 0"
</div> :total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="materialsUsageDetails1"
/>
<el-dialog <el-dialog
v-model="dialogVisible2" v-model="dialogVisible2"
:title="dialogType2 === 'addSon' ? '新增采购信息' : '编辑采购信息'" :title="dialogType2 === 'addSon' ? '新增采购信息' : '编辑采购信息'"
@ -480,6 +485,12 @@ const resetForm = () => {
form.id = ''; form.id = '';
}; };
const queryParams = reactive({
pageSize: 10,
pageNum: 1,
physicalsupplyId: routeParams.value.id
});
const handleEdit2 = (row) => { const handleEdit2 = (row) => {
dialogType2.value = 'editSon'; dialogType2.value = 'editSon';
currentRow2.value = row; currentRow2.value = row;
@ -573,9 +584,10 @@ const handleSubmit = async () => {
}; };
const materialsUsageDetails1 = () => { const materialsUsageDetails1 = () => {
loading.value = true; loading.value = true;
materialsUsageDetails({ physicalsupplyId: routeParams.value.id }) materialsUsageDetails(queryParams)
.then((res) => { .then((res) => {
tableData.value = res.rows; tableData.value = res.rows;
total.value = res.total;
}) })
.catch(() => { .catch(() => {
loading.value = false; loading.value = false;

View File

@ -88,20 +88,7 @@
</el-table> </el-table>
<!-- 分页 --> <!-- 分页 -->
<div class="flex items-center justify-between p-4 border-t"> <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="fetchData" />
<div class="text-gray-500 text-sm">
{{ total }} 条记录当前显示第 {{ (currentPage - 1) * pageSize + 1 }} {{ Math.min(currentPage * pageSize, total) }}
</div>
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="total"
layout="prev, pager, next, jumper, sizes"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</div> </div>
<!-- 新增/编辑对话框 --> <!-- 新增/编辑对话框 -->
<el-dialog <el-dialog
@ -264,6 +251,13 @@ const formRules = reactive({
findType: [{ required: true, message: '请选择类型', trigger: 'change' }] findType: [{ required: true, message: '请选择类型', trigger: 'change' }]
}); });
const queryParams = reactive({
pageSize: 10,
pageNum: 1,
findType: 1,
projectId: currentProject.value?.id
});
// 格式化日期 // 格式化日期
const formatDate = (dateString) => { const formatDate = (dateString) => {
if (!dateString) return '-'; if (!dateString) return '-';
@ -289,10 +283,7 @@ const tableRowClassName = ({ row, rowIndex }) => {
const fetchData = async () => { const fetchData = async () => {
loading.value = true; loading.value = true;
try { try {
const res = await useMaterialsQueryList({ const res = await useMaterialsQueryList(queryParams);
projectId: currentProject.value?.id,
findType: 1
});
tableData.value = res.rows; tableData.value = res.rows;
total.value = res.total; total.value = res.total;

View File

@ -166,21 +166,13 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 分页 --> <!-- 分页 -->
<div class="flex flex-wrap items-center justify-between p-4 border-t gap-4"> <pagination
<div class="text-gray-500 text-sm"> v-show="total > 0"
{{ total }} 条记录当前显示第 {{ (currentPage - 1) * pageSize + 1 }} {{ Math.min(currentPage * pageSize, total) }}
</div>
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="total" :total="total"
layout="prev, pager, next, jumper, sizes" v-model:page="queryParams.pageNum"
@size-change="handleSizeChange" v-model:limit="queryParams.pageSize"
@current-change="handleCurrentChange" @pagination="materialsUsageDetails1"
small />
></el-pagination>
</div>
</div> </div>
<!-- 删除确认对话框 --> <!-- 删除确认对话框 -->
<el-dialog v-model="deleteDialogVisible2" title="确认删除" width="300px" :show-close="false"> <el-dialog v-model="deleteDialogVisible2" title="确认删除" width="300px" :show-close="false">
@ -503,7 +495,11 @@ const resetForm = () => {
form.findType = 1; form.findType = 1;
form.id = ''; form.id = '';
}; };
const queryParams = reactive({
pageSize: 10,
pageNum: 1,
physicalsupplyId: routeParams.value.id
});
const handleEdit2 = (row) => { const handleEdit2 = (row) => {
dialogType2.value = 'editSon'; dialogType2.value = 'editSon';
currentRow2.value = row; currentRow2.value = row;
@ -596,8 +592,9 @@ const handleSubmit = async () => {
} }
}; };
const materialsUsageDetails1 = () => { const materialsUsageDetails1 = () => {
materialsUsageDetails({ physicalsupplyId: routeParams.value.id }).then((res) => { materialsUsageDetails(queryParams).then((res) => {
tableData.value = res.rows; tableData.value = res.rows;
total.value = res.total;
}); });
}; };
// 格式化日期 // 格式化日期

View File

@ -32,6 +32,7 @@
<!-- 任务列表表格 --> <!-- 任务列表表格 -->
<el-table v-loading="loading" :data="masterList" @selection-change="handleSelectionChange" border> <el-table v-loading="loading" :data="masterList" @selection-change="handleSelectionChange" border>
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="selection" width="55" align="center" />
<el-table-column label="执行人名称" align="center" prop="slaveName" />
<el-table-column label="任务名称" align="center" prop="taskName" /> <el-table-column label="任务名称" align="center" prop="taskName" />
<el-table-column label="任务描述" align="center" prop="describe" /> <el-table-column label="任务描述" align="center" prop="describe" />
<el-table-column label="计划完成时间" align="center" prop="pcd" width="180"> <el-table-column label="计划完成时间" align="center" prop="pcd" width="180">
@ -144,12 +145,10 @@
<!-- 新增/修改任务弹窗 --> <!-- 新增/修改任务弹窗 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body destroy-on-close> <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body destroy-on-close>
<el-form ref="masterFormRef" :model="form" :rules="rules" label-width="100px"> <el-form ref="masterFormRef" :model="form" :rules="rules" label-width="100px">
<<<<<<< HEAD =======
<el-input v-model="form.projectId" placeholder="请输入项目ID" :readonly="!!currentProjectId" :disabled="!!currentProjectId" v-if="false" /> <el-input v-model="form.projectId" placeholder="请输入项目ID" :readonly="!!currentProjectId" :disabled="!!currentProjectId" v-if="false" />
<template #help> <template #help>
<span v-if="currentProjectId" class="text-success">已自动关联当前选中项目</span> <span v-if="currentProjectId" class="text-success">已自动关联当前选中项目</span>
</template> </template>
>>>>>>> 4511145f52e1caf07eea31e374583c6602fdfcfc
<el-form-item label="任务名称" prop="taskName"> <el-form-item label="任务名称" prop="taskName">
<el-input v-model="form.taskName" placeholder="请输入任务名称" /> <el-input v-model="form.taskName" placeholder="请输入任务名称" />
</el-form-item> </el-form-item>
@ -633,8 +632,18 @@ const handleExport = () => {
proxy?.download('patch/patch/export', { ...queryParams.value }, `任务列表_${new Date().getTime()}.xlsx`); proxy?.download('patch/patch/export', { ...queryParams.value }, `任务列表_${new Date().getTime()}.xlsx`);
}; };
onMounted(() => { // 监听项目id刷新数据
const listeningProject = watch(
() => currentProject.value?.id,
(nid, oid) => {
queryParams.value.projectId = nid;
form.value.projectId = nid;
getList(); getList();
}
);
onUnmounted(() => {
listeningProject();
}); });
</script> </script>

View File

@ -18,9 +18,9 @@
<el-option v-for="item in matrixOptions" :key="item.id" :label="item.matrixName" :value="item.id" /> <el-option v-for="item in matrixOptions" :key="item.id" :label="item.matrixName" :value="item.id" />
</el-select> --> </el-select> -->
</el-form-item> </el-form-item>
<el-form-item> <!-- <el-form-item>
<el-button type="primary" icon="Download" @click="handleQuery">导出周报</el-button> <el-button type="primary" icon="Download" @click="handleQuery">导出周报</el-button>
</el-form-item> </el-form-item> -->
</el-form> </el-form>
</el-card> </el-card>
</div> </div>

View File

@ -1,6 +1,7 @@
<template> <template>
<div class="p-2"> <div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> <transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]"> <div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover"> <el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true"> <el-form ref="queryFormRef" :model="queryParams" :inline="true">
@ -40,59 +41,43 @@
<template #header> <template #header>
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['contractor:constructionUser:add']">新增 </el-button> <el-button type="primary" plain icon="Plus" @click="handleAdd"
v-hasPermi="['contractor:constructionUser:add']">新增 </el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
type="danger" v-hasPermi="['contractor:constructionUser:remove']">
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete()"
v-hasPermi="['contractor:constructionUser:remove']"
>
删除 删除
</el-button> </el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['contractor:constructionUser:export']" <el-button type="warning" plain icon="Download" @click="handleExport"
>导出 v-hasPermi="['contractor:constructionUser:export']">导出
</el-button> </el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="warning" plain icon="Edit" :disabled="multiple" @click="statusDialog = true">用户状态编辑 </el-button> <el-button type="warning" plain icon="Edit" :disabled="multiple" @click="statusDialog = true">用户状态编辑
</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-switch <el-switch v-model="playCardStatus" class="ml-2" inline-prompt
v-model="playCardStatus" style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949" :loading="playCardLoding"
class="ml-2" @change="handlePlayCardStatus" inactive-text="一键关闭打卡" active-text="一键开启打卡" />
inline-prompt
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
:loading="playCardLoding"
@change="handlePlayCardStatus"
inactive-text="一键关闭打卡"
active-text="一键开启打卡"
/>
</el-col> </el-col>
<el-row @mouseover="informationStatus = true" :gutter="10" @mouseout="informationStatus = false"> <el-row @mouseover="informationStatus = true" :gutter="10" @mouseout="informationStatus = false">
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="success" plain>员工资料 </el-button> <el-button type="success" plain>员工资料 </el-button>
</el-col> </el-col>
<el-col :span="1.5" v-show="informationStatus"> <el-col :span="1.5" v-show="informationStatus">
<el-button type="primary" plain icon="Edit" @click="downloadTemplate" v-hasPermi="['contractor:constructionUserFile:download']" <el-button type="primary" plain icon="Edit" @click="downloadTemplate"
>下载资料模板 v-hasPermi="['contractor:constructionUserFile:download']">下载资料模板
</el-button> </el-button>
</el-col> </el-col>
<el-col :span="1.5" v-show="informationStatus"> <el-col :span="1.5" v-show="informationStatus">
<file-upload <file-upload v-model="filePath" isImportInfo :isShowTip="false"
v-model="filePath" uploadUrl="/project/constructionUserFile/upload/zip" :limit="1" :file-size="50">
isImportInfo <el-button type="warning" plain icon="Edit"
:isShowTip="false" v-hasPermi="['contractor:constructionUserFile:upload']">导入员工资料 </el-button>
uploadUrl="/project/constructionUserFile/upload/zip"
:limit="1"
:file-size="50"
>
<el-button type="warning" plain icon="Edit" v-hasPermi="['contractor:constructionUserFile:upload']">导入员工资料 </el-button>
</file-upload> </file-upload>
</el-col> </el-col>
</el-row> </el-row>
@ -130,18 +115,9 @@
</el-table-column> </el-table-column>
<el-table-column label="打卡状态" align="center" prop="clock"> <el-table-column label="打卡状态" align="center" prop="clock">
<template #default="scope"> <template #default="scope">
<el-switch <el-switch v-model="scope.row.clock" class="ml-2" inline-prompt
v-model="scope.row.clock" style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949" active-text="开启" inactive-text="禁用"
class="ml-2" :loading="playCardLoding" active-value="0" inactive-value="1" @change="handleClockStatus(scope.row)" />
inline-prompt
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
active-text="开启"
inactive-text="禁用"
:loading="playCardLoding"
active-value="0"
inactive-value="1"
@change="handleClockStatus(scope.row)"
/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="薪水" align="center" min-width="180"> <el-table-column label="薪水" align="center" min-width="180">
@ -150,7 +126,8 @@
{{ scope.row.salary ? scope.row.salary : scope.row.standardSalary }} {{ scope.row.salary ? scope.row.salary : scope.row.standardSalary }}
(<dict-tag :options="wage_measure_unit_type" :value="scope.row.wageMeasureUnit"></dict-tag>) (<dict-tag :options="wage_measure_unit_type" :value="scope.row.wageMeasureUnit"></dict-tag>)
</span> </span>
<div class="text-blue text-sm cursor-pointer" @click="openSalaryDialog(scope.row)">{{ scope.row.salary ? '取消变更' : '变更' }}</div> <div class="text-blue text-sm cursor-pointer" @click="openSalaryDialog(scope.row)">{{ scope.row.salary ?
'取消变更' : '变更' }}</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="入场时间" align="center" prop="entryDate" min-width="180" /> <el-table-column label="入场时间" align="center" prop="entryDate" min-width="180" />
@ -164,30 +141,29 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" min-width="300"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" min-width="300">
<template #default="scope"> <template #default="scope">
<el-space wrap> <el-space wrap>
<el-button link type="primary" icon="View" @click="handleShowDrawer(scope.row)" v-hasPermi="['contractor:constructionUser:query']"> <el-button link type="primary" icon="View" @click="handleShowDrawer(scope.row)"
v-hasPermi="['contractor:constructionUser:query']">
详情 详情
</el-button> </el-button>
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['contractor:constructionUser:edit']"> <el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['contractor:constructionUser:edit']">
修改 修改
</el-button> </el-button>
<el-button link type="warning" icon="Female" @click="handlePlayCard(scope.row)"> 打卡 </el-button> <el-button link type="warning" icon="Female" @click="handlePlayCard(scope.row)"> 打卡 </el-button>
<el-button <el-button link type="danger" icon="Avatar" @click="handleJoinBlacklist(scope.row)"
link v-hasPermi="['contractor:constructionBlacklist:add']">
type="danger"
icon="Avatar"
@click="handleJoinBlacklist(scope.row)"
v-hasPermi="['contractor:constructionBlacklist:add']"
>
黑名单 黑名单
</el-button> </el-button>
<!-- <el-button link type="primary" icon="Switch" @click="handleToggle(scope.row)"> 切换人脸 </el-button> --> <!-- <el-button link type="primary" icon="Switch" @click="handleToggle(scope.row)"> 切换人脸 </el-button> -->
<el-button link type="primary" icon="Switch" @click="handleChange(scope.row)"> 人员迁移 </el-button> <el-button link type="primary" icon="Switch" @click="handleChange(scope.row)"> 人员迁移 </el-button>
<el-button link type="primary" icon="ChatLineSquare" @click="handleExit(scope.row)"> 入退场记录 </el-button> <el-button link type="primary" icon="ChatLineSquare" @click="handleExit(scope.row)"> 入退场记录 </el-button>
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['contractor:constructionUser:remove']"> <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['contractor:constructionUser:remove']">
删除 删除
</el-button> </el-button>
<el-tooltip content="红点:部分上传,绿点:已上传,无点:未上传" placement="right" effect="dark"> <el-tooltip content="红点:部分上传,绿点:已上传,无点:未上传" placement="right" effect="dark">
<el-badge :is-dot="scope.row.fileUploadStatus != '1'" :type="uploadStatusColor(scope.row.fileUploadStatus)"> <el-badge :is-dot="scope.row.fileUploadStatus != '1'"
:type="uploadStatusColor(scope.row.fileUploadStatus)">
<el-button link type="primary" icon="FolderAdd" @click="handleUpload(scope.row)">文件上传 </el-button> <el-button link type="primary" icon="FolderAdd" @click="handleUpload(scope.row)">文件上传 </el-button>
</el-badge> </el-badge>
</el-tooltip> </el-tooltip>
@ -196,7 +172,8 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card> </el-card>
<!-- 添加或修改施工人员对话框 --> <!-- 添加或修改施工人员对话框 -->
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="930px" append-to-body> <el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="930px" append-to-body>
@ -248,12 +225,14 @@
</div> </div>
<div class="el-col el-col-12"> <div class="el-col el-col-12">
<el-form-item label="身份证有效开始期" prop="sfzStart"> <el-form-item label="身份证有效开始期" prop="sfzStart">
<el-date-picker clearable v-model="form.sfzStart" type="date" value-format="YYYY-MM-DD" placeholder="请输入身份证有效开始期" /> <el-date-picker clearable v-model="form.sfzStart" type="date" value-format="YYYY-MM-DD"
placeholder="请输入身份证有效开始期" />
</el-form-item> </el-form-item>
</div> </div>
<div class="el-col el-col-12"> <div class="el-col el-col-12">
<el-form-item label="身份证有效结束期" prop="sfzEnd"> <el-form-item label="身份证有效结束期" prop="sfzEnd">
<el-date-picker clearable v-model="form.sfzEnd" type="date" value-format="YYYY-MM-DD" placeholder="请输入身份证有效结束期" /> <el-date-picker clearable v-model="form.sfzEnd" type="date" value-format="YYYY-MM-DD"
placeholder="请输入身份证有效结束期" />
</el-form-item> </el-form-item>
</div> </div>
<div class="el-col el-col-12"> <div class="el-col el-col-12">
@ -263,7 +242,8 @@
</div> </div>
<div class="el-col el-col-12"> <div class="el-col el-col-12">
<el-form-item label="身份证出生日期" prop="sfzBirth"> <el-form-item label="身份证出生日期" prop="sfzBirth">
<el-date-picker clearable v-model="form.sfzBirth" type="date" value-format="YYYY-MM-DD" placeholder="请输入身份证出生日期" /> <el-date-picker clearable v-model="form.sfzBirth" type="date" value-format="YYYY-MM-DD"
placeholder="请输入身份证出生日期" />
</el-form-item> </el-form-item>
</div> </div>
<div class="el-col el-col-12"> <div class="el-col el-col-12">
@ -316,14 +296,16 @@
<div class="el-col el-col-12"> <div class="el-col el-col-12">
<el-form-item label="打卡" prop="clock"> <el-form-item label="打卡" prop="clock">
<el-select v-model="form.clock" clearable placeholder="请选择打卡状态"> <el-select v-model="form.clock" clearable placeholder="请选择打卡状态">
<el-option v-for="item in user_clock_type" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in user_clock_type" :key="item.value" :label="item.label"
:value="item.value" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</div> </div>
<div class="el-col el-col-12"> <div class="el-col el-col-12">
<el-form-item label="结算方式" prop="wageMeasureUnit"> <el-form-item label="结算方式" prop="wageMeasureUnit">
<el-select v-model="form.wageMeasureUnit" clearable placeholder="请选择结算方式"> <el-select v-model="form.wageMeasureUnit" clearable placeholder="请选择结算方式">
<el-option v-for="item in wage_measure_unit_type" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in wage_measure_unit_type" :key="item.value" :label="item.label"
:value="item.value" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</div> </div>
@ -352,7 +334,8 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="分包单位" label-width="130px"> <el-form-item label="分包单位" label-width="130px">
<el-select v-model="skipObject.contractorId" :disabled="!skipObject.projectId" placeholder="请选择分包单位" style="width: 240px"> <el-select v-model="skipObject.contractorId" :disabled="!skipObject.projectId" placeholder="请选择分包单位"
style="width: 240px">
<el-option v-for="item in contractorList" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in contractorList" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -367,7 +350,8 @@
<div class="image_upload" v-for="(item, index) in uploadPath" :key="item.value"> <div class="image_upload" v-for="(item, index) in uploadPath" :key="item.value">
<div class="title">{{ item.label }}</div> <div class="title">{{ item.label }}</div>
<div class="file_upload_all" v-if="item.value != 7"> <div class="file_upload_all" v-if="item.value != 7">
<file-upload v-model="item.path" isConstruction :isShowTip="false" :limit="10" :file-type="['pdf']" :file-size="50" /> <file-upload v-model="item.path" isConstruction :isShowTip="false" :limit="10" :file-type="['pdf']"
:file-size="50" />
</div> </div>
</div> </div>
<template #footer> <template #footer>
@ -386,8 +370,7 @@
</el-form> </el-form>
</div> </div>
<template #footer> <template #footer>
<span <span><el-button type="primary" @click="submitForm">保存</el-button>
><el-button type="primary" @click="submitForm">保存</el-button>
<el-button @click="showFaceDrawer = false">取消</el-button> <el-button @click="showFaceDrawer = false">取消</el-button>
</span> </span>
</template> </template>
@ -399,8 +382,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<template #footer> <template #footer>
<span <span><el-button type="primary" @click="handleEdit">保存</el-button>
><el-button type="primary" @click="handleEdit">保存</el-button>
<el-button @click="statusDialog = false">取消</el-button> <el-button @click="statusDialog = false">取消</el-button>
</span> </span>
</template> </template>
@ -424,8 +406,8 @@
<el-timeline-item color="rgb(255, 73, 73)"> <el-timeline-item color="rgb(255, 73, 73)">
<div class="mb">{{ '退场时间:' + item.entryDate }}</div> <div class="mb">{{ '退场时间:' + item.entryDate }}</div>
<div class="pl-xl"> <div class="pl-xl">
<span class="text-coolgray font-bold">退场文件<image-preview v-for="itm in item.pathUrl" :src="itm" width="100px" class="mr" /></span <span class="text-coolgray font-bold">退场文件<image-preview v-for="itm in item.pathUrl" :src="itm"
><br /> width="100px" class="mr" /></span><br />
<p class="mt text-coolgray"> <p class="mt text-coolgray">
备注<span class="text-blue">{{ item.remark }}</span> 备注<span class="text-blue">{{ item.remark }}</span>
</p> </p>
@ -453,11 +435,8 @@
<el-date-picker v-model="monthValue" type="month" placeholder="请选择月份" @change="handleMonth" /> <el-date-picker v-model="monthValue" type="month" placeholder="请选择月份" @change="handleMonth" />
</template> </template>
<template #date-cell="{ data }"> <template #date-cell="{ data }">
<div <div class="w100% h100% position-relative m-0 monthDay" :class="data.isSelected ? 'is-selected' : ''"
class="w100% h100% position-relative m-0 monthDay" @click="handleViewPlayCard(playCardIdx(data), data)">
:class="data.isSelected ? 'is-selected' : ''"
@click="handleViewPlayCard(playCardIdx(data), data)"
>
{{ data.day.split('-').slice(1).join('-') }} {{ data.day.split('-').slice(1).join('-') }}
<div :style="{ background: playCardColor(data) }" v-if="playCardIdx(data) != -1"></div> <div :style="{ background: playCardColor(data) }" v-if="playCardIdx(data) != -1"></div>
</div> </div>
@ -507,6 +486,7 @@ import {
ConstructionUserFileForm, ConstructionUserFileForm,
ConstructionUserFileQuery ConstructionUserFileQuery
} from '@/api/project/constructionUserFile/types'; } from '@/api/project/constructionUserFile/types';
import { ElLoadingService } from 'element-plus'; import { ElLoadingService } from 'element-plus';
import type { CalendarDateType, CalendarInstance } from 'element-plus'; import type { CalendarDateType, CalendarInstance } from 'element-plus';
import { AttendanceMonthVO } from '@/api/project/attendance/types'; import { AttendanceMonthVO } from '@/api/project/attendance/types';
@ -1087,10 +1067,12 @@ onMounted(() => {
margin: 0 15px; margin: 0 15px;
position: relative; position: relative;
font-size: 12px; font-size: 12px;
>div { >div {
margin: 0 15px; margin: 0 15px;
position: relative; position: relative;
font-size: 12px; font-size: 12px;
&::before { &::before {
position: absolute; position: absolute;
content: ''; content: '';
@ -1102,29 +1084,35 @@ onMounted(() => {
border-radius: 50%; border-radius: 50%;
} }
} }
.red { .red {
&::before { &::before {
background-color: red; background-color: red;
} }
} }
.gray { .gray {
&::before { &::before {
background-color: gray; background-color: gray;
} }
} }
.orange { .orange {
&::before { &::before {
background-color: orange; background-color: orange;
} }
} }
.green { .green {
&::before { &::before {
background-color: green; background-color: green;
} }
} }
} }
.monthDay { .monthDay {
padding: 8px; padding: 8px;
>div { >div {
position: absolute; position: absolute;
width: 20px; width: 20px;
@ -1135,13 +1123,16 @@ onMounted(() => {
right: 0; right: 0;
margin: auto; margin: auto;
} }
.type2 { .type2 {
background: rgb(255, 0, 0); background: rgb(255, 0, 0);
} }
.type3 { .type3 {
background: rgb(0, 128, 0); background: rgb(0, 128, 0);
} }
} }
.block_box { .block_box {
border: 1px solid #9eccfa; border: 1px solid #9eccfa;
border-radius: 6px; border-radius: 6px;
@ -1155,10 +1146,12 @@ onMounted(() => {
font-size: 14px; font-size: 14px;
margin-bottom: 10px; margin-bottom: 10px;
} }
.image_upload { .image_upload {
border-bottom: 1px solid #e3e3d7; border-bottom: 1px solid #e3e3d7;
padding-bottom: 4px; padding-bottom: 4px;
} }
.title { .title {
font-size: 18px; font-size: 18px;
font-weight: 700; font-weight: 700;
@ -1167,12 +1160,15 @@ onMounted(() => {
width: 100%; width: 100%;
font-family: cursive; font-family: cursive;
} }
.information { .information {
display: none; display: none;
} }
.informationStatus:hover .information { .informationStatus:hover .information {
display: block; display: block;
} }
::v-deep(.el-calendar) { ::v-deep(.el-calendar) {
.el-calendar-day { .el-calendar-day {
padding: 0; padding: 0;

View File

@ -5,7 +5,7 @@
<div v-show="showSearch" class="mb-[10px]"> <div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover"> <el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true"> <el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="企业登记注册类型" prop="supplierType"> <el-form-item label="企业登记注册类型" prop="supplierType" label-width="140px">
<el-select v-model="queryParams.supplierType" placeholder="请选择类型" clearable> <el-select v-model="queryParams.supplierType" placeholder="请选择类型" clearable>
<el-option label="劳务" value="劳务"></el-option> <el-option label="劳务" value="劳务"></el-option>
<el-option label="技术服务" value="技术服务"></el-option> <el-option label="技术服务" value="技术服务"></el-option>
@ -15,13 +15,6 @@
<el-form-item label="企业名称" prop="supplierName"> <el-form-item label="企业名称" prop="supplierName">
<el-input v-model="queryParams.supplierName" placeholder="请输入企业名称" clearable style="width: 200px" /> <el-input v-model="queryParams.supplierName" placeholder="请输入企业名称" clearable style="width: 200px" />
</el-form-item> </el-form-item>
<el-form-item label="审核状态" prop="state">
<el-select v-model="queryParams.state" placeholder="请选择状态" clearable>
<el-option label="待审核" value="0"></el-option>
<el-option label="已通过" value="1"></el-option>
<el-option label="未通过" value="2"></el-option>
</el-select>
</el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button> <el-button icon="Refresh" @click="resetQuery">重置</el-button>
@ -38,33 +31,16 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['supplierInput:supplierInput:add']">新增</el-button> <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['supplierInput:supplierInput:add']">新增</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <!-- <el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['supplierInput:supplierInput:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete()"
v-hasPermi="['supplierInput:supplierInput:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['supplierInput:supplierInput:export']">导出</el-button> <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['supplierInput:supplierInput:export']">导出</el-button>
</el-col> </el-col> -->
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
</template> </template>
<!-- 数据表格 --> <!-- 数据表格 -->
<el-table v-loading="loading" :data="supplierInputList" @selection-change="handleSelectionChange" border> <el-table v-loading="loading" :data="supplierInputList" @selection-change="handleSelectionChange" border>
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="index" label="序号" align="center" width="60" />
<el-table-column label="ID" align="center" prop="id" width="80" />
<el-table-column label="企业登记注册类型" align="center" prop="supplierType" width="140" /> <el-table-column label="企业登记注册类型" align="center" prop="supplierType" width="140" />
<el-table-column label="企业名称" align="center" prop="supplierName" width="180" /> <el-table-column label="企业名称" align="center" prop="supplierName" width="180" />
<el-table-column label="法定代表人" align="center" prop="supplierPerson" width="120" /> <el-table-column label="法定代表人" align="center" prop="supplierPerson" width="120" />
@ -73,49 +49,45 @@
<el-table-column label="负责人电话" align="center" prop="personPhone" width="120" /> <el-table-column label="负责人电话" align="center" prop="personPhone" width="120" />
<el-table-column label="纳税规模" align="center" prop="taxScale" width="120" /> <el-table-column label="纳税规模" align="center" prop="taxScale" width="120" />
<el-table-column label="资质等级" align="center" prop="supplierLivel" width="120" /> <el-table-column label="资质等级" align="center" prop="supplierLivel" width="120" />
<el-table-column label="审核状态" align="center" prop="state" width="120"> <el-table-column label="流程状态" align="center">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.state === '1' ? 'success' : scope.row.state === '2' ? 'danger' : 'warning'"> <dict-tag :options="wf_business_status" :value="scope.row.state" />
{{ scope.row.state === '1' ? '已通过' : scope.row.state === '2' ? '未通过' : '待审核' }}
</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="入库资料" align="center" prop="inputFile" width="120"> <el-table-column label="入库资料" align="center" prop="inputFile" width="120">
<template #default="scope"> <template #default="scope">
<el-link v-if="scope.row.inputFile" :href="scope.row.inputFile" target="_blank" underline>查看文件</el-link> <el-link v-if="scope.row.inputFile" :href="scope.row.inputFile" target="_blank" :style="{ textDecoration: 'none', color: '#409eff' }">
查看文件
</el-link>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120"> <el-table-column label="操作" align="center" fixed="right" width="240">
<template #default="scope"> <template #default="scope">
<el-tooltip content="修改" placement="top"> <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['supplierInput:supplierInput:edit']"
<el-button >修改</el-button
link >
type="primary" <el-button link type="primary" icon="edit" @click="handleAudit(scope.row)" v-if="scope.row.state == 'draft' || scope.row.state == 'back'"
icon="Edit" >审核</el-button
@click="handleUpdate(scope.row)" >
v-hasPermi="['supplierInput:supplierInput:edit']" <el-button link type="primary" icon="View" v-if="scope.row.state != '2' && scope.row.state != 'draft'" @click="handleAuditView(scope.row)"
></el-button> >查看流程</el-button
</el-tooltip> >
<el-tooltip content="删除" placement="top"> <!-- <el-button
<el-button
link link
type="primary" type="primary"
icon="Delete" icon="Delete"
@click="handleDelete(scope.row)" @click="handleDelete(scope.row)"
v-hasPermi="['supplierInput:supplierInput:remove']" v-hasPermi="['supplierInput:supplierInput:remove']"
></el-button> ></el-button> -->
</el-tooltip>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 分页 --> <!-- 分页 -->
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card> </el-card>
<!-- 新增/修改对话框 --> <!-- 新增/修改对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body> <el-dialog :title="dialog.title" v-model="dialog.visible" width="950px" append-to-body>
<el-form ref="supplierInputFormRef" :model="form" :rules="rules" label-width="140px"> <el-form ref="supplierInputFormRef" :model="form" :rules="rules" label-width="200px">
<!-- 第一行基础信息2列布局 --> <!-- 第一行基础信息2列布局 -->
<el-row :gutter="20" class="mb-4"> <el-row :gutter="20" class="mb-4">
<el-col :span="12"> <el-col :span="12">
@ -216,7 +188,7 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="发证日期" prop="issueDate"> <el-form-item label="发证日期" prop="issueDate">
<el-date-picker v-model="form.issueDate" type="date" placeholder="请选择发证日期" /> <el-date-picker v-model="form.issueDate" type="date" placeholder="请选择发证日期" value-format="YYYY-MM-DD" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -225,7 +197,7 @@
<el-row :gutter="20" class="mb-4"> <el-row :gutter="20" class="mb-4">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="证书有效期" prop="certificateValidity"> <el-form-item label="证书有效期" prop="certificateValidity">
<el-date-picker v-model="form.certificateValidity" type="date" placeholder="请选择证书有效期" /> <el-date-picker v-model="form.certificateValidity" type="date" placeholder="请选择证书有效期" value-format="YYYY-MM-DD" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@ -248,19 +220,17 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<!-- 第十行安全生产许可证有效期仅劳务类型显示 --> <!-- 第十行安全生产许可证有效期仅劳务类型显示 -->
<el-row :gutter="20" class="mb-4" v-if="form.supplierType === '劳务'"> <el-row :gutter="20" class="mb-4" v-if="form.supplierType === '劳务'">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="安全生产许可证有效期" prop="safeCertificateValidity"> <el-form-item label="安全生产许可证发证日期" prop="safeCertificateValidity">
<el-input v-model="form.safeCertificateValidity" placeholder="请输入有效期" clearable /> <el-date-picker v-model="form.safeCertificateValidity" type="date" placeholder="请选择发证日期" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<!-- 空列占位 --> <!-- 空列占位 -->
</el-col> </el-col>
</el-row> </el-row>
<!-- 第十一行注册人员数量仅劳务类型显示 --> <!-- 第十一行注册人员数量仅劳务类型显示 -->
<el-row :gutter="20" class="mb-4" v-if="form.supplierType === '劳务'"> <el-row :gutter="20" class="mb-4" v-if="form.supplierType === '劳务'">
<el-col :span="12"> <el-col :span="12">
@ -281,44 +251,26 @@
<!-- 空列占位 --> <!-- 空列占位 -->
</el-col> </el-col>
</el-row> </el-row>
<!-- 第十二行职称人员数量仅劳务类型显示 --> <!-- 第十二行职称人员数量仅劳务类型显示 -->
<el-row :gutter="20" class="mb-4" v-if="form.supplierType === '劳务'"> <el-row :gutter="20" class="mb-4" v-if="form.supplierType === '劳务'">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="职称人员数量" prop="personnelNumber1"> <el-form-item label="高级工程师人数" prop="personnelNumber1">
<el-input v-model="form.personnelNumber1" placeholder="请输入职称人员数量" clearable /> <el-input v-model="form.personnelNumber1" placeholder="请输高级工程师数量" clearable />
</el-form-item> </el-form-item>
<el-form-item label="职称人员数量" prop="personnelNumber2"> <el-form-item label="工程师数量" prop="personnelNumber2">
<el-input v-model="form.personnelNumber2" placeholder="请输入职称人员数量" clearable /> <el-input v-model="form.personnelNumber2" placeholder="请输入工程师数量" clearable />
</el-form-item> </el-form-item>
<el-form-item label="职称人员数量" prop="personnelNumber3"> <el-form-item label="助理工程师数量" prop="personnelNumber3">
<el-input v-model="form.personnelNumber3" placeholder="请输入职称人员数量" clearable /> <el-input v-model="form.personnelNumber3" placeholder="请输入助理工程师数量" clearable />
</el-form-item> </el-form-item>
<el-form-item label="职称人员数量" prop="personnelNumber4"> <el-form-item label="其他人员数量" prop="personnelNumber4">
<el-input v-model="form.personnelNumber4" placeholder="请输入职称人员数量" clearable /> <el-input v-model="form.personnelNumber4" placeholder="请输入其他人员数量" clearable />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<!-- 空列占位 --> <!-- 空列占位 -->
</el-col> </el-col>
</el-row> </el-row>
<!-- 第十三行审核状态 -->
<el-row :gutter="20" class="mb-4">
<el-col :span="12">
<!-- 空列占位保持布局对称 -->
</el-col>
<el-col :span="12">
<el-form-item label="审核状态" prop="state" v-if="dialog.title === '修改供应商入库'">
<el-select v-model="form.state" disabled>
<el-option label="待审核" value="0"></el-option>
<el-option label="已通过" value="1"></el-option>
<el-option label="未通过" value="2"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 第十四行入库资料上传 --> <!-- 第十四行入库资料上传 -->
<el-row class="mb-4"> <el-row class="mb-4">
<el-col :span="24"> <el-col :span="24">
@ -347,7 +299,7 @@
> >
<li style="margin-top: 10px" class="el-upload-list__item ele-upload-list__item-content"> <li style="margin-top: 10px" class="el-upload-list__item ele-upload-list__item-content">
<el-link :href="`${fileUrl}`" :underline="false" target="_blank"> <el-link :href="`${fileUrl}`" :underline="false" target="_blank">
<el-button class="el-icon-document"> 下载文件 </el-button> <el-button class="el-icon-document"> 查看文件 </el-button>
</el-link> </el-link>
</li> </li>
</transition-group> </transition-group>
@ -357,7 +309,6 @@
</el-col> </el-col>
</el-row> </el-row>
</el-form> </el-form>
<!-- 对话框底部按钮 --> <!-- 对话框底部按钮 -->
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
@ -372,15 +323,13 @@
<script setup name="SupplierInput" lang="ts"> <script setup name="SupplierInput" lang="ts">
import { ComponentInternalInstance, getCurrentInstance, onMounted, ref, reactive, toRefs, computed } from 'vue'; import { ComponentInternalInstance, getCurrentInstance, onMounted, ref, reactive, toRefs, computed } from 'vue';
import { ElFormInstance } from 'element-plus'; import { ElFormInstance } from 'element-plus';
import { listSupplierInput, getSupplierInput, delSupplierInput, addSupplierInput, updateSupplierInput } from '@/api/supplierInput/supplierInput'; import { listSupplierInput, getSupplierInput, delSupplierInput } from '@/api/supplierInput/supplierInput';
import { SupplierInputVO, SupplierInputQuery, SupplierInputForm, PageData, DialogOption } from '@/api/supplierInput/supplierInput/types'; import { SupplierInputVO, SupplierInputQuery, SupplierInputForm, PageData, DialogOption } from '@/api/supplierInput/supplierInput/types';
import Pagination from '@/components/Pagination/index.vue'; import Pagination from '@/components/Pagination/index.vue';
import RightToolbar from '@/components/RightToolbar/index.vue'; import RightToolbar from '@/components/RightToolbar/index.vue';
import FileUpload from '@/components/FileUpload/index.vue'; import FileUpload from '@/components/FileUpload/index.vue';
// 实例代理
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
// 组件引用 // 组件引用
const fileUploadRef = ref<InstanceType<typeof FileUpload> | null>(null); const fileUploadRef = ref<InstanceType<typeof FileUpload> | null>(null);
const queryFormRef = ref<ElFormInstance>(); const queryFormRef = ref<ElFormInstance>();
@ -403,7 +352,7 @@ const dialog = reactive<DialogOption>({
title: '' title: ''
}); });
// 初始化表单数据 // 初始化表单数据新增build1-build4、personnelNumber1-personnelNumber4字段用于拆分拼接字符串
const initFormData: any = { const initFormData: any = {
id: undefined, id: undefined,
supplierType: undefined, supplierType: undefined,
@ -425,13 +374,21 @@ const initFormData: any = {
safeCode: undefined, safeCode: undefined,
safeCodeData: undefined, safeCodeData: undefined,
safeCertificateValidity: undefined, safeCertificateValidity: undefined,
registeredNumber: undefined, registeredNumber: undefined, // 后端返回的拼接字符串如“1,2,3,4”
personnelNumber: undefined, personnelNumber: undefined, // 后端返回的拼接字符串如“5,6,7,8”
fileId: undefined, fileId: undefined,
inputFile: undefined, inputFile: undefined,
state: '0' // 新增默认待审核 // state: '0', // 新增默认待审核
// 新增:用于表单输入的单独字段
build1: undefined, // 一建建造师
build2: undefined, // 二建建造师
build3: undefined, // 注册造价工程师
build4: undefined, // 其他注册人员
personnelNumber1: undefined, // 高级工程师
personnelNumber2: undefined, // 工程师
personnelNumber3: undefined, // 助理工程师
personnelNumber4: undefined // 其他职称人员
}; };
// 核心数据(表单+查询参数) // 核心数据(表单+查询参数)
const data = reactive<PageData<SupplierInputForm, SupplierInputQuery>>({ const data = reactive<PageData<SupplierInputForm, SupplierInputQuery>>({
form: { ...initFormData }, form: { ...initFormData },
@ -442,6 +399,8 @@ const data = reactive<PageData<SupplierInputForm, SupplierInputQuery>>({
supplierName: undefined, supplierName: undefined,
state: undefined, state: undefined,
inputFile: undefined, inputFile: undefined,
registeredNumber: undefined,
personnelNumber: undefined,
params: {} params: {}
} }
}); });
@ -462,7 +421,14 @@ const rules = computed(() => {
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur' } { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur' }
], ],
id: [{ required: true, message: 'ID不能为空', trigger: 'blur' }], id: [{ required: true, message: 'ID不能为空', trigger: 'blur' }],
build1: [{ required: true, message: '请输入一建建造师数量', trigger: 'change' }] build1: [{ required: true, message: '请输入一建建造师数量', trigger: 'change' }],
build2: [{ required: true, message: '请输入二建建造师数量', trigger: 'change' }],
build3: [{ required: true, message: '请输入注册造价工程师数量', trigger: 'change' }],
build4: [{ required: true, message: '请输入其他数量', trigger: 'change' }],
personnelNumber1: [{ required: true, message: '请输入高级工程师数量', trigger: 'change' }],
personnelNumber2: [{ required: true, message: '请输入工程师数量', trigger: 'change' }],
personnelNumber3: [{ required: true, message: '请输入助理工程师数量', trigger: 'change' }],
personnelNumber4: [{ required: true, message: '请输入其他数量', trigger: 'change' }]
}; };
// 仅当类型为"劳务"时,添加安全生产许可证+人员数量校验 // 仅当类型为"劳务"时,添加安全生产许可证+人员数量校验
@ -472,10 +438,17 @@ const rules = computed(() => {
// 安全生产许可证相关校验 // 安全生产许可证相关校验
safeCode: [{ required: true, message: '请输入安全生产许可证编号', trigger: 'blur' }], safeCode: [{ required: true, message: '请输入安全生产许可证编号', trigger: 'blur' }],
safeCodeData: [{ required: true, message: '请选择安全生产许可证发证日期', trigger: 'change' }], safeCodeData: [{ required: true, message: '请选择安全生产许可证发证日期', trigger: 'change' }],
safeCertificateValidity: [{ required: true, message: '请输入安全生产许可证有效期', trigger: 'blur' }], safeCertificateValidity: [{ required: true, message: '请选择安全生产许可证有效期', trigger: 'change' }],
// 人员数量相关校验 // 注册人员数量校验
registeredNumber: [{ required: true, message: '请输入注册人员数量', trigger: 'blur' }] build1: [{ required: true, message: '请输入一建建造师数量', trigger: 'blur' }],
// personnelNumber: [{ required: true, message: '请输入职称人员数量', trigger: 'blur' }] build2: [{ required: true, message: '请输入二建建造师数量', trigger: 'blur' }],
build3: [{ required: true, message: '请输入注册造价工程师数量', trigger: 'blur' }],
build4: [{ required: true, message: '请输入其他注册人员数量', trigger: 'blur' }],
// 职称人员数量校验
personnelNumber1: [{ required: true, message: '请输入高级工程师数量', trigger: 'blur' }],
personnelNumber2: [{ required: true, message: '请输入工程师数量', trigger: 'blur' }],
personnelNumber3: [{ required: true, message: '请输入助理工程师数量', trigger: 'blur' }],
personnelNumber4: [{ required: true, message: '请输入其他职称人员数量', trigger: 'blur' }]
}; };
} }
@ -491,9 +464,24 @@ const handleTypeChange = () => {
form.value.safeCertificateValidity = undefined; form.value.safeCertificateValidity = undefined;
form.value.registeredNumber = undefined; form.value.registeredNumber = undefined;
form.value.personnelNumber = undefined; form.value.personnelNumber = undefined;
// 清空表单单独字段
form.value.build1 = form.value.build2 = form.value.build3 = form.value.build4 = undefined;
form.value.personnelNumber1 = form.value.personnelNumber2 = form.value.personnelNumber3 = form.value.personnelNumber4 = undefined;
} }
// 重置隐藏字段的校验状态,避免错误提示残留 // 重置隐藏字段的校验状态,避免错误提示残留
supplierInputFormRef.value?.clearValidate(['safeCode', 'safeCodeData', 'safeCertificateValidity', 'registeredNumber', 'personnelNumber']); supplierInputFormRef.value?.clearValidate([
'safeCode',
'safeCodeData',
'safeCertificateValidity',
'build1',
'build2',
'build3',
'build4',
'personnelNumber1',
'personnelNumber2',
'personnelNumber3',
'personnelNumber4'
]);
}; };
/** 查询供应商入库列表 */ /** 查询供应商入库列表 */
@ -536,14 +524,45 @@ const resetQuery = () => {
handleQuery(); handleQuery();
}; };
/** 文件上传成功回调 */ const splitBackEndStrToForm = (resData: any) => {
// const handleUploadSuccess = () => { if (resData.registeredNumber) {
// proxy?.$modal.msgSuccess('操作成功'); const registeredArr = resData.registeredNumber.split(',');
// dialog.visible = false; form.value.build1 = registeredArr[0] || undefined; // 一建建造师
// buttonLoading.value = false; form.value.build2 = registeredArr[1] || undefined; // 二建建造师
// getList(); form.value.build3 = registeredArr[2] || undefined; // 注册造价工程师
// }; form.value.build4 = registeredArr[3] || undefined; // 其他注册人员
}
if (resData.personnelNumber) {
const personnelArr = resData.personnelNumber.split(',');
form.value.personnelNumber1 = personnelArr[0] || undefined; // 高级工程师
form.value.personnelNumber2 = personnelArr[1] || undefined; // 工程师
form.value.personnelNumber3 = personnelArr[2] || undefined; // 助理工程师
form.value.personnelNumber4 = personnelArr[3] || undefined; // 其他职称人员
}
};
/** 审核过程按钮操作 */
const handleAudit = async (row) => {
proxy.$tab.closePage(proxy.$route);
proxy.$router.push({
path: `/approval/supplierInput/indexEdit`,
query: {
id: row.id,
type: 'update'
}
});
};
/** 查看按钮操作 */
const handleAuditView = async (row) => {
proxy.$tab.closePage(proxy.$route);
proxy.$router.push({
path: `/approval/supplierInput/indexEdit`,
query: {
id: row.id,
type: 'view'
}
});
};
/** 文件选择变更 */ /** 文件选择变更 */
const change = () => { const change = () => {
fileUrl.value = ''; fileUrl.value = '';
@ -563,7 +582,6 @@ const handleAdd = () => {
dialog.title = '添加供应商入库'; dialog.title = '添加供应商入库';
}; };
/** 修改操作 */
const handleUpdate = async (row?: SupplierInputVO) => { const handleUpdate = async (row?: SupplierInputVO) => {
reset(); reset();
const _id = row?.id || ids.value[0]; const _id = row?.id || ids.value[0];
@ -571,8 +589,14 @@ const handleUpdate = async (row?: SupplierInputVO) => {
try { try {
const res = await getSupplierInput(_id); const res = await getSupplierInput(_id);
form.value = { ...form.value, ...res.data, inputFile: '' }; const resData = res.data || {};
fileUrl.value = res.data.inputFile; // 1. 基础字段回显
form.value = { ...form.value, ...resData, inputFile: '' };
// 2. 核心修复:拆分后端拼接字符串到表单单独字段
splitBackEndStrToForm(resData);
// 3. 文件地址回显
fileUrl.value = resData.inputFile || '';
// 4. 打开对话框
dialog.visible = true; dialog.visible = true;
dialog.title = '修改供应商入库'; dialog.title = '修改供应商入库';
} catch (error) { } catch (error) {
@ -586,8 +610,15 @@ const submitForm = () => {
supplierInputFormRef.value?.validate(async (valid: boolean) => { supplierInputFormRef.value?.validate(async (valid: boolean) => {
if (!valid) return; if (!valid) return;
form.value.registeredNumber = `${form.value.build1},${form.value.build2},${form.value.build3},${form.value.build4}`; if (form.value.supplierType === '劳务') {
form.value.personnelNumber = `${form.value.personnelNumber1},${form.value.personnelNumber2},${form.value.personnelNumber3},${form.value.personnelNumber4}`; form.value.registeredNumber = [form.value.build1, form.value.build2, form.value.build3, form.value.build4].join(',');
form.value.personnelNumber = [
form.value.personnelNumber1,
form.value.personnelNumber2,
form.value.personnelNumber3,
form.value.personnelNumber4
].join(',');
}
buttonLoading.value = true; buttonLoading.value = true;
try { try {
if (fileUploadRef.value) { if (fileUploadRef.value) {

View File

@ -0,0 +1,521 @@
<template>
<div class="p-4 bg-gray-50 min-h-screen">
<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.state"
: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" disabled :model="form" :rules="rules" label-width="150px" class="space-y-4">
<div class="">
<el-row>
<el-col :span="12">
<el-form-item label="企业登记注册类型" prop="supplierType">
<el-select v-model="form.supplierType" placeholder="请选择供应商类型" @change="handleTypeChange">
<el-option label="劳务" value="劳务"></el-option>
<el-option label="技术服务" value="技术服务"></el-option>
<el-option label="物资设备" value="物资设备"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="企业名称" prop="supplierName">
<el-input v-model="form.supplierName" placeholder="请输入企业名称" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="企业法定代表人" prop="supplierPerson">
<el-input v-model="form.supplierPerson" placeholder="请输入法定代表人" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="统一社会信用代码" prop="supplierCode">
<el-input v-model="form.supplierCode" placeholder="请输入统一社会信用代码" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="企业注册地址" prop="supplierAddres">
<el-input v-model="form.supplierAddres" placeholder="请输入注册地址" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="负责人姓名" prop="personName">
<el-input v-model="form.personName" placeholder="请输入负责人姓名" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="负责人联系电话" prop="personPhone">
<el-input v-model="form.personPhone" placeholder="请输入联系电话" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="纳税规模" prop="taxScale">
<el-select v-model="form.taxScale" placeholder="请选择纳税规模">
<el-option label="一般纳税人" value="一般纳税人"></el-option>
<el-option label="小规模纳税人" value="小规模纳税人"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="开户行户名" prop="bankPersonName">
<el-input v-model="form.bankPersonName" placeholder="请输入开户行户名" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="开户银行" prop="bankName">
<el-input v-model="form.bankName" placeholder="请输入开户银行" clearable />
</el-form-item> </el-col
><el-col :span="12">
<el-form-item label="开户行账号" prop="bankAccount">
<el-input v-model="form.bankAccount" placeholder="请输入开户行账号" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="经营范围" prop="scope">
<el-input v-model="form.scope" placeholder="请输入经营范围" clearable />
</el-form-item> </el-col
><el-col :span="12">
<el-form-item label="企业资质等级" prop="supplierLivel">
<el-input v-model="form.supplierLivel" placeholder="请输入资质等级" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发证日期" prop="issueDate">
<el-date-picker v-model="form.issueDate" type="date" placeholder="请选择发证日期" value-format="YYYY-MM-DD" />
</el-form-item> </el-col
><el-col :span="12">
<el-form-item label="证书有效期" prop="certificateValidity">
<el-date-picker v-model="form.certificateValidity" type="date" placeholder="请选择证书有效期" value-format="YYYY-MM-DD" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="近三年营业额" prop="pastThreeYears">
<el-input v-model="form.pastThreeYears" placeholder="请输入近三年营业额" clearable />
</el-form-item> </el-col
><el-col :span="12">
<el-form-item label="生产许可证编号" prop="safeCode">
<el-input v-model="form.safeCode" placeholder="请输入许可证编号" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="生产许可证发证日期" prop="safeCodeData">
<el-date-picker v-model="form.safeCodeData" type="date" placeholder="请选择发证日期" />
</el-form-item> </el-col
><el-col :span="12">
<el-form-item label="生产许可证发证日期" prop="safeCertificateValidity">
<el-date-picker v-model="form.safeCertificateValidity" type="date" placeholder="请选择发证日期" />
</el-form-item>
</el-col>
</el-row>
<el-row class="mb-4" v-if="form.supplierType === '劳务'">
<el-col :span="12">
<el-form-item label="一建建造师" prop="build1">
<el-input v-model="form.build1" placeholder="请输入一建建造师数量" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="二建建造师" prop="build2">
<el-input v-model="form.build2" placeholder="请输入二建建造师数量" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="其他(分别写)" prop="build4">
<el-input v-model="form.build3" placeholder="请输入其他人员数量" clearable />
</el-form-item> </el-col
><el-col :span="12">
<el-form-item label="注册造价工程师" prop="build3">
<el-input v-model="form.build4" placeholder="请输入注册造价工程师数量" clearable />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24" class="mb-4" v-if="form.supplierType === '劳务'">
<el-col :span="12">
<el-form-item label="高级工程师人数" prop="personnelNumber1">
<el-input v-model="form.personnelNumber1" placeholder="请输高级工程师数量" clearable />
</el-form-item> </el-col
><el-col :span="12">
<el-form-item label="工程师数量" prop="personnelNumber2">
<el-input v-model="form.personnelNumber2" placeholder="请输入工程师数量" clearable />
</el-form-item> </el-col
><el-col :span="12">
<el-form-item label="助理工程师数量" prop="personnelNumber3">
<el-input v-model="form.personnelNumber3" placeholder="请输入助理工程师数量" clearable />
</el-form-item> </el-col
><el-col :span="12">
<el-form-item label="其他人员数量" prop="personnelNumber4">
<el-input v-model="form.personnelNumber4" placeholder="请输入其他人员数量" clearable />
</el-form-item>
</el-col>
</el-row>
</div>
</el-form>
</div>
</el-card>
<!-- 提交组件 -->
<approvalRecord ref="approvalRecordRef"></approvalRecord>
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
<!-- 流程选择对话框 -->
<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 } 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 { StartProcessBo } from '@/api/workflow/workflowCommon/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
import { useUserStoreHook } from '@/store/modules/user';
import { getSupplierInput } from '@/api/supplierInput/supplierInput';
// 获取用户 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 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 flowCodeOptions = [
{
value: currentProject.value?.id + '_supplierInput',
label: '供应商入库审核'
}
];
const initFormData = {
id: undefined,
supplierType: undefined,
supplierName: undefined,
supplierPerson: undefined,
supplierCode: undefined,
supplierAddres: undefined,
personName: undefined,
personPhone: undefined,
bankPersonName: undefined,
bankName: undefined,
bankAccount: undefined,
taxScale: undefined,
scope: undefined,
supplierLivel: undefined,
issueDate: undefined,
certificateValidity: undefined,
pastThreeYears: undefined,
safeCode: undefined,
safeCodeData: undefined,
safeCertificateValidity: undefined,
registeredNumber: undefined, // 后端返回的拼接字符串如“1,2,3,4”
personnelNumber: undefined, // 后端返回的拼接字符串如“5,6,7,8”
fileId: undefined,
inputFile: undefined,
state: '0', // 新增默认待审核
// 新增:用于表单输入的单独字段
build1: undefined, // 一建建造师
build2: undefined, // 二建建造师
build3: undefined, // 注册造价工程师
build4: undefined, // 其他注册人员
personnelNumber1: undefined, // 高级工程师
personnelNumber2: undefined, // 工程师
personnelNumber3: undefined, // 助理工程师
personnelNumber4: undefined // 其他职称人员
};
const data = reactive<PageData<LeaveForm, LeaveQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
projectId: currentProject.value?.id,
fileName: undefined,
fileType: undefined,
fileSuffix: undefined,
fileStatus: undefined,
originalName: undefined,
newest: undefined,
params: {}
},
rules: {
versionNumber: [{ required: true, message: '版本号不能为空', trigger: 'blur' }],
fileName: [{ required: true, message: '文件名称不能为空', trigger: 'blur' }],
fileType: [{ required: true, message: '文件类型不能为空', trigger: 'change' }],
fileUrl: [
{
validator: (rule, value, callback) => {
// 新增时必须上传文件
if (!form.value.fileUrl) {
callback(new Error('请上传图纸文件'));
} else {
callback();
}
},
trigger: 'change'
}
]
}
});
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 getSupplierInput(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;
dialog.visible = false;
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.state === '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 () => {
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>