Browse Source

年报管理页面

master
xuhuajiao 4 weeks ago
parent
commit
58f3b2867d
  1. 9
      src/api/statistics/statistics.js
  2. 2
      src/router/index.js
  3. 5
      src/router/routers.js
  4. 274
      src/views/archivesStatistics/Da3Report-checkbox.vue
  5. 272
      src/views/archivesStatistics/Da3Report.vue
  6. 376
      src/views/archivesStatistics/annualReport‌/index.vue
  7. 1090
      src/views/archivesStatistics/da3-model.js

9
src/api/statistics/statistics.js

@ -59,6 +59,15 @@ export function FetchBorrowdRegisterStatisticsList(params) {
// }) // })
// } // }
// 报表数据详情
export function FetchInitStatisticsTemplate(data) {
return request({
url: 'api/archives-report/init',
method: 'post',
data
})
}
export default { export default {
FetchTotalStatistics, FetchTotalStatistics,
FetchArchivedAllYear, FetchArchivedAllYear,

2
src/router/index.js

@ -9,7 +9,7 @@ import { filterAsyncRouter } from '@/store/modules/permission'
NProgress.configure({ showSpinner: false })// NProgress Configuration NProgress.configure({ showSpinner: false })// NProgress Configuration
const whiteList = ['/login', '/ssoLogin']// no redirect whitelist
const whiteList = ['/login', '/ssoLogin', '/da3Report']// no redirect whitelist
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
if (to.meta.title) { if (to.meta.title) {

5
src/router/routers.js

@ -83,6 +83,11 @@ export const constantRouterMap = [
path: '/fourTestReport', path: '/fourTestReport',
component: (resolve) => require(['@/views/fourTestReport/index'], resolve), component: (resolve) => require(['@/views/fourTestReport/index'], resolve),
hidden: true hidden: true
},
{
path: '/da3Report',
component: (resolve) => require(['@/views/archivesStatistics/Da3Report'], resolve),
hidden: true
} }
] ]

274
src/views/archivesStatistics/Da3Report-checkbox.vue

@ -0,0 +1,274 @@
<script>
import embeddedModel from './da3-model.js'
export default {
name: 'Da3Report',
props: {
// 后台聚合返回的数据模型(template/units/body/footer);不传则用内置 demo 数据
model: { type: Object, default: null }
},
data() {
return {
form: {},
orgCheck: []
}
},
computed: {
data() {
return this.model || embeddedModel
},
leftUnits() {
return this.data.units.filter(u => u.card === 1) // 01-05
},
rightUnits() {
return this.data.units.filter(u => u.card === 2) // 06-07
},
metaTop() {
return [
{ label: '表号', value: this.data.template.form_no },
{ label: '制定机关', value: this.data.template.issuing_org },
{ label: '批准机关', value: this.data.template.approving_org }
// { label: '批准文号', value: this.data.template.approve_doc_no },
// { label: '有效期至', value: this.data.template.valid_to }
]
}
},
watch: {
data: {
handler(d) {
this.initForm(d)
},
immediate: true
}
},
methods: {
initForm(d) {
const form = {}
d.units.forEach(u => { form['u_' + u.code] = '' })
d.body.forEach(it => {
if (it.type === 'indicator' || it.type === 'continuation') {
form[it.code + '_c'] = '' // 本年
form[it.code + '_p'] = '' // 上年
}
})
this.form = form
},
fillDemo() {
const DEMO = {
u_01: '91420100MA4KXXXXXX', u_02: '阅行客(武汉)科技有限公司', u_03: '130',
u_04: '430000', u_05: '武汉市xx区xx路1号', u_06: '027-88888888', u_07: '独立档案室',
'08_c': '12', '08_p': '10', '09_c': '8', '09_p': '7', '10_c': '2',
'11_c': '5', '12_c': '5', '34_c': '1200', '35_c': '35000', '36_c': '42.5',
'37_c': '800', '38_c': '600', '39_c': '120', '82_c': '5', '95_c': '是',
'96_c': '否', '97_c': '否', '109_c': '1'
}
Object.assign(this.form, DEMO)
},
clearAll() {
Object.keys(this.form).forEach(k => { this.form[k] = '' })
},
buildPayload() {
const units = {}; const reportData = {}
this.data.units.forEach(u => { units[u.code] = this.form['u_' + u.code] || '' })
// 07 机构情况:勾选项同步
if (this.orgCheck.length > 0) {
const labels = []
if (this.orgCheck.includes('1')) labels.push('1.档案馆')
if (this.orgCheck.includes('2')) labels.push('2.档案方如馆等')
units['07'] = labels.join('、')
}
this.data.body.forEach(it => {
if (it.type === 'indicator' || it.type === 'continuation') {
reportData[it.code] = { cur: this.form[it.code + '_c'] || '', prev: this.form[it.code + '_p'] || '' }
}
})
return { units, data: reportData }
},
exportJSON() {
const payload = this.buildPayload()
console.log(JSON.stringify(payload, null, 2))
this.$emit('export', payload)
alert('已导出到控制台(F12),并通过 emit("export") 回传父组件')
}
}
}
</script>
<template>
<div class="da3">
<!-- <div class="toolbar">
<button @click="fillDemo">填入示例数据</button>
<button @click="clearAll">清空</button>
<button @click="exportJSON">导出当前填报 JSON</button>
<span class="hint">数据驱动渲染 · 来自 template_item 等表</span>
</div> -->
<table class="form">
<!-- 附件2 + 题名 -->
<tr><td class="attach" colspan="9">{{ data.template.attach }}</td></tr>
<tr><td class="title" colspan="9">{{ data.template.title }}</td></tr>
<!-- 元信息(表号/制定机关/批准机关) -->
<tr v-for="(m, i) in metaTop" :key="'mt' + i" class="meta-row">
<td colspan="9" class="meta">
<div class="meta-flex">
<!-- <i class="colon">:</i> -->
<span class="meta-label">{{ m.label }}</span>
<i class="colon">:</i>
<span class="meta-value">{{ m.value }}</span>
</div>
</td>
</tr>
<!-- 单位信息卡 01-07(左列 01-05 + 右列 06-07 + 批准文号/有效期) -->
<tr v-for="(u, i) in leftUnits" :key="'lu' + i" :class="['unit-row', { 'unit-row-bordered': i >= 2 }]">
<td class="ucode">{{ u.code }}</td>
<td class="ulabel" colspan="4">{{ u.label }}:<input v-model="form['u_' + u.code]" type="text"></td>
<template v-if="i === 0">
<td class="meta" colspan="4">
<div class="meta-flex">
<span class="meta-label">批准文号</span>
<i class="colon">:</i>
<span class="meta-value">{{ data.template.approve_doc_no }}</span>
</div>
</td></template>
<template v-else-if="i === 1">
<td class="meta" colspan="4">
<div class="meta-flex">
<span class="meta-label">有效期至</span>
<i class="colon">:</i>
<span class="meta-value" style="text-align: right !important; text-align-last: right !important;">{{ data.template.valid_to }}</span>
</div>
</td>
</template>
<template v-if="i === 2 && rightUnits[0]">
<td class="ucode">{{ rightUnits[0].code }}</td>
<td class="ulabel" colspan="3">{{ rightUnits[0].label }}:<input v-model="form['u_' + rightUnits[0].code]" type="text"></td>
</template>
<template v-else-if="i === 3 && rightUnits[1]">
<td class="ucode ucell" rowspan="2">{{ rightUnits[1].code }}</td>
<td class="ulabel ucell" rowspan="2">{{ rightUnits[1].label }}:</td>
<td class="ucell check-cell" colspan="2" rowspan="2">
<label class="check-line"><input v-model="orgCheck" type="checkbox" value="1"> 1.档案馆</label>
<label class="check-line"><input v-model="orgCheck" type="checkbox" value="2"> 2.档案方如馆等</label>
</td>
</template>
<template v-else-if="i === 4" />
<template v-else>
<td colspan="4" />
</template>
</tr>
<!-- 列头 -->
<tr>
<th class="colname" colspan="5">指标名称</th>
<th class="colname">计量单位</th>
<th class="colname">代码</th>
<th class="colname">数量({{ data.template.cur_year }}年)</th>
<th class="colname">上年度数据({{ data.template.prev_year }}年)</th>
</tr>
<tr>
<th class="colsub" colspan="5">甲</th>
<th class="colsub">乙</th>
<th class="colsub">丙</th>
<th class="colsub">1</th>
<th class="colsub" />
</tr>
<!-- 主体 -->
<template v-for="(it, idx) in data.body">
<!-- 章节 / 分组 -->
<tr v-if="it.type === 'section' || it.type === 'group'" :key="'s' + idx" :class="it.type + ' body-row'">
<td class="nm" colspan="5" :style="{ paddingLeft: (it.level * 1.6) + 'em' }">{{ it.name }}</td>
<td class="dash">{{ it.unit || '—' }}</td>
<td class="dash">—</td>
<td class="dash">—</td>
<td class="dash" />
</tr>
<!-- 指标 / 续行 -->
<tr v-if="it.type !== 'section' && it.type !== 'group'" :key="'i' + idx" class="body-row">
<td class="nm" colspan="5" :style="{ paddingLeft: (it.level * 1.6) + 'em' }">{{ it.name }}</td>
<td class="unit">{{ it.unit }}</td>
<td class="code">{{ it.code }}</td>
<td class="data">
<select v-if="it.input === 'yesno'" v-model="form[it.code + '_c']">
<option value="" /><option value="是">是</option><option value="否">否</option>
</select>
<input v-else v-model="form[it.code + '_c']" type="text" inputmode="decimal">
</td>
<td class="data">
<select v-if="it.input === 'yesno'" v-model="form[it.code + '_p']">
<option value="" /><option value="是">是</option><option value="否">否</option>
</select>
<input v-else v-model="form[it.code + '_p']" type="text" inputmode="decimal">
</td>
</tr>
</template>
<!-- 页脚签章 -->
<tr class="footer-row">
<td v-for="(f, fi) in data.footer" :key="'f' + fi" :colspan="fi < data.footer.length - 1 ? data.footer[fi + 1].col - f.col : (10 - f.col)">{{ f.label }}</td>
</tr>
</table>
</div>
</template>
<style scoped>
* { box-sizing: border-box; }
.da3 { font-family: "SimSun", "宋体", serif; color: #000; background: #fff; padding: 20px; }
.toolbar { max-width: 1040px; margin: 0 auto 12px; font-size: 13px; color: #444; }
.toolbar button { font-family: inherit; padding: 4px 10px; margin-right: 8px; cursor: pointer; }
.toolbar .hint { color: #888; }
table.form {
width: 1000px; margin: 0 auto; border-collapse: collapse;
background: #fff; border: hidden;
}
/* 标题、附件、元信息区无边框 */
table.form .attach, table.form .title,
table.form .meta-row td {
border: none;
}
/* 01-02 无边框 */
table.form .unit-row td {
border: none;
}
/* 03-07 有边框 */
table.form .unit-row-bordered td {
border: 1px solid #000;
}
/* 列头 + 数据区有边框 */
table.form .colname, table.form .colsub,
table.form .body-row td {
border-right: 1px solid #000;
}
table.form .colname:last-child,
table.form .colsub:last-child,
table.form .body-row td:last-child {
border-right: none;
}
table.form td, table.form th { padding: 2px 6px; vertical-align: middle; font-size: 13px; line-height: 1.6; }
.attach { font-size: 12px; text-align: left; }
table.form td.title { font-size: 30px !important; font-weight: bold; text-align: center; letter-spacing: 6px; padding: 12px 0; font-family: "SimHei", "黑体", sans-serif; }
.meta { font-size: 12px; white-space: nowrap; }
.meta-flex { display: flex; justify-content: flex-end; align-items: baseline; width: 210px; margin-left: auto; }
.meta-label { display: block; width: 60px; text-align: justify; text-align-last: justify; }
.meta-flex .colon { font-style: normal; }
.meta-value { display: block; flex: 1; margin-left: 5px; text-align: justify; text-align-last: justify; word-break: break-all; }
.ucode { text-align: center; width: 30px; font-weight: bold; white-space: nowrap; }
.ulabel { font-size: 13px; white-space: nowrap; border-right: none !important; }
.ulabel input { width: auto; min-width: 200px; border: none; border: 1px solid #ccc ; font-family: inherit; font-size: 13px; padding: 2px; outline: none; }
.check-line { text-align: left; font-size: 13px; line-height: 1.8; }
.check-cell { white-space: nowrap; border-right: none !important; }
.colname { font-weight: bold; text-align: center; background: #fff; border-top: 1px solid #000; border-bottom: 1px solid #000; white-space: nowrap; }
.colsub { text-align: center; font-size: 12px; color: #000; font-weight: normal; border-bottom: 1px solid #000; white-space: nowrap; }
.section td { font-weight: bold; }
.nm { white-space: pre; }
.unit { text-align: center; width: 60px; white-space: nowrap; }
.code { text-align: center; width: 42px; white-space: nowrap; }
.data { width: 160px; text-align: center; white-space: nowrap; }
.data input, .data select { width: 96%; border: none; border: 1px solid #ccc; padding: 4px 0; font-family: inherit; font-size: 13px; text-align: center; outline: none; }
.dash { text-align: center; }
.footer-row td { border: none; border-top: 1px solid #000; white-space: nowrap; padding: 8px 6px; }
.footer-note td { border: none; padding: 8px 6px; font-size: 12px; }
</style>

272
src/views/archivesStatistics/Da3Report.vue

@ -0,0 +1,272 @@
<script>
import embeddedModel from './da3-model.js'
export default {
name: 'Da3Report',
props: {
// 后台聚合返回的数据模型(template/units/body/footer);不传则用内置 demo 数据
model: { type: Object, default: null }
},
data() {
return {
form: {}
}
},
computed: {
data() {
return this.model || embeddedModel
},
// 查看模式(不可输入)还是编辑模式(可输入),默认查看
isView() {
return this.$route.query.mode !== 'edit'
},
leftUnits() {
return this.data.units.filter(u => u.card === 1) // 01-05
},
rightUnits() {
return this.data.units.filter(u => u.card === 2) // 06-07
},
metaTop() {
return [
{ label: '表号', value: this.data.template.form_no },
{ label: '制定机关', value: this.data.template.issuing_org },
{ label: '批准机关', value: this.data.template.approving_org }
// { label: '批准文号', value: this.data.template.approve_doc_no },
// { label: '有效期至', value: this.data.template.valid_to }
]
}
},
watch: {
data: {
handler(d) {
this.initForm(d)
// TODO: 接口就绪后,改为按路由参数(id)请求真实填报数据后回显
this.fillDemo()
},
immediate: true
}
},
methods: {
initForm(d) {
const form = {}
d.units.forEach(u => { form['u_' + u.code] = '' })
d.body.forEach(it => {
if (it.type === 'indicator' || it.type === 'continuation') {
form[it.code + '_c'] = '' // 本年
form[it.code + '_p'] = '' // 上年
}
})
this.form = form
},
fillDemo() {
const DEMO = {
u_01: '91420100MA4KXXXXXX', u_02: '阅行客(武汉)科技有限公司', u_03: '130',
u_04: '430000', u_05: '武汉市xx区xx路1号', u_06: '027-88888888', u_07: '独立档案室',
'08_c': '12', '08_p': '10', '09_c': '8', '09_p': '7', '10_c': '2',
'11_c': '5', '12_c': '5', '34_c': '1200', '35_c': '35000', '36_c': '42.5',
'37_c': '800', '38_c': '600', '39_c': '120', '82_c': '5', '95_c': '是',
'96_c': '否', '97_c': '否', '109_c': '1'
}
Object.assign(this.form, DEMO)
},
clearAll() {
Object.keys(this.form).forEach(k => { this.form[k] = '' })
},
buildPayload() {
const units = {}; const reportData = {}
this.data.units.forEach(u => { units[u.code] = this.form['u_' + u.code] || '' })
this.data.body.forEach(it => {
if (it.type === 'indicator' || it.type === 'continuation') {
reportData[it.code] = { cur: this.form[it.code + '_c'] || '', prev: this.form[it.code + '_p'] || '' }
}
})
return { units, data: reportData }
},
exportJSON() {
const payload = this.buildPayload()
console.log(JSON.stringify(payload, null, 2))
this.$emit('export', payload)
alert('已导出到控制台(F12),并通过 emit("export") 回传父组件')
}
}
}
</script>
<template>
<div class="da3">
<!-- <div class="toolbar">
<button @click="fillDemo">填入示例数据</button>
<button @click="clearAll">清空</button>
<button @click="exportJSON">导出当前填报 JSON</button>
<span class="hint">数据驱动渲染 · 来自 template_item 等表</span>
</div> -->
<table class="form">
<!-- 附件2 + 题名 -->
<tr><td class="attach" colspan="9">{{ data.template.attach }}</td></tr>
<tr><td class="title" colspan="9">{{ data.template.title }}</td></tr>
<!-- 元信息(表号/制定机关/批准机关) -->
<tr v-for="(m, i) in metaTop" :key="'mt' + i" class="meta-row">
<td colspan="9" class="meta">
<div class="meta-flex">
<!-- <i class="colon">:</i> -->
<span class="meta-label">{{ m.label }}</span>
<i class="colon">:</i>
<span class="meta-value">{{ m.value }}</span>
</div>
</td>
</tr>
<!-- 单位信息卡 01-07(左列 01-05 + 右列 06-07 + 批准文号/有效期) -->
<tr v-for="(u, i) in leftUnits" :key="'lu' + i" :class="['unit-row', { 'unit-row-bordered': i >= 2 }]">
<td class="ucode">{{ u.code }}</td>
<td class="ulabel" colspan="4">{{ u.label }}:<span v-if="isView" class="plain">{{ form['u_' + u.code] }}</span><input v-else v-model="form['u_' + u.code]" type="text"></td>
<template v-if="i === 0">
<td class="meta" colspan="4">
<div class="meta-flex">
<span class="meta-label">批准文号</span>
<i class="colon">:</i>
<span class="meta-value">{{ data.template.approve_doc_no }}</span>
</div>
</td></template>
<template v-else-if="i === 1">
<td class="meta" colspan="4">
<div class="meta-flex">
<span class="meta-label">有效期至</span>
<i class="colon">:</i>
<span class="meta-value" style="text-align: right !important; text-align-last: right !important;">{{ data.template.valid_to }}</span>
</div>
</td>
</template>
<template v-if="i === 2 && rightUnits[0]">
<td class="ucode">{{ rightUnits[0].code }}</td>
<td class="ulabel" colspan="3">{{ rightUnits[0].label }}:<span v-if="isView" class="plain">{{ form['u_' + rightUnits[0].code] }}</span><input v-else v-model="form['u_' + rightUnits[0].code]" type="text"></td>
</template>
<template v-else-if="i === 3 && rightUnits[1]">
<td class="ucode ucell" rowspan="2">{{ rightUnits[1].code }}</td>
<td class="ulabel ucell" colspan="3" rowspan="2">{{ rightUnits[1].label }}:<span v-if="isView" class="plain">{{ form['u_' + rightUnits[1].code] }}</span><input v-else v-model="form['u_' + rightUnits[1].code]" type="text"></td>
</template>
<template v-else-if="i === 4" />
<template v-else>
<td colspan="4" />
</template>
</tr>
<!-- 列头 -->
<tr>
<th class="colname" colspan="5">指标名称</th>
<th class="colname">计量单位</th>
<th class="colname">代码</th>
<th class="colname">数量({{ data.template.cur_year }}年)</th>
<th class="colname">上年度数据({{ data.template.prev_year }}年)</th>
</tr>
<tr>
<th class="colsub" colspan="5">甲</th>
<th class="colsub">乙</th>
<th class="colsub">丙</th>
<th class="colsub">1</th>
<th class="colsub" />
</tr>
<!-- 主体 -->
<template v-for="(it, idx) in data.body">
<!-- 章节 / 分组 -->
<tr v-if="it.type === 'section' || it.type === 'group'" :key="'s' + idx" :class="it.type + ' body-row'">
<td class="nm" colspan="5" :style="{ paddingLeft: (it.level * 1.6) + 'em' }">{{ it.name }}</td>
<td class="dash">{{ it.unit || '—' }}</td>
<td class="dash">—</td>
<td class="dash">—</td>
<td class="dash" />
</tr>
<!-- 指标 / 续行 -->
<tr v-if="it.type !== 'section' && it.type !== 'group'" :key="'i' + idx" class="body-row">
<td class="nm" colspan="5" :style="{ paddingLeft: (it.level * 1.6) + 'em' }">{{ it.name }}</td>
<td class="unit">{{ it.unit }}</td>
<td class="code">{{ it.code }}</td>
<td class="data">
<span v-if="isView" class="plain">{{ form[it.code + '_c'] }}</span>
<select v-else-if="it.input === 'yesno'" v-model="form[it.code + '_c']">
<option value="" /><option value="是">是</option><option value="否">否</option>
</select>
<input v-else v-model="form[it.code + '_c']" type="text" inputmode="decimal">
</td>
<td class="data">
<span v-if="isView" class="plain">{{ form[it.code + '_p'] }}</span>
<select v-else-if="it.input === 'yesno'" v-model="form[it.code + '_p']">
<option value="" /><option value="是">是</option><option value="否">否</option>
</select>
<input v-else v-model="form[it.code + '_p']" type="text" inputmode="decimal">
</td>
</tr>
</template>
<!-- 页脚签章 -->
<tr class="footer-row">
<td v-for="(f, fi) in data.footer" :key="'f' + fi" :colspan="fi < data.footer.length - 1 ? data.footer[fi + 1].col - f.col : (10 - f.col)">{{ f.label }}</td>
</tr>
</table>
</div>
</template>
<style scoped>
* { box-sizing: border-box; }
.da3 { font-family: "SimSun", "宋体", serif; color: #000; background: #fff; padding: 20px; }
.toolbar { max-width: 1040px; margin: 0 auto 12px; font-size: 13px; color: #444; }
.toolbar button { font-family: inherit; padding: 4px 10px; margin-right: 8px; cursor: pointer; }
.toolbar .hint { color: #888; }
table.form {
width: 1000px; margin: 0 auto; border-collapse: collapse;
background: #fff; border: hidden;
}
/* 标题、附件、元信息区无边框 */
table.form .attach, table.form .title,
table.form .meta-row td {
border: none;
}
/* 01-02 无边框 */
table.form .unit-row td {
border: none;
}
/* 03-07 有边框 */
table.form .unit-row-bordered td {
border: 1px solid #000;
}
/* 列头 + 数据区有边框 */
table.form .colname, table.form .colsub,
table.form .body-row td {
border-right: 1px solid #000;
}
table.form .colname:last-child,
table.form .colsub:last-child,
table.form .body-row td:last-child {
border-right: none;
}
table.form td, table.form th { padding: 2px 6px; vertical-align: middle; font-size: 13px; line-height: 1.6; }
.attach { font-size: 12px; text-align: left; }
table.form td.title { font-size: 30px !important; font-weight: bold; text-align: center; letter-spacing: 6px; padding: 12px 0; font-family: "SimHei", "黑体", sans-serif; }
.meta { font-size: 12px; white-space: nowrap; }
.meta-flex { display: flex; justify-content: flex-end; align-items: baseline; width: 210px; margin-left: auto; }
.meta-label { display: block; width: 60px; text-align: justify; text-align-last: justify; }
.meta-flex .colon { font-style: normal; }
.meta-value { display: block; flex: 1; margin-left: 5px; text-align: justify; text-align-last: justify; word-break: break-all; }
.ucode { text-align: center; width: 30px; font-weight: bold; white-space: nowrap; }
.ulabel { font-size: 13px; white-space: nowrap; border-right: none !important; }
.ulabel input { width: auto; min-width: 200px; border: none; border: 1px solid #ccc ; font-family: inherit; font-size: 13px; padding: 2px; outline: none; }
.check-line { text-align: left; font-size: 13px; line-height: 1.8; }
.check-cell { white-space: nowrap; border-right: none !important; }
.colname { font-weight: bold; text-align: center; background: #fff; border-top: 1px solid #000; border-bottom: 1px solid #000; white-space: nowrap; }
.colsub { text-align: center; font-size: 12px; color: #000; font-weight: normal; border-bottom: 1px solid #000; white-space: nowrap; }
.section td { font-weight: bold; }
.nm { white-space: pre; }
.unit { text-align: center; width: 60px; white-space: nowrap; }
.code { text-align: center; width: 42px; white-space: nowrap; }
.data { width: 160px; text-align: center; white-space: nowrap; }
.data input, .data select { width: 96%; border: none; border: 1px solid #ccc; padding: 4px 0; font-family: inherit; font-size: 13px; text-align: center; outline: none; }
/* 查看模式纯文本展示 */
.plain { display: inline-block; min-width: 60px; min-height: 1em; }
.dash { text-align: center; }
.footer-row td { border: none; border-top: 1px solid #000; white-space: nowrap; padding: 8px 6px; }
.footer-note td { border: none; padding: 8px 6px; font-size: 12px; }
</style>

376
src/views/archivesStatistics/annualReport‌/index.vue

@ -0,0 +1,376 @@
<template>
<div class="app-container row-container">
<div class="connection-header collect-header" style="padding: 0; border-top: none; height: auto; margin-bottom: 20px;">
<div class="head-search" style="margin-bottom: 0;">
<el-select
v-model="fondsIds"
multiple
collapse-tags
placeholder="请选择所属全宗"
style="width: 320px;"
>
<el-option
v-for="item in fondsOptions"
:key="item.id"
:label="item.fondsName"
:value="item.id"
/>
</el-select>
<el-select
v-model="years"
multiple
collapse-tags
placeholder="请选择年份"
style="width: 150px;"
>
<el-option
v-for="item in yearsOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
<el-button class="filter-item filter-search" size="mini" type="success" icon="el-icon-search" @click="getTotalStatistics">查询</el-button>
<el-button class="filter-item filter-refresh" size="mini" type="warning" icon="el-icon-refresh-left" @click="resetQuery">重置</el-button>
</div>
<el-button size="mini" :loading="addLoading" @click="toAdd">
<i class="iconfont icon-xinzeng" />
新增
</el-button>
</div>
<el-table v-loading="loading" class="archives-table" :data="allData" style="width: 100%;">
<el-table-column prop="year" label="年度" align="center" />
<el-table-column prop="archivesCount" label="填报单位" />
<el-table-column prop="username" label="创建人" align="center" />
<el-table-column prop="createTime" label="创建时间" align="center">
<template slot-scope="scope">
<div>{{ scope.row.createTime | parseTime }}</div>
</template>
</el-table-column>
<el-table-column prop="modelName" label="统计模板" />
<el-table-column prop="handle" label="操作">
<template slot-scope="scope">
<el-button size="mini" @click="handleDetail(scope.row)">查看详情</el-button>
<el-button size="mini" @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="mini" @click="handleDelete(scope.row)">删除</el-button>
<!-- <el-button :loading="btnLoading" class="packing-handle-btn iconfont" @click="handleCartoning(scope.row)"><svg-icon icon-class="zhuanghe" class="svg-arc-style" />装盒</el-button> -->
</template>
</el-table-column>
</el-table>
<el-pagination
v-if="allData.length !== 0"
:current-page="page.page"
:total="page.total"
:page-size="page.size"
:pager-count="5"
layout="total, prev, pager, next, sizes"
@size-change="handleSizeChange"
@current-change="handleCurrentPage"
/>
<!-- 年报新增/编辑弹框 -->
<el-dialog class="dialog-middle" :modal-append-to-body="false" :close-on-click-modal="false" :before-close="closeFormDialog" :visible="formVisible" :title="dialogTitle" width="560px">
<span class="dialog-right-top" />
<span class="dialog-left-bottom" />
<div class="setting-dialog">
<el-form ref="form" :model="form" :rules="formRules" label-width="90px">
<el-form-item label="全宗" prop="fondsId">
<el-select v-model="form.fondsId" :disabled="isEdit" placeholder="请选择全宗" style="width: 100%;">
<el-option
v-for="item in fondsOptions"
:key="item.id"
:label="item.fondsName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="年度" prop="year">
<el-date-picker v-model="form.year" type="year" value-format="yyyy" :disabled="isEdit" placeholder="请选择年度" style="width: 100%;" />
</el-form-item>
<el-form-item label="统计模板" prop="modelId">
<el-select v-model="form.modelId" :disabled="isEdit" placeholder="请选择统计模板" style="width: 100%;">
<el-option
v-for="item in modelOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remarks">
<el-input v-model="form.remarks" type="textarea" :rows="3" placeholder="请输入备注" />
</el-form-item>
</el-form>
</div>
<div slot="footer" class="dialog-footer">
<el-button v-if="isEdit" type="primary" @click="handleEditDetail">编辑详情</el-button>
<el-button type="text" @click="closeFormDialog">取消</el-button>
<el-button :loading="submitLoading" type="primary" @click="handleSubmit">确定</el-button>
</div>
</el-dialog>
<!-- 年报详情弹框 -->
<el-dialog class="dialog-middle" :modal-append-to-body="false" :close-on-click-modal="false" :before-close="closeDetailDialog" :visible="detailVisible" title="年报详情" width="600px">
<span class="dialog-right-top" />
<span class="dialog-left-bottom" />
<div class="setting-dialog detail-content">
<div class="detail-item"><span class="detail-label">统计年度:</span>{{ detailData.year }}</div>
<div class="detail-item"><span class="detail-label">填报单位:</span>{{ detailData.archivesCount }}</div>
<div class="detail-item"><span class="detail-label">填报人:</span>{{ detailData.username }}</div>
<div class="detail-item"><span class="detail-label">填报时间:</span>{{ detailData.createTime | parseTime }}</div>
<div class="detail-item"><span class="detail-label">备注:</span>{{ detailData.remarks || '-' }}</div>
<div class="detail-item"><span class="detail-label">统计模板:</span>{{ detailData.modelName }}</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleReportDetail">报表详情</el-button>
<el-button type="primary" @click="closeDetailDialog">确定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { FetchFondsAll } from '@/api/system/fonds'
import { FetchTotalStatistics, FetchArchivedAllYear } from '@/api/statistics/statistics'
import { mapGetters } from 'vuex'
export default {
name: 'AnnualReport',
data() {
return {
allData: [],
fondsOptions: [],
fondsIds: [],
yearsOptions: [],
years: [],
loading: false,
// 新增/编辑共用弹框
formVisible: false,
dialogMode: 'add', // 'add' | 'edit'
submitLoading: false,
form: {
id: null,
fondsId: null,
year: String(new Date().getFullYear()),
modelId: null,
remarks: null
},
formRules: {
fondsId: [{ required: true, message: '请选择全宗', trigger: 'change' }],
year: [{ required: true, message: '请选择年度', trigger: 'change' }],
modelId: [{ required: true, message: '请选择统计模板', trigger: 'change' }]
},
addLoading: false,
// 详情弹框
detailVisible: false,
detailData: {},
// 统计模板 mock 数据
modelOptions: [
{ id: 1, name: '《档案室基本情况表》(2025版)' }
],
page: {
page: 1,
total: 0,
size: 10
}
}
},
computed: {
...mapGetters([
'baseApi',
'user'
]),
isEdit() {
return this.dialogMode === 'edit'
},
dialogTitle() {
return this.isEdit ? '年报编辑' : '年报新增'
}
},
mounted() {
this.getFondsDatas()
this.getArchivedAllYearDatas()
this.getTotalStatistics()
},
methods: {
toAdd() {
this.dialogMode = 'add'
this.form = {
id: null,
fondsId: null,
year: String(new Date().getFullYear()),
modelId: null,
remarks: null
}
this.formVisible = true
},
handleEdit(row) {
this.dialogMode = 'edit'
const modelItem = this.modelOptions.find(m => m.name === row.modelName)
const fondsItem = this.fondsOptions.find(f => f.fondsName === row.archivesCount)
this.form = {
id: row.id,
fondsId: fondsItem ? fondsItem.id : null,
year: row.year,
modelId: modelItem ? modelItem.id : null,
remarks: row.remarks
}
this.formVisible = true
},
closeFormDialog() {
this.formVisible = false
this.$refs.form.resetFields()
},
handleSubmit() {
this.$refs.form.validate((valid) => {
if (valid) {
this.submitLoading = true
if (this.isEdit) {
// TODO: 替换为实际编辑接口
const index = this.allData.findIndex(item => item.id === this.form.id)
if (index !== -1) {
this.allData[index].remarks = this.form.remarks
}
this.$message({ message: '编辑成功', type: 'success', offset: 8 })
} else {
// TODO: 替换为实际新增接口
const modelName = this.modelOptions.find(item => item.id === this.form.modelId)?.name
const fondsName = this.fondsOptions.find(item => item.id === this.form.fondsId)?.fondsName
const newRow = {
id: Date.now(),
year: this.form.year,
archivesCount: fondsName,
username: this.user?.username || '',
createTime: new Date().getTime(),
modelName: modelName,
remarks: this.form.remarks
}
this.allData.unshift(newRow)
this.$message({ message: '新增成功', type: 'success', offset: 8 })
}
this.submitLoading = false
this.closeFormDialog()
}
})
},
handleEditDetail() {
const route = this.$router.resolve({ path: '/da3Report', query: { mode: 'edit' }})
window.open(route.href, '_blank')
},
handleSizeChange(val) {
this.page.size = val
this.getTotalStatistics()
},
handleCurrentPage(val) {
this.page.page = val
this.getTotalStatistics()
},
handleDetail(row) {
this.detailData = { ...row }
this.detailVisible = true
},
closeDetailDialog() {
this.detailVisible = false
this.detailData = {}
},
handleReportDetail() {
const route = this.$router.resolve({ path: '/da3Report', query: { mode: 'view' }})
window.open(route.href, '_blank')
},
handleDelete() {
this.$confirm('此操作将删除当前数据' + '<span>你是否还要继续?</span>', '提示', {
confirmButtonText: '继续',
cancelButtonText: '取消',
type: 'warning',
dangerouslyUseHTMLString: true
}).then(() => {
console.log('确认删除')
}).catch(() => {
console.log('取消')
})
},
resetQuery() {
this.fondsIds = []
this.years = []
this.getTotalStatistics()
},
getFondsDatas() {
FetchFondsAll().then(res => {
this.fondsOptions = res
// 默认全选所有档案库
// this.fondsIds = res.map(item => item.id)
// this.checkAndQuery()
})
},
getArchivedAllYearDatas() {
FetchArchivedAllYear().then(res => {
this.yearsOptions = res.map(item => ({
id: item,
name: item
}))
// 默认全选所有年份
// this.years = res.map(item => item)
// this.checkAndQuery()
})
},
checkAndQuery() {
// 当两个数据都加载完成后才执行查询
if (this.fondsOptions.length > 0 && this.yearsOptions.length > 0) {
this.getTotalStatistics()
}
},
getTotalStatistics() {
this.loading = true
FetchTotalStatistics({
fondsIds: this.fondsIds,
years: this.years
}).then(res => {
this.allData = res
this.loading = false
})
}
}
}
</script>
<style lang="scss" scoped>
.app-container {
height: calc(100vh - 140px);
.head-search{
.el-select,
.el-button{
margin-right: 10px;
}
}
::v-deep .el-table__footer{
font-size: 14px;
}
::v-deep .el-table__empty-block{
border-bottom: 1px solid #e4e7ed;
}
::v-deep .summary-row {
background-color: #f5f7fa !important;
td{
border-top: 1px solid #dfe6ec !important;
border-bottom: 1px solid #dfe6ec !important;
}
}
.detail-content {
padding: 10px 20px;
.detail-item {
margin-bottom: 16px;
font-size: 14px;
line-height: 1.6;
color: #545B65;
.detail-label {
display: inline-block;
color: #0C0E1E;
font-weight: 500;
width: 70px;
text-align: right;
}
}
}
::v-deep .el-dialog__footer{
padding: 20px 0;
}
}
</style>

1090
src/views/archivesStatistics/da3-model.js
File diff suppressed because it is too large
View File

Loading…
Cancel
Save