dev
lion 1 week ago
parent cf475fa609
commit d0c864913f

@ -2,8 +2,8 @@
ENV = 'development'
# base api
VUE_APP_DOMIAN = http://127.0.0.1:8000
VUE_APP_UPLOAD_API = http://127.0.0.1:8000/api/admin/upload-file
VUE_APP_DOMIAN = http://hjjc-hdcontract-test.ali251.langye.net
VUE_APP_UPLOAD_API = http://hjjc-hdcontract-test.ali251.langye.net/api/admin/upload-file
VUE_APP_BASE_API =
VUE_APP_OUT_Book = http://hjjc-book-service-test.ali251.langye.net
VUE_APP_OUT_GDZC = http://hjjc-szemcgdzc.ali251.langye.net/admin

@ -70,6 +70,7 @@ export function resetMoney (params) {
})
}
/** @deprecated 请使用 splitSections */
export function cloneChildren(data) {
return request({
method: 'post',
@ -77,3 +78,35 @@ export function cloneChildren(data) {
data
})
}
export function splitSections(data) {
return request({
method: 'post',
url: '/api/admin/contract/split-sections',
data
})
}
export function getSections(params) {
return request({
method: 'get',
url: '/api/admin/contract/sections',
params
})
}
export function saveSection(data) {
return request({
method: 'post',
url: '/api/admin/contract/section/save',
data
})
}
export function destroySection(params) {
return request({
method: 'get',
url: '/api/admin/contract/section/destroy',
params
})
}

@ -328,7 +328,7 @@ export default {
message: "新增合同",
});
this.isShow = false;
this.$emit("refresh");
this.$emit("refresh", res.id);
})
}
this.form.files = this.fileLists.map(i => i.response?.id)

@ -1,55 +1,85 @@
<template>
<div>
<Modal width="54" v-model="isShow" title="合同拆分" @on-ok="submit">
<div style="margin-bottom: 10px;display: flex;justify-content: space-between;">
<span>新增拆分合同</span>
<el-button type="primary" icon="el-icon-plus" size="small" @click="form.data.push({pid: '',name: row.name,plan_price: row.plan_price})">新增</el-button>
<Modal width="720" v-model="isShow" :title="modalTitle" @on-ok="submit">
<div style="margin-bottom: 10px;display: flex;justify-content: space-between;align-items: center;">
<span>源项目{{ row.name }}</span>
<el-button type="primary" icon="el-icon-plus" size="small" @click="addSection"></el-button>
</div>
<div>
<el-form :model="form" ref="dynamicValidateForm" label-width="100px">
<template v-for="(item, index) in form.data">
<div>
<Tag color="primary" style="height: 28px;line-height: 28px;">{{ '合同'+(index+1) }}</Tag>
<el-button size="mini" type="danger" @click.prevent="form.data.splice(index,1)">删除</el-button>
<el-form :model="form" ref="dynamicValidateForm" label-width="100px">
<div v-for="(item, index) in form.sections" :key="index" style="border: 1px solid #ebeef5;padding: 12px;margin-bottom: 12px;border-radius: 4px;">
<div style="display: flex;justify-content: space-between;margin-bottom: 8px;">
<Tag color="primary">标段 {{ index + 1 }}</Tag>
<el-button size="mini" type="danger" @click.prevent="removeSection(index)">删除</el-button>
</div>
<el-form-item
label="标段编号"
:prop="'sections.' + index + '.section_no'"
>
<el-input v-model="item.section_no" placeholder="如:二标段"></el-input>
</el-form-item>
<el-form-item
label="标段名称"
:prop="'sections.' + index + '.section_name'"
:rules="{ required: true, message: '标段名称不能为空', trigger: 'blur' }"
>
<el-input v-model="item.section_name"></el-input>
</el-form-item>
<el-form-item
label="计划金额"
:prop="'sections.' + index + '.plan_price'"
:rules="{ required: true, message: '计划金额不能为空', trigger: 'blur' }"
>
<el-input-number :min="0" :precision="2" :controls="false" v-model="item.plan_price" style="width: 100%;" @change="syncPlanLinkMoney(item)"></el-input-number>
</el-form-item>
<el-form-item label="供应商">
<el-input v-model="item.supply" placeholder="可选,各标段可不同"></el-input>
</el-form-item>
<el-form-item label="预算分摊" v-if="sourcePlans.length">
<div v-for="(link, li) in item.plan_links" :key="li" style="display:flex;gap:8px;margin-bottom:6px;">
<el-select v-model="link.plan_id" placeholder="预算计划" style="flex:1;">
<el-option v-for="p in sourcePlans" :key="p.plan_id" :label="p.label" :value="p.plan_id"></el-option>
</el-select>
<el-input-number :min="0" :precision="2" :controls="false" v-model="link.use_money" style="width: 140px;"></el-input-number>
</div>
<el-form-item
label="标段名称"
:prop="'data['+index+'].name'"
:rules="{required: true, message: '名称不能为空', trigger: 'blur'}"
>
<el-input v-model="item.name"></el-input>
</el-form-item>
<el-form-item
label="计划金额"
:prop="'data['+index+'].plan_price'"
:rules="{required: true, message: '计划金额不能为空', trigger: 'blur'}"
>
<el-input-number :min="0" :precision="2" :controls="false" v-model="item.plan_price"></el-input-number>
</el-form-item>
</template>
</el-form>
</div>
<el-button v-if="sourcePlans.length > 1" type="text" @click="addPlanLink(item)"></el-button>
</el-form-item>
</div>
</el-form>
</Modal>
</div>
</template>
<script>
import { cloneChildren, detailContract } from "@/api/contract/contract";
import { splitSections, detailContract } from "@/api/contract/contract";
function emptySection() {
return {
section_no: '',
section_name: '',
plan_price: undefined,
supply: '',
plan_links: []
};
}
export default {
data() {
return {
id: "",
isShow: false,
nums: 1,
row: {},
sourcePlans: [],
form: {
data: [
]
},
row: {}
sections: [emptySection()]
}
};
},
computed: {
modalTitle() {
return this.row.split_status ? '继续拆分标段' : '合同拆分';
}
},
methods: {
setId(id) {
this.id = id;
@ -60,43 +90,111 @@ export default {
hide() {
this.isShow = false;
},
addSection() {
const sec = emptySection();
this.initPlanLinks(sec);
this.form.sections.push(sec);
},
removeSection(index) {
if (this.form.sections.length <= 1) {
this.$message.warning('至少保留一个标段');
return;
}
this.form.sections.splice(index, 1);
},
addPlanLink(item) {
item.plan_links.push({ plan_id: this.sourcePlans[0]?.plan_id, use_money: 0 });
},
syncPlanLinkMoney(item) {
if (item.plan_links.length === 1 && item.plan_price != null) {
item.plan_links[0].use_money = item.plan_price;
}
},
initPlanLinks(section) {
if (!this.sourcePlans.length) {
section.plan_links = [];
return;
}
section.plan_links = [{
plan_id: this.sourcePlans[0].plan_id,
use_money: section.plan_price || 0
}];
},
formatPlanLabel(plan) {
if (!plan) {
return '';
}
const year = plan.year ? `[${plan.year}] ` : '';
const pidInfo = plan.pid_info || plan.pidInfo;
const prefix = pidInfo?.name ? `${pidInfo.name} - ` : '';
const name = plan.name || '';
const label = `${year}${prefix}${name}`.trim();
return label || `计划#${plan.id || plan.plan_id}`;
},
buildSourcePlans(row) {
const plans = row.plans || [];
if (plans.length) {
return plans.map(plan => ({
plan_id: plan.id,
label: this.formatPlanLabel(plan)
}));
}
const links = row.plan_link || row.planLink || [];
return links.map(link => ({
plan_id: link.plan_id,
label: link.plan ? this.formatPlanLabel(link.plan) : `计划#${link.plan_id}`
}));
},
async getDetail() {
this.row = await detailContract({ id: this.id })
this.row = await detailContract({ id: this.id });
this.sourcePlans = this.buildSourcePlans(this.row);
this.form.sections = [emptySection()];
this.initPlanLinks(this.form.sections[0]);
},
submit() {
this.$refs['dynamicValidateForm'].validate(valid => {
if(valid) {
let subData = this.form.data.map(i => ({
...this.row,
...i,
pid: this.id,
id: "",
is_substitute: 1
}))
this.$refs.dynamicValidateForm.validate(valid => {
if (!valid) return;
cloneChildren({
data: subData
}).then(res => {
this.$message.success("操作成功")
this.hide()
this.$emit('refresh')
})
for (const sec of this.form.sections) {
if (sec.plan_links && sec.plan_links.length) {
const sum = sec.plan_links.reduce((t, l) => t + Number(l.use_money || 0), 0);
if (Math.abs(sum - Number(sec.plan_price || 0)) > 0.009) {
this.$message.error(`标段「${sec.section_name}」预算分摊须等于计划金额`);
return;
}
}
}
})
splitSections({
contract_id: this.id,
sections: this.form.sections.map(sec => ({
section_no: sec.section_no,
section_name: sec.section_name,
plan_price: sec.plan_price,
supply: sec.supply,
plan_links: (sec.plan_links || []).filter(l => l.plan_id && l.use_money != null)
}))
}).then(() => {
this.$message.success("拆分成功");
this.hide();
this.$emit('refresh');
});
});
},
},
computed: {},
watch: {
isShow(newVal) {
if (newVal) {
this.getDetail();
} else {
this.form.data = []
this.form.sections = [emptySection()];
this.sourcePlans = [];
}
},
id(newVal) {
this.getDetail()
id() {
if (this.isShow) {
this.getDetail();
}
}
},
};

@ -288,7 +288,13 @@
<Button type="primary" @click="toExport()" style="margin-left: 10px"
>导出</Button
>
<!-- <Button type="primary" style="margin-left: 10px">导出</Button>-->
<Button
v-if="$store.state.user.min_allow_level === 0"
type="warning"
style="margin-left: 10px"
:loading="syncOaFlowLoading"
@click="syncOaFlow"
>同步OA流程</Button>
</div>
</slot>
</lx-header>
@ -381,6 +387,24 @@
>合同审批
</Button>
</template>
<template v-if="scope.row.can_split && scope.row.is_contract && hasSplitSections(scope.row)">
<Button
class="slot-btns-item"
size="small"
type="warning"
@click="openSplit(scope.row)"
>继续拆分
</Button>
</template>
<template v-if="scope.row.is_split_child && scope.row.can_delete">
<Button
class="slot-btns-item"
size="small"
type="error"
@click="destroySplitSection(scope.row)"
>删除标段
</Button>
</template>
<!-- <template v-if="scope.row.FLOWSTATUS['shenpi'].isEnabled()&&!scope.row.pid&&scope.row.is_contract">-->
<!-- <Button-->
<!-- class="slot-btns-item"-->
@ -1167,7 +1191,7 @@
<oaFiles ref="oaFiles"></oaFiles>
<addContractLedger ref="addContractLedger" @refresh="getContracts(false,false,true)"></addContractLedger>
<addContractLedger ref="addContractLedger" @refresh="onLedgerSaved"></addContractLedger>
<splitContract ref="splitContract" @refresh="getContracts(false,false,false)"></splitContract>
</div>
@ -1181,7 +1205,8 @@ import {
checkContractName,
updateStatus,
detailContract,
resetMoney
resetMoney,
destroySection
} from "@/api/contract/contract";
import { getparameter } from "@/api/system/dictionary";
import { listdeptNoAuth } from "@/api/system/department";
@ -1458,7 +1483,7 @@ export default {
prop: "sign_plan_count",
width: 120,
formatter: (cell, data, value) => {
if (value == 0) return "暂无";
if (!value || value == 0) return "暂无";
return value + "期";
},
customFn:row => {
@ -1580,11 +1605,13 @@ export default {
fixed: "left",
align: "left",
customFn:row => {
const prefix = row.is_split_child ? ' └ ' : ''
const displayName = row.section_name ? `${prefix}${row.section_no ? row.section_no + ' ' : ''}${row.section_name}` : `${prefix}${row.name}`
if (row.type === 1 && row.end_date && (this.$moment().valueOf() - this.$moment(row.end_date).valueOf()) > 0) {
return (<span style="color: red;"><span>已到期</span><span>{row.name}</span></span>)
return (<span style="color: red;"><span>已到期</span><span>{displayName}</span></span>)
} else {
return (
<span>{row.name}</span>
<span>{displayName}</span>
)
}
}
@ -1650,7 +1677,7 @@ export default {
<br/>
{
(row.FLOWSTATUS.zhaobiao.getStatus() > 1) ? <a style="color: #333" on={{['click']:()=>{
this.$refs['biddingUpload'].setId(row.id)
this.$refs['biddingUpload'].setId(this.flowSourceId(row))
this.$refs['biddingUpload'].show()
}}}>查看</a> : ''
}
@ -1807,7 +1834,7 @@ export default {
prop: "sign_plan_count",
width: 120,
formatter: (cell, data, value) => {
if (value == 0) return "暂无";
if (!value || value == 0) return "暂无";
return value + "期";
},
},
@ -2101,9 +2128,22 @@ export default {
selections: [], //
isShowEditor: false,
syncOaFlowLoading: false,
};
},
methods: {
async syncOaFlow () {
this.syncOaFlowLoading = true
try {
await updateFlow()
this.$message.success('OA流程同步完成')
this.getContracts(false, true)
} catch (e) {
this.$message.error('OA流程同步失败')
} finally {
this.syncOaFlowLoading = false
}
},
resetMoney (row) {
resetMoney({
id: row.id,
@ -2122,8 +2162,13 @@ export default {
}
})
},
/** 采购/招标 OA 关联源 contract */
flowSourceId (row) {
return row.is_split_child && row.split_source_id ? row.split_source_id : row.id
},
async toOaDetail (tbname,row) {
let res;
const flowId = this.flowSourceId(row)
switch (tbname) {
case 'hetong':
res = await httpCurl({
@ -2134,7 +2179,7 @@ export default {
case 'caigou':
res = await httpCurl({
tbname,
out_caigou_id: row.id
out_caigou_id: flowId
})
break;
case 'pay':
@ -2339,16 +2384,55 @@ export default {
},
//
signPre (row) {
if (!row.can_split) {
this.signProcess(row)
return
}
this.$confirm('是否为多标段合同?','提示',{
confirmButtonText: '合同拆分',
cancelButtonText: '合同审批',
distinguishCancelAndClose: true,
closeOnClickModal: false,
type: 'warning'
}).then(_ => {
this.$refs['splitContract'].setId(row.id)
this.$refs['splitContract'].show()
}).catch(_ => {
this.signProcess(row)
this.openSplit(row)
}).catch(action => {
// OA X / ESC
if (action === 'cancel') {
this.signProcess(row)
}
})
},
openSplit(row) {
this.$refs['splitContract'].setId(row.id)
this.$refs['splitContract'].show()
},
/** 已至少拆分出一个标段时才显示「继续拆分」 */
hasSplitSections(row) {
if (row.section_count > 0) {
return true
}
const children = row.split_children || row.splitChildren || []
return children.length > 0
},
destroySplitSection(row) {
this.$confirm('确认删除该标段?删除后不可恢复。', '提示', { type: 'warning' }).then(() => {
destroySection({ id: row.id }).then(() => {
this.$message.success('删除成功')
this.getContracts(false, false, false)
})
}).catch(() => {})
},
buildDisplayList(data) {
const rows = []
;(data || []).forEach(source => {
rows.push(source)
const children = source.split_children || source.splitChildren || []
children.forEach(child => {
rows.push(child)
})
})
return rows
},
async signProcess(row) {
this.setNowContract(row, "hetong");
@ -2491,6 +2575,24 @@ export default {
this.getContracts();
},
//
onLedgerSaved (contractId) {
this.getContracts(false, false, contractId || false)
},
async openOaAfterCreate (row) {
if (!row || row.is_simple === 1) {
return
}
if (row.is_substitute) {
await this.signProcess(row)
return
}
if (
row.purchase_status === 1 &&
((row.req_status === 3 && row.is_plan === 0) || row.is_plan === 1)
) {
await this.buyProcess(row)
}
},
async getContracts(is_export,noloading=false,isopenOa=false) {
const querySelect = {
...this.select,
@ -2524,8 +2626,9 @@ export default {
is_auth: 1,
},noloading);
res.list.data.forEach(i => this.handleContractFlow(i))
this.list = res.list.data;
const displayList = this.buildDisplayList(res.list.data)
displayList.forEach(i => this.handleContractFlow(i))
this.list = displayList;
this.total = res.list.total;
this.tableTotal.fundLogTotal = res.fund_log_total;
this.tableTotal.moneyTotal = Number(res.money_total)
@ -2537,22 +2640,15 @@ export default {
console.log(this.list)
//oa
// OA contract id
if (isopenOa) {
if (res.list.data[0]) {
if (
res.list.data[0].is_simple !== 1 &&
res.list.data[0].purchase_status === 1 &&
((res.list.data[0].req_status === 3 && res.list.data[0].is_plan === 0) ||
res.list.data[0].is_plan === 1) &&
!res.list.data[0].is_substitute
) {
await this.buyProcess(res.list.data[0])
}
if (res.list.data[0].is_simple !== 1 && res.list.data[0].is_substitute ) {
await this.signProcess(res.list.data[0])
}
let row = null
if (typeof isopenOa === 'number') {
row = await detailContract({ id: isopenOa }, true)
} else if (res.list.data[0]) {
row = res.list.data[0]
}
await this.openOaAfterCreate(row)
}
},
@ -2794,7 +2890,7 @@ export default {
"qianding": new Flow(),
"zhifu": new Flow()
}
if (item.is_simple !== 1 && !item.is_substitute) {
if (item.is_simple !== 1 && !item.is_substitute && !item.is_split_child) {
//
flowStatus["caigou"].setStatus(item.purchase_status)
@ -2806,7 +2902,18 @@ export default {
}
}
}
if (item.is_contract && item.purchase_way?.remark === 'true' && !item.is_substitute) {
if (item.is_split_child) {
// contract contract
if (item.is_simple !== 1 && !item.is_substitute) {
flowStatus['caigou'].setStatus(item.purchase_status)
flowStatus['caigou'].setExecutable(false)
}
if (item.is_contract && item.purchase_way?.remark === 'true') {
flowStatus['zhaobiao'].setStatus(item.invite_status)
flowStatus['zhaobiao'].setExecutable(false)
}
}
if (item.is_contract && item.purchase_way?.remark === 'true' && !item.is_substitute && !item.is_split_child) {
// \
flowStatus["zhaobiao"].setStatus(item.invite_status)
if (item.invite_status === 1 && item.purchase_status === 3) {
@ -2823,7 +2930,13 @@ export default {
flowStatus["shenpi"].setExecutable(true)
}
}
if (item.is_contract && !item.is_substitute) {
if (item.is_contract && !item.is_substitute && !item.is_split_child) {
flowStatus["qianding"].setStatus(item.status)
if (item.join_status === 3 && item.status === 1) {
flowStatus["qianding"].setExecutable(true)
}
}
if (item.is_contract && item.is_split_child) {
flowStatus["qianding"].setStatus(item.status)
if (item.join_status === 3 && item.status === 1) {
flowStatus["qianding"].setExecutable(true)
@ -2834,7 +2947,8 @@ export default {
//
if ((!item.is_contract && !item.is_substitute && item.purchase_status === 3) ||
item.status === 2 ||
(!item.is_contract && item.is_simple) || (item.is_contract && item.is_substitute && item.join_status === 3)) {
(!item.is_contract && item.is_simple) || (item.is_contract && item.is_substitute && item.join_status === 3) ||
(item.is_contract && item.is_split_child && item.join_status === 3)) {
//
flowStatus["zhifu"].setExecutable(true)
}

@ -60,6 +60,13 @@
<Button type="primary" style="margin-left: 10px" @click="getFundLogs"
>查询</Button
>
<Button
v-if="$store.state.user.min_allow_level === 0"
type="warning"
style="margin-left: 10px"
:loading="syncPayFlowLoading"
@click="syncPayFlow"
>同步支付审批</Button>
</slot>
</lx-header>
@ -180,6 +187,7 @@ export default {
pageSize: 10,
is_auth: 1,
status: "",
syncPayFlowLoading: false,
table: [
{
label: "项目名称",
@ -300,6 +308,18 @@ export default {
};
},
methods: {
async syncPayFlow () {
this.syncPayFlowLoading = true
try {
await fundlogFlow()
this.$message.success('支付审批流程同步完成')
await this.getFundLogs()
} catch (e) {
this.$message.error('支付审批流程同步失败')
} finally {
this.syncPayFlowLoading = false
}
},
async toOaDetail (row) {
window.open(
`${process.env.VUE_APP_OUT_OLD}/index.php?s=/flow/edit/id/${row.flow_id}&auth_token=${this.$store.getters.oa_token}`,

@ -628,7 +628,7 @@ export default {
department_id: this.select.department_id,
start_audit_date: this.select.start_audit_date,
end_audit_date: this.select.end_audit_date,
sort_name: "updated_at",
sort_name: "created_at",
sort_type: "desc",
}).then((res) => {
let tokens = getToken();

@ -26,8 +26,9 @@ module.exports = {
* Detail: https://cli.vuejs.org/config/#publicpath
*/
publicPath: process.env.ENV === 'staging' ? '/admin_test' : '/admin',
outputDir: process.env.ENV === 'staging' ? '//Users/apple/www/hjjc-contract-business-service/public/admin_test':'//Users/apple/www/hjjc-contract-business-service/public/admin',
// outputDir: '/Users/mac/Documents/朗业/2025/s-苏州环境监测中心/hetong/public/admin',
outputDir: process.env.ENV === 'staging'
? '/Users/mac/Documents/朗业/2025/s-苏州环境监测中心/hjjc-hdcontract/public/admin_test'
: '/Users/mac/Documents/朗业/2025/s-苏州环境监测中心/hjjc-hdcontract/public/admin',
// :'/Users/mac/Documents/朗业/2025/s-苏州环境监测中心/hetong/public/admin',
// /Users/mac/Documents/朗业/2025/s-苏州环境监测中心/hetong/public/admin
assetsDir: 'static',

Loading…
Cancel
Save