Merge remote-tracking branch 'origin/main'

This commit is contained in:
=
2026-07-15 09:24:24 +08:00
25 changed files with 773 additions and 45 deletions
@@ -9,6 +9,7 @@ CREATE TABLE IF NOT EXISTS `tour_setting` (
`sortNo` int DEFAULT NULL COMMENT '排序编号',
`minGroupPeople` int DEFAULT NULL COMMENT '最少成团人数',
`maxGroupPeople` int DEFAULT NULL COMMENT '最多成团人数',
`inProvinceYears` int DEFAULT 0 COMMENT '省内几年去一次',
`outProvinceYears` int DEFAULT NULL COMMENT '省外几年去一次',
`outProvinceRatio` decimal(10,2) DEFAULT NULL COMMENT '省外人数占比',
`outProvinceRatioType` varchar(50) DEFAULT '当年报名人数' COMMENT '省外人数占比类型',
@@ -154,6 +154,14 @@ layout("/layouts/platform.html"){
<el-col :span="24">
<div class="tour-setting-basic-divider"></div>
</el-col>
<el-col :span="12">
<el-form-item label="省内几年去一次" prop="inProvinceYears">
<el-input-number v-model="formData.inProvinceYears" :controls="false" :min="0" :precision="0" placeholder="请输入省内间隔年限" style="width: 100%"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="24">
<div class="tour-setting-basic-divider"></div>
</el-col>
<el-col :span="12">
<el-form-item label="省外几年去一次" prop="outProvinceYears">
<el-input-number v-model="formData.outProvinceYears" :controls="false" :min="0" :precision="0" placeholder="请输入省外间隔年限" style="width: 100%"></el-input-number>
@@ -364,6 +372,14 @@ layout("/layouts/platform.html"){
callback()
}
}
const checkInProvinceYears = (rule, value, callback) => {
if (value !== null && value !== undefined && value !== ""
&& (!Number.isInteger(Number(value)) || Number(value) < 0)) {
callback(new Error("省内间隔年限必须为非负整数"))
} else {
callback()
}
}
return {
title: "",
dialogVisible: false,
@@ -388,6 +404,7 @@ layout("/layouts/platform.html"){
travelPeopleQuota: [{required: true, message: "必填", trigger: ["blur", "change"]}],
minGroupPeople: [{validator: checkGroupPeople, trigger: ["blur", "change"]}],
maxGroupPeople: [{validator: checkGroupPeople, trigger: ["blur", "change"]}],
inProvinceYears: [{validator: checkInProvinceYears, trigger: ["blur", "change"]}],
outProvinceRatioType: [{required: true, message: "必填", trigger: ["blur", "change"]}],
outProvinceFixedPeople: [{validator: checkOutProvinceFixedPeople, trigger: ["blur", "change"]}],
cycleStartYear: [{validator: checkCycleYear, trigger: ["blur", "change"]}],
@@ -539,6 +556,7 @@ layout("/layouts/platform.html"){
sortNo: 0,
minGroupPeople: 0,
maxGroupPeople: 0,
inProvinceYears: 0,
outProvinceYears: 0,
outProvinceRatio: 0,
outProvinceRatioType: "当年报名人数",
@@ -632,6 +650,7 @@ layout("/layouts/platform.html"){
this.formData = Object.assign({
travelPeopleQuota: 0,
activityGroupId: "",
inProvinceYears: 0,
outProvinceRatioType: "当年报名人数",
outProvinceFixedPeople: 0,
cycleStartYear: "",
@@ -88,7 +88,7 @@ layout("/layouts/platform.html"){
<div style="flex: 1;display: flex;gap: 5px;">
<el-tag
v-for="item in typeOptions"
:key="item.code"
:key="item.id"
:effect="pageForm.typeIds && pageForm.typeIds.includes(item.id) ? 'dark':'plain'"
@click="tagToggle('typeIds',item.id)"
>
@@ -125,6 +125,7 @@ layout("/layouts/platform.html"){
<el-button type="primary" size="small" @click="exportAllProposalFeedBackAsZip">导出反馈表压缩包
</el-button>
<el-button type="primary" size="small" @click="exportSummaryAsExcel">导出汇总表</el-button>
<el-button type="primary" size="small" @click="exportUndertakeUnitTablesAsZip">导出承办单位表压缩包</el-button>
<!-- <el-button type="primary" size="small" @click="exportProposalRegisterSummaryAsExcel">导出立案汇总表-->
<el-button type="primary" size="small" @click="exportCustomAsExcel">自定义导出</el-button>
</table-tool>
@@ -205,6 +206,7 @@ layout("/layouts/platform.html"){
},
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "立案编号", prop: "caseFilingCode"},
{label: "提案名称", prop: "name"},
{label: "提案人", prop: "createUserName"},
{label: "提案类别", prop: "typeName"},
@@ -290,6 +292,15 @@ layout("/layouts/platform.html"){
pageForm: JSON.stringify(this.pageForm)
})
},
exportUndertakeUnitTablesAsZip() {
if (!this.pageForm.sessionId) {
this.$message.warning("请选择教代会")
return
}
this.$downLoad(loc() + "/exportUndertakeUnitTablesAsZip", {
pageForm: JSON.stringify(this.pageForm)
})
},
exportProposalRegisterSummaryAsExcel() {
this.$downLoad("/platform/proposal/export/comprehensive/exportProposalRegisterSummaryAsExcel", {
pageForm: JSON.stringify(this.pageForm)
@@ -313,15 +324,25 @@ layout("/layouts/platform.html"){
},
listProposalType() {
this.$axios.post("/platform/proposal/common/listProposalType").then((res) => {
if (!this.pageForm.sessionId) {
this.$set(this, "typeOptions", [])
return Promise.resolve()
}
return this.$axios.post(loc() + "/listSessionProposalTypes", {
sessionId: this.pageForm.sessionId
}).then((res) => {
if (res.code === 0) {
this.typeOptions = res.data
this.$set(this, "typeOptions", res.data)
}
})
},
async meetingChange(val) {
this.pageForm.delegationId = null
meetingChange(val) {
// 切换届次后旧类别不再适用,需清空选择并加载当前届次类别
this.$set(this.pageForm, "typeIds", [])
this.$set(this, "typeOptions", [])
this.listProposalType()
this.$set(this.pageForm, "delegationId", null)
this.listDelegation()
},
listDelegation() {
@@ -334,9 +355,10 @@ layout("/layouts/platform.html"){
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this, "sessionOptions", res.data)
if (this.sessionOptions && this.sessionOptions.length > 0) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.listProposalType()
this.listDelegation()
this.pageData()
}
@@ -379,7 +401,6 @@ layout("/layouts/platform.html"){
this.listUnderTake()
this.listUnion()
this.listUnit()
this.listProposalType()
}
})
</script>
@@ -101,7 +101,7 @@ layout("/layouts/platform.html"){
<el-col :span="12">
<el-form-item label="提案类型" prop="typeId">
<el-select v-model="formData.typeId" style="width: 100%">
<el-option :key="item.code" :label="item.name" :value="item.id"
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in typeOptions"></el-option>
</el-select>
</el-form-item>
@@ -270,7 +270,7 @@ layout("/layouts/platform.html"){
delegationId: [{required: true, message: "请选择所属代表团", trigger: ["blur", "change"]}],
sessionId: [{required: true, message: "请选择所属教代会", trigger: ["blur", "change"]}],
committeeId: [{required: true, message: "请选择所属委员会", trigger: ["blur", "change"]}],
typeId: [{required: true, message: "请选择提案类", trigger: ["blur", "change"]}],
typeId: [{required: true, message: "请选择提案类", trigger: ["blur", "change"]}],
suggestUnits: [{required: true, message: "请选择建议办理单位", trigger: ["blur", "change"]}],
sign: [{required: true, message: "请扫描二维码进行签字", trigger: ["blur", "change"]}],
excerpt: [{required: true, message: "请填写", trigger: ["blur", "change"]}],
@@ -446,9 +446,15 @@ layout("/layouts/platform.html"){
}
},
// 获取提案类
// 根据当前教代会届次获取允许撰写的提案类
listProposalType() {
this.$axios.post("/platform/proposal/common/listProposalType").then((res) => {
if (!this.formData.sessionId) {
this.typeOptions = []
return Promise.resolve()
}
return this.$axios.post("/platform/proposal/write/listSessionProposalTypes", {
sessionId: this.formData.sessionId
}).then((res) => {
if (res.code === 0) {
this.typeOptions = res.data
}
@@ -466,6 +472,10 @@ layout("/layouts/platform.html"){
//教代会change
async meetingChange(val) {
// 切换届次后,原提案类型不再有效,需按新届次重新选择
this.$set(this.formData, "typeId", null)
this.typeOptions = []
this.listProposalType()
this.formData.delegationId = null
this.formData.committeeId = null
this.listDelegation()
@@ -506,6 +516,7 @@ layout("/layouts/platform.html"){
this.checkWriteTime()
}
await this.listDelegation()
this.listProposalType()
// await this.listSource()
}
})
@@ -578,7 +589,6 @@ layout("/layouts/platform.html"){
created() {
this.init()
this.listSuggestUnit()
this.listProposalType()
this.getProposalConfig()
}
})
@@ -35,7 +35,12 @@ layout("/layouts/platform.html"){
<el-table-column prop="year" label="年份" sortable></el-table-column>
<el-table-column prop="j" label="届数" sortable></el-table-column>
<el-table-column prop="c" label="次数" sortable></el-table-column>
<el-table-column prop="proposalType" label="提案类型" show-overflow-tooltip></el-table-column>
<el-table-column prop="proposalType" label="提案类型" min-width="180">
<template slot-scope="{row}">
<el-tag v-for="item in parseProposalTypes(row.proposalType)" :key="item" size="small"
style="margin-right: 5px">{{item}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="description" label="描述"></el-table-column>
<el-table-column prop="startDate" label="开启时间"></el-table-column>
<el-table-column prop="enable" label="开启状态">
@@ -79,9 +84,9 @@ layout("/layouts/platform.html"){
<dict-select v-model="formData.c" code="TEACHER_CONGRESS_C"></dict-select>
</el-form-item>
<!-- 支持复用历史类型,也允许直接输入并创建新的届次提案类型。 -->
<!-- 支持多选历史类型,也允许直接输入并创建新的届次提案类型。 -->
<el-form-item prop="proposalType" label="提案类型">
<el-select v-model="formData.proposalType" clearable filterable allow-create default-first-option
<el-select v-model="formData.proposalType" multiple clearable filterable allow-create default-first-option
placeholder="请选择或输入提案类型" style="width: 100%">
<el-option v-for="item in proposalTypeOptions" :key="item.proposalType"
:label="item.proposalType" :value="item.proposalType"></el-option>
@@ -143,6 +148,23 @@ layout("/layouts/platform.html"){
el: "#app",
mixins: [initTableMixins],
data() {
// 多选项至少保留一项,单个自定义类型最多 50 个字符,序列化后总长度不超过数据库字段限制。
const validateProposalTypes = (rule, value, callback) => {
const proposalTypes = value || []
if (!proposalTypes.length) {
callback(new Error("请至少选择或输入一个提案类型"))
return
}
if (proposalTypes.some((item) => item && item.trim().length > 50)) {
callback(new Error("单个提案类型最多50个字符"))
return
}
if (JSON.stringify(proposalTypes).length > 1000) {
callback(new Error("提案类型数据不能超过1000个字符"))
return
}
callback()
}
return {
dialogFormVisible: false,
formRules: {
@@ -150,8 +172,7 @@ layout("/layouts/platform.html"){
j: [{required: true, message: "必填", trigger: ["change", "blur"]}],
c: [{required: true, message: "必填", trigger: ["change", "blur"]}],
proposalType: [
{required: true, message: "请选择或输入提案类型", trigger: ["change", "blur"]},
{max: 50, message: "提案类型最多50个字", trigger: ["change", "blur"]}
{validator: validateProposalTypes, trigger: ["change", "blur"]}
],
enable: [{required: true, message: "必填", trigger: ["change", "blur"]}],
description: [{required: true, message: "必填", trigger: ["change", "blur"]}],
@@ -167,7 +188,7 @@ layout("/layouts/platform.html"){
this.dialogFormVisible = true
this.$nextTick(() => {
this.formData = {}
this.$set(this.formData, "proposalType", "")
this.$set(this.formData, "proposalType", [])
})
},
openEdit(id) {
@@ -175,6 +196,7 @@ layout("/layouts/platform.html"){
this.$axios.post(loc() + "/findOne", {id}).then((res) => {
if (res.code === 0) {
res.data.year = res.data.year.toString()
this.$set(res.data, "proposalType", this.parseProposalTypes(res.data.proposalType))
this.formData = res.data
}
})
@@ -184,7 +206,11 @@ layout("/layouts/platform.html"){
this.$refs.formRef.validate((valid) => {
if (valid) {
const loading = createLoading()
this.$axios.post(loc() + (this.formData.id ? "/update" : "/insert"), this.formData).then((res) => {
const submitData = {
...this.formData,
proposalType: JSON.stringify(this.formData.proposalType || [])
}
this.$axios.post(loc() + (this.formData.id ? "/update" : "/insert"), submitData).then((res) => {
if (res.code === 0) {
this.dialogFormVisible = false
this.$message.success(res.msg)
@@ -198,6 +224,22 @@ layout("/layouts/platform.html"){
})
},
// 数据库存储 JSON 数组;同时兼容字段调整前可能存在的单值内容。
parseProposalTypes(proposalType) {
if (Array.isArray(proposalType)) {
return proposalType
}
if (!proposalType) {
return []
}
try {
const values = JSON.parse(proposalType)
return Array.isArray(values) ? values : [proposalType]
} catch (e) {
return [proposalType]
}
},
doDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
@@ -210,10 +210,10 @@ layout("/layouts/platform_h5.html"){
is-link
readonly
name="typeName"
label="提案类"
placeholder="请选择提案类"
label="提案类"
placeholder="请选择提案类"
@click="showTypePicker = true"
:rules="[{ required: true, message: '请选择提案类' }]"
:rules="[{ required: true, message: '请选择提案类' }]"
required
></van-field>
<van-popup v-model="showTypePicker" position="bottom">
@@ -411,7 +411,7 @@ layout("/layouts/platform_h5.html"){
},
onTypeConfirm(value) {
this.formData.typeId = value.value;
this.$set(this.formData, 'typeId', value.value);
this.$set(this.formData, 'typeName', value.text);
this.showTypePicker = false;
},
@@ -589,9 +589,15 @@ layout("/layouts/platform_h5.html"){
}
},
// 获取提案类
// 根据当前教代会届次获取允许撰写的提案类
listProposalType() {
this.$axios.post("/platform/proposal/common/listProposalType").then((res) => {
if (!this.formData.sessionId) {
this.typeOptions = [];
return Promise.resolve();
}
return this.$axios.post("/platform/proposal/write/listSessionProposalTypes", {
sessionId: this.formData.sessionId
}).then((res) => {
if (res.code === 0) {
this.typeOptions = res.data;
}
@@ -609,6 +615,11 @@ layout("/layouts/platform_h5.html"){
//教代会change
async meetingChange(val) {
// 切换届次后清空旧值,并加载新届次允许选择的提案类型
this.$set(this.formData, "typeId", null);
this.$set(this.formData, "typeName", "");
this.typeOptions = [];
this.listProposalType();
this.formData.delegationId = null;
this.formData.committeeId = null;
this.formData.delegationName = '';
@@ -646,6 +657,7 @@ layout("/layouts/platform_h5.html"){
if (!isModify && this.sessionOptions && this.sessionOptions.length > 0) {
this.$set(this.formData, "sessionId", this.sessionOptions[0].id);
this.$set(this.formData, "sessionName", this.sessionOptions[0].fullName);
this.listProposalType();
await this.listDelegation();
await this.listSource();
// 获取代表团
@@ -655,7 +667,9 @@ layout("/layouts/platform_h5.html"){
} else {
await this.listDelegation();
await this.listSource();
this.echoPicker()
this.listProposalType().then(() => {
this.echoPicker();
});
}
}
});
@@ -742,7 +756,6 @@ layout("/layouts/platform_h5.html"){
created() {
this.init();
this.listSuggestUnit();
this.listProposalType();
this.getProposalConfig();
},
watch: {