collectiveMain.vue 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296
  1. <template>
  2. <div class="collective">
  3. <div class="collective-header">
  4. <div class="collective-header-left">
  5. <span>集体审议</span>
  6. </div>
  7. <div v-if="isEditable" class="collective-header-right">
  8. <el-button type="primary" @click="handlePrint">补充资料</el-button>
  9. <el-button type="primary" @click="handleAddRecord">新增记录</el-button>
  10. </div>
  11. </div>
  12. <!-- 集体审议记录列表 -->
  13. <div class="collective-list">
  14. <el-table :data="recordList" style="width: 100%" border>
  15. <el-table-column
  16. type="index"
  17. label="序号"
  18. width="80"
  19. header-align="center"
  20. align="center"
  21. />
  22. <el-table-column
  23. prop="deliberationForm"
  24. label="审议形式"
  25. header-align="center"
  26. align="center"
  27. />
  28. <el-table-column
  29. prop="location"
  30. label="地点"
  31. header-align="center"
  32. align="center"
  33. />
  34. <el-table-column
  35. prop="hostPerson"
  36. label="主持人"
  37. header-align="center"
  38. align="center"
  39. />
  40. <el-table-column
  41. prop="reviewTime"
  42. label="审议时间"
  43. header-align="center"
  44. align="center"
  45. />
  46. <el-table-column
  47. prop="attachments"
  48. label="附件"
  49. width="80"
  50. header-align="center"
  51. align="center"
  52. >
  53. <template slot-scope="scope">
  54. <el-tooltip
  55. v-if="scope.row.attachments && scope.row.attachments.length > 0"
  56. content="查看附件"
  57. placement="top"
  58. >
  59. <el-button type="text" @click="handleViewAttachment(scope.row)">
  60. <i class="el-icon-document"></i>
  61. </el-button>
  62. </el-tooltip>
  63. </template>
  64. </el-table-column>
  65. <el-table-column
  66. v-if="isEditable"
  67. label="操作"
  68. width="120"
  69. header-align="center"
  70. align="center"
  71. >
  72. <template slot-scope="scope">
  73. <el-button type="text" @click="handleEditRecord(scope.row)">
  74. 修改
  75. </el-button>
  76. <el-button
  77. type="text"
  78. style="color: #f56c6c"
  79. @click="handleDeleteRecord(scope.row)"
  80. >
  81. 删除
  82. </el-button>
  83. </template>
  84. </el-table-column>
  85. </el-table>
  86. </div>
  87. <!-- 新增/修改集体审议记录弹窗 -->
  88. <el-dialog
  89. :title="dialogTitle"
  90. :visible.sync="showRecordDialog"
  91. width="800px"
  92. :close-on-click-modal="false"
  93. :close-on-press-escape="false"
  94. :modal="false"
  95. append-to-body
  96. >
  97. <div class="record-form">
  98. <!-- 表单行:审议形式 -->
  99. <div class="form-row">
  100. <div class="form-item">
  101. <label class="form-label required">审议形式</label>
  102. <el-input
  103. v-model="formData.deliberationForm"
  104. placeholder="请输入审议形式"
  105. class="form-input"
  106. ></el-input>
  107. </div>
  108. </div>
  109. <!-- 表单行:时间 -->
  110. <div class="form-row">
  111. <div class="form-item">
  112. <label class="form-label required">时间</label>
  113. <div class="time-picker">
  114. <el-date-picker
  115. v-model="formData.startDate"
  116. type="datetime"
  117. placeholder="开始时间"
  118. value-format="yyyy-MM-dd HH:mm"
  119. :picker-options="startDateOptions"
  120. class="date-picker"
  121. ></el-date-picker>
  122. <span class="date-range-separator">至</span>
  123. <el-date-picker
  124. v-model="formData.endDate"
  125. type="datetime"
  126. placeholder="结束时间"
  127. value-format="yyyy-MM-dd HH:mm"
  128. :picker-options="endDateOptions"
  129. class="date-picker"
  130. ></el-date-picker>
  131. </div>
  132. </div>
  133. </div>
  134. <!-- 表单行:地点 -->
  135. <div class="form-row">
  136. <div class="form-item">
  137. <label class="form-label required">地点</label>
  138. <el-input
  139. v-model="formData.location"
  140. placeholder="请输入地点"
  141. class="form-input"
  142. ></el-input>
  143. </div>
  144. </div>
  145. <!-- 表单行:主持人和记录人 -->
  146. <div class="form-row">
  147. <div class="form-item form-item-compact">
  148. <label class="form-label required">主持人</label>
  149. <el-input
  150. v-model="formData.hostPerson"
  151. placeholder="请输入参加人员"
  152. class="form-input"
  153. ></el-input>
  154. <label class="required">记录人</label>
  155. <el-input
  156. v-model="formData.recordPerson"
  157. placeholder="请输入记录人"
  158. class="form-input"
  159. ></el-input>
  160. </div>
  161. </div>
  162. <!-- 表单行:参加人员 -->
  163. <div class="form-row">
  164. <div class="form-item">
  165. <label class="form-label required">参加人员</label>
  166. <el-input
  167. v-model="formData.participants"
  168. placeholder="请输入参加人员"
  169. class="form-input"
  170. ></el-input>
  171. </div>
  172. </div>
  173. <!-- 表单行:审议项目 -->
  174. <div class="form-row">
  175. <div class="form-item">
  176. <label class="form-label">审议项目</label>
  177. <el-input
  178. v-model="formData.reviewProject"
  179. placeholder="自动获取项目名称"
  180. readonly
  181. class="form-input readonly-input"
  182. ></el-input>
  183. </div>
  184. </div>
  185. <!-- 表单行:被审单位 -->
  186. <div class="form-row">
  187. <div class="form-item">
  188. <label class="form-label">被审单位</label>
  189. <el-input
  190. v-model="formData.auditedUnit"
  191. placeholder="自动获取被审单位名称"
  192. readonly
  193. class="form-input readonly-input"
  194. ></el-input>
  195. </div>
  196. </div>
  197. <!-- 表单行:审议情况 -->
  198. <div class="form-row">
  199. <div class="form-item">
  200. <label class="form-label required">审议情况</label>
  201. <el-input
  202. v-model="formData.reviewSituation"
  203. type="textarea"
  204. :rows="5"
  205. placeholder="填写"
  206. class="form-textarea"
  207. ></el-input>
  208. </div>
  209. </div>
  210. <!-- 表单行:审议结论意见 -->
  211. <div class="form-row">
  212. <div class="form-item">
  213. <label class="form-label required">审议结论意见</label>
  214. <el-input
  215. v-model="formData.reviewConclusion"
  216. type="textarea"
  217. :rows="5"
  218. placeholder="填写"
  219. class="form-textarea"
  220. ></el-input>
  221. </div>
  222. </div>
  223. <!-- 表单行:审议记录扫描件 -->
  224. <div class="form-row">
  225. <div class="form-item">
  226. <label class="form-label required">审议记录扫描件</label>
  227. <div class="upload-file">
  228. <el-upload
  229. class="upload-demo"
  230. :auto-upload="false"
  231. :on-change="handleFileChange"
  232. :file-list="fileList"
  233. accept=".doc,.docx,.pdf"
  234. >
  235. <el-button size="small" type="primary">选择文件</el-button>
  236. <div slot="tip" class="el-upload__tip">
  237. 只能上传doc、docx、pdf格式文件
  238. </div>
  239. </el-upload>
  240. <div v-if="fileList.length > 0" class="file-name">
  241. <a
  242. :href="fileList[0].url || '#'"
  243. target="_blank"
  244. class="file-link"
  245. >
  246. {{ fileList[0].name }}
  247. </a>
  248. </div>
  249. </div>
  250. </div>
  251. </div>
  252. </div>
  253. <!-- 弹窗底部按钮 -->
  254. <div slot="footer" class="dialog-footer">
  255. <el-button class="cancel-btn" @click="handleCancel">取消</el-button>
  256. <el-button type="primary" class="save-btn" @click="handleSave">
  257. 保存
  258. </el-button>
  259. </div>
  260. </el-dialog>
  261. <!-- 补充资料弹窗 -->
  262. <el-dialog
  263. :visible.sync="showSupplementDialog"
  264. title="补充资料"
  265. width="600px"
  266. :modal="false"
  267. custom-class="supplement-dialog"
  268. >
  269. <div class="supplement-dialog-content">
  270. <div class="supplement-form-item">
  271. <label class="supplement-form-label required">补充意见:</label>
  272. <el-input
  273. v-model="additionalParams.content"
  274. type="textarea"
  275. :rows="6"
  276. placeholder="请输入补充意见"
  277. maxlength="500"
  278. show-word-limit
  279. class="supplement-textarea"
  280. />
  281. </div>
  282. <div class="supplement-form-item">
  283. <label class="supplement-form-label required">选择子单位:</label>
  284. <el-select
  285. v-model="additionalParams.selectedSubUnits"
  286. multiple
  287. collapse-tags
  288. placeholder="请选择子单位"
  289. class="supplement-select"
  290. filterable
  291. >
  292. <el-option
  293. v-for="unit in subUnitList"
  294. :key="unit.id"
  295. :label="unit.name"
  296. :value="unit.id"
  297. />
  298. </el-select>
  299. </div>
  300. <!-- <div class="supplement-form-item">
  301. <label class="supplement-form-label required">发送方式:</label>
  302. <el-checkbox-group v-model="additionalParams.sendType">
  303. <el-checkbox label="site">站内消息</el-checkbox>
  304. <el-checkbox label="sms">短信通知</el-checkbox>
  305. </el-checkbox-group>
  306. </div> -->
  307. </div>
  308. <div slot="footer" class="supplement-dialog-footer">
  309. <el-button @click="showSupplementDialog = false">取消</el-button>
  310. <el-button type="primary" @click="submitSupplement">发送</el-button>
  311. </div>
  312. </el-dialog>
  313. </div>
  314. </template>
  315. <script>
  316. import {
  317. addCollectiveDeliberate,
  318. updateCollectiveDeliberate,
  319. deleteCollectiveDeliberate,
  320. getCollectiveDeliberateList,
  321. getSubUnitList,
  322. } from '@/api/audit/collective'
  323. import { getReviewTask } from '@/api/audit/reviewTask'
  324. export default {
  325. name: 'CollectiveMain',
  326. components: {},
  327. props: {
  328. visible: {
  329. type: Boolean,
  330. default: true,
  331. },
  332. id: {
  333. type: [String, Number],
  334. default: null,
  335. },
  336. currentNode: {
  337. type: String,
  338. default: '',
  339. },
  340. currentStatus: {
  341. type: String,
  342. default: '',
  343. },
  344. projectName: {
  345. type: String,
  346. default: '',
  347. },
  348. auditObject: {
  349. type: String,
  350. default: '',
  351. },
  352. isEditable: {
  353. type: Boolean,
  354. default: true,
  355. },
  356. },
  357. data() {
  358. return {
  359. // 记录列表数据
  360. recordList: [],
  361. // 弹窗显示状态
  362. showRecordDialog: false,
  363. showSupplementDialog: false,
  364. // 表单数据
  365. formData: {
  366. id: '',
  367. deliberationForm: '',
  368. startDate: '',
  369. endDate: '',
  370. location: '',
  371. hostPerson: '',
  372. recordPerson: '',
  373. participants: '',
  374. reviewProject: '',
  375. auditedUnit: '',
  376. reviewSituation: '',
  377. reviewConclusion: '',
  378. attachments: [],
  379. },
  380. // 文件列表
  381. fileList: [],
  382. // 当前操作类型:add/edit
  383. operationType: 'add',
  384. // 补充资料弹窗数据
  385. additionalParams: {
  386. content: '',
  387. // sendType: [],
  388. selectedSubUnits: [],
  389. },
  390. // 子单位列表
  391. subUnitList: [],
  392. // 模拟用户列表数据
  393. userList: [
  394. { id: 1, name: '张三' },
  395. { id: 2, name: '李四' },
  396. { id: 3, name: '王五' },
  397. ],
  398. // 开始时间选择器选项
  399. startDateOptions: {
  400. disabledDate: (time) => {
  401. if (this.formData.endDate) {
  402. return time.getTime() > new Date(this.formData.endDate).getTime()
  403. }
  404. return false
  405. },
  406. disabledTime: (date) => {
  407. if (this.formData.endDate) {
  408. const endDate = new Date(this.formData.endDate)
  409. if (
  410. date.getFullYear() === endDate.getFullYear() &&
  411. date.getMonth() === endDate.getMonth() &&
  412. date.getDate() === endDate.getDate()
  413. ) {
  414. return {
  415. disabledHours: () => {
  416. const hours = []
  417. const endHour = endDate.getHours()
  418. for (let i = endHour + 1; i < 24; i++) {
  419. hours.push(i)
  420. }
  421. return hours
  422. },
  423. disabledMinutes: (selectedHour) => {
  424. if (selectedHour === endHour) {
  425. const minutes = []
  426. const endMinute = endDate.getMinutes()
  427. for (let i = endMinute + 1; i < 60; i++) {
  428. minutes.push(i)
  429. }
  430. return minutes
  431. }
  432. return []
  433. },
  434. }
  435. }
  436. }
  437. return {}
  438. },
  439. },
  440. // 结束时间选择器选项
  441. endDateOptions: {
  442. disabledDate: (time) => {
  443. if (this.formData.startDate) {
  444. return (
  445. time.getTime() < new Date(this.formData.startDate).getTime()
  446. )
  447. }
  448. return time.getTime() < Date.now() - 8.64e7 // 禁止选择过去的日期
  449. },
  450. disabledTime: (date) => {
  451. if (this.formData.startDate) {
  452. const startDate = new Date(this.formData.startDate)
  453. if (
  454. date.getFullYear() === startDate.getFullYear() &&
  455. date.getMonth() === startDate.getMonth() &&
  456. date.getDate() === startDate.getDate()
  457. ) {
  458. return {
  459. disabledHours: () => {
  460. const hours = []
  461. const startHour = startDate.getHours()
  462. for (let i = 0; i < startHour; i++) {
  463. hours.push(i)
  464. }
  465. return hours
  466. },
  467. disabledMinutes: (selectedHour) => {
  468. if (selectedHour === startHour) {
  469. const minutes = []
  470. const startMinute = startDate.getMinutes()
  471. for (let i = 0; i < startMinute; i++) {
  472. minutes.push(i)
  473. }
  474. return minutes
  475. }
  476. return []
  477. },
  478. }
  479. }
  480. }
  481. return {}
  482. },
  483. },
  484. }
  485. },
  486. computed: {
  487. dialogTitle() {
  488. return this.operationType === 'add'
  489. ? '新增集体审议记录'
  490. : '修改集体审议记录'
  491. },
  492. },
  493. mounted() {
  494. this.loadRecordList()
  495. this.getProjectInfo()
  496. },
  497. methods: {
  498. // 加载记录列表
  499. loadRecordList() {
  500. // 调用API获取集体审议记录列表
  501. const queryParams = {
  502. taskId: this.id, // 使用props传入的id作为项目ID
  503. }
  504. getCollectiveDeliberateList(queryParams)
  505. .then((res) => {
  506. if (res && res.state && res.code === 200) {
  507. // 根据新的接口返回格式,从res.value中获取数据
  508. const data = res.value.records || []
  509. // 处理返回的数据,转换为前端表格需要的格式
  510. this.recordList = Array.isArray(data)
  511. ? data.map((item) => ({
  512. id: item.id,
  513. deliberationForm: item.deliberationForm,
  514. location: item.location,
  515. hostPerson: item.hostPerson,
  516. recordPerson: item.recordPerson,
  517. reviewTime: item.beginTime,
  518. attachments: item.attachmentIds
  519. ? item.attachmentIds.split(',').map((attachmentId) => ({
  520. name: `附件_${attachmentId}`,
  521. url: '#', // 实际应该根据附件ID获取完整URL
  522. }))
  523. : [],
  524. }))
  525. : []
  526. } else {
  527. this.$message.error(res.message || '获取记录列表失败')
  528. // 如果API调用失败,使用模拟数据
  529. this.recordList = []
  530. }
  531. })
  532. .catch((error) => {
  533. this.$message.error('获取记录列表失败:' + error.message)
  534. // 错误时使用模拟数据
  535. })
  536. },
  537. // 获取项目信息
  538. getProjectInfo() {
  539. // 模拟获取项目信息,实际应该调用API
  540. this.formData.reviewProject = 'XX项目成本监审'
  541. this.formData.auditedUnit = 'XX有限公司'
  542. },
  543. // 补充资料
  544. handlePrint() {
  545. this.additionalParams = {
  546. content: '',
  547. // sendType: [],
  548. selectedSubUnits: [],
  549. }
  550. this.loadSubUnitList()
  551. this.showSupplementDialog = true
  552. },
  553. // 加载子单位列表
  554. async loadSubUnitList() {
  555. if (!this.id) {
  556. return
  557. }
  558. try {
  559. const res = await getSubUnitList({ taskId: this.id })
  560. if (res && res.code === 200 && res.value) {
  561. this.subUnitList = Array.isArray(res.value)
  562. ? res.value.map((item) => ({
  563. id: item.id || item.unitId,
  564. name: item.name || item.unitName,
  565. taskId: item.taskId || item.childTaskId, // 保存子任务ID
  566. }))
  567. : []
  568. } else {
  569. this.subUnitList = []
  570. }
  571. } catch (error) {
  572. console.error('获取子单位列表失败:', error)
  573. this.subUnitList = []
  574. }
  575. },
  576. // 提交补充资料
  577. async submitSupplement() {
  578. // 验证补充意见
  579. if (
  580. !this.additionalParams.content ||
  581. !this.additionalParams.content.trim()
  582. ) {
  583. this.$message.error('请输入补充意见')
  584. return
  585. }
  586. // 验证任务ID
  587. if (!this.id) {
  588. this.$message.error('缺少任务ID')
  589. return
  590. }
  591. // 验证选择子单位
  592. if (
  593. !this.additionalParams.selectedSubUnits ||
  594. this.additionalParams.selectedSubUnits.length === 0
  595. ) {
  596. this.$message.error('请选择子单位')
  597. return
  598. }
  599. // 验证发送方式
  600. // if (
  601. // !this.additionalParams.sendType ||
  602. // this.additionalParams.sendType.length === 0
  603. // ) {
  604. // this.$message.error('请选择发送方式')
  605. // return
  606. // }
  607. try {
  608. // 转换发送方式:site -> 1, sms -> 2
  609. // const sendTypeMap = {
  610. // site: '1',
  611. // sms: '2',
  612. // }
  613. // const sendTypeStr = this.additionalParams.sendType
  614. // .map((type) => sendTypeMap[type])
  615. // .filter(Boolean)
  616. // .join(',')
  617. // 获取子任务ID(选中的子单位ID)
  618. const childTaskId = this.additionalParams.selectedSubUnits.join(',')
  619. const params = {
  620. taskId: this.id,
  621. processNodeKey: this.currentNode || '',
  622. key: 1,
  623. // sendType: sendTypeStr,
  624. content: this.additionalParams.content,
  625. childTaskId: childTaskId,
  626. }
  627. const response = await getReviewTask(params)
  628. if (response && response.code === 200) {
  629. this.$message.success(response.message || '补充资料发送成功')
  630. // 关闭弹窗
  631. this.showSupplementDialog = false
  632. // 重置表单数据
  633. this.additionalParams = {
  634. content: '',
  635. // sendType: [],
  636. selectedSubUnits: [],
  637. }
  638. } else {
  639. this.$message.error(response?.message || '补充资料发送失败')
  640. }
  641. } catch (error) {
  642. console.error('补充资料发送失败:', error)
  643. this.$message.error('补充资料发送失败')
  644. }
  645. },
  646. // 新增记录
  647. handleAddRecord() {
  648. this.operationType = 'add'
  649. this.resetForm()
  650. this.showRecordDialog = true
  651. },
  652. // 编辑记录
  653. handleEditRecord(row) {
  654. this.operationType = 'edit'
  655. // 复制数据到表单
  656. this.formData = {
  657. id: row.id,
  658. deliberationForm: row.deliberationForm,
  659. location: row.location,
  660. // 解析时间,实际应该根据API返回格式处理
  661. startDate: row.reviewTime,
  662. endDate: row.reviewTime,
  663. hostPerson: row.hostPerson,
  664. recordPerson: row.recordPerson,
  665. participants: '',
  666. reviewProject: this.formData.reviewProject,
  667. auditedUnit: this.formData.auditedUnit,
  668. reviewSituation: '',
  669. reviewConclusion: '',
  670. attachments: row.attachments || [],
  671. }
  672. // 设置文件列表
  673. this.fileList = row.attachments
  674. ? row.attachments.map((file) => ({
  675. name: file.name,
  676. url: file.url,
  677. uid: file.name,
  678. }))
  679. : []
  680. this.showRecordDialog = true
  681. },
  682. // 删除记录
  683. handleDeleteRecord(row) {
  684. this.$confirm('确定要删除这条记录吗?', '删除确认', {
  685. confirmButtonText: '确定',
  686. cancelButtonText: '取消',
  687. type: 'warning',
  688. })
  689. .then(() => {
  690. // 调用API进行删除操作
  691. deleteCollectiveDeliberate(row.id)
  692. .then((res) => {
  693. if (res && res.state && res.code === 200) {
  694. this.$message.success('删除成功')
  695. this.loadRecordList() // 重新加载记录列表
  696. } else {
  697. this.$message.error(res.message || '删除失败')
  698. }
  699. })
  700. .catch((error) => {
  701. this.$message.error('删除失败:' + error.message)
  702. })
  703. })
  704. .catch(() => {
  705. this.$message.info('已取消删除')
  706. })
  707. },
  708. // 查看附件
  709. handleViewAttachment(row) {
  710. if (row.attachments && row.attachments.length > 0) {
  711. // 打开附件链接
  712. window.open(row.attachments[0].url, '_blank')
  713. }
  714. },
  715. // 文件改变处理
  716. handleFileChange(file, fileList) {
  717. this.fileList = fileList.slice(-1) // 只保留最新选择的文件
  718. },
  719. // 保存记录
  720. handleSave() {
  721. // 表单验证
  722. if (!this.formData.deliberationForm) {
  723. this.$message.error('请输入审议形式')
  724. return
  725. }
  726. if (!this.formData.location) {
  727. this.$message.error('请输入地点')
  728. return
  729. }
  730. if (!this.formData.startDate || !this.formData.endDate) {
  731. this.$message.error('请选择时间')
  732. return
  733. }
  734. if (!this.formData.hostPerson) {
  735. this.$message.error('请选择主持人')
  736. return
  737. }
  738. if (!this.formData.recordPerson) {
  739. this.$message.error('请选择记录人')
  740. return
  741. }
  742. // 构建保存数据,按照接口要求的参数格式
  743. const saveData = {
  744. id: this.formData.id,
  745. taskId: this.id, // 使用props传入的id作为项目ID
  746. deliberationForm: this.formData.deliberationForm,
  747. beginTime: this.formData.startDate,
  748. endTime: this.formData.endDate,
  749. location: this.formData.location,
  750. hostPerson: this.formData.hostPerson,
  751. recordPerson: this.formData.recordPerson,
  752. participants: this.formData.participants,
  753. enterpriseId: '', // 需要从项目信息中获取监审单位id
  754. deliberationContent: this.formData.reviewSituation,
  755. conclusionOpinion: this.formData.reviewConclusion,
  756. attachmentIds: this.fileList
  757. .map((file) => file.uid || file.name)
  758. .join(','), // 附件ID集合,多个用逗号分隔
  759. remark: '', // 备注
  760. }
  761. // 调用API进行保存操作
  762. if (this.operationType === 'add') {
  763. // 添加新记录
  764. addCollectiveDeliberate(saveData)
  765. .then((res) => {
  766. if (res && res.state && res.code === 200) {
  767. this.$message.success('新增成功')
  768. this.loadRecordList() // 重新加载记录列表
  769. this.showRecordDialog = false
  770. this.resetForm()
  771. } else {
  772. this.$message.error(res.message || '新增失败')
  773. }
  774. })
  775. .catch((error) => {
  776. this.$message.error('新增失败:' + error.message)
  777. })
  778. } else {
  779. // 更新现有记录
  780. updateCollectiveDeliberate(saveData)
  781. .then((res) => {
  782. if (res && res.state && res.code === 200) {
  783. this.$message.success('修改成功')
  784. this.loadRecordList() // 重新加载记录列表
  785. this.showRecordDialog = false
  786. this.resetForm()
  787. } else {
  788. this.$message.error(res.message || '修改失败')
  789. }
  790. })
  791. .catch((error) => {
  792. this.$message.error('修改失败:' + error.message)
  793. })
  794. }
  795. },
  796. // 取消操作
  797. handleCancel() {
  798. this.showRecordDialog = false
  799. this.resetForm()
  800. },
  801. // 重置表单
  802. resetForm() {
  803. this.formData = {
  804. id: '',
  805. deliberationForm: '',
  806. startDate: '',
  807. endDate: '',
  808. location: '',
  809. hostPerson: '',
  810. recordPerson: '',
  811. participants: '',
  812. reviewProject: this.formData.reviewProject, // 保持项目信息不变
  813. auditedUnit: this.formData.auditedUnit, // 保持单位信息不变
  814. reviewSituation: '',
  815. reviewConclusion: '',
  816. attachments: [],
  817. }
  818. this.fileList = []
  819. },
  820. },
  821. }
  822. </script>
  823. <style scoped>
  824. /* 主容器样式 */
  825. .collective {
  826. padding: 10px;
  827. font-family: 'Microsoft YaHei', sans-serif;
  828. }
  829. /* 页面头部样式 */
  830. .collective-header {
  831. display: flex;
  832. justify-content: space-between;
  833. align-items: center;
  834. margin-bottom: 20px;
  835. padding: 5px 0;
  836. }
  837. .collective-header-left span {
  838. font-size: 18px;
  839. font-weight: bold;
  840. color: #333;
  841. }
  842. /* 列表容器样式 */
  843. .collective-list {
  844. margin-top: 15px;
  845. border: 1px solid #ebeef5;
  846. border-radius: 4px;
  847. overflow: hidden;
  848. }
  849. /* 表单容器样式 */
  850. .record-form {
  851. padding: 20px 0 0;
  852. background: #fff;
  853. }
  854. /* 表单行样式 */
  855. .form-row {
  856. display: flex;
  857. margin-bottom: 20px;
  858. align-items: flex-start;
  859. min-height: 40px;
  860. }
  861. /* 表单项样式 */
  862. .form-item {
  863. flex: 1;
  864. margin-right: 20px;
  865. position: relative;
  866. display: flex;
  867. align-items: center;
  868. }
  869. /* 紧凑表单项目,减小间距 */
  870. .form-item-compact {
  871. margin-right: 20px; /* 减小右侧间距 */
  872. width: calc(50% - 10px); /* 调整宽度以适应紧凑布局 */
  873. }
  874. .form-item:last-child {
  875. margin-right: 0;
  876. }
  877. /* 表单标签样式 */
  878. .form-label {
  879. display: inline-block;
  880. width: 120px;
  881. text-align: right;
  882. margin-right: 10px;
  883. font-weight: 500;
  884. color: #303133;
  885. font-size: 14px;
  886. line-height: 32px;
  887. vertical-align: middle;
  888. flex-shrink: 0;
  889. }
  890. /* 必填项标记 */
  891. .form-label.required::before {
  892. content: '*';
  893. color: #f56c6c;
  894. margin-right: 4px;
  895. }
  896. /* 表单输入框样式 */
  897. .form-input {
  898. flex: 1;
  899. max-width: 600px;
  900. }
  901. /* 只读输入框样式 */
  902. .readonly-input {
  903. background-color: #f5f7fa;
  904. color: #909399;
  905. cursor: not-allowed;
  906. }
  907. /* 表单选择器样式 */
  908. .form-select {
  909. width: 200px;
  910. }
  911. /* 表单文本域样式 */
  912. .form-textarea {
  913. flex: 1;
  914. max-width: 600px;
  915. }
  916. /* 时间选择器容器样式 */
  917. .time-picker {
  918. display: flex;
  919. align-items: center;
  920. flex-wrap: wrap;
  921. flex: 1;
  922. max-width: 400px;
  923. }
  924. /* 日期选择器样式 */
  925. .date-picker {
  926. width: 180px;
  927. }
  928. /* 日期范围分隔符 */
  929. .date-range-separator {
  930. margin: 0 10px;
  931. color: #606266;
  932. font-size: 14px;
  933. }
  934. /* 文件上传样式 */
  935. .upload-file {
  936. display: flex;
  937. flex-direction: column;
  938. flex: 1;
  939. max-width: 400px;
  940. }
  941. /* 文件名称样式 */
  942. .file-name {
  943. margin-top: 10px;
  944. padding: 5px 0;
  945. word-break: break-all;
  946. }
  947. /* 文件链接样式 */
  948. .file-link {
  949. color: #409eff;
  950. text-decoration: none;
  951. font-size: 14px;
  952. }
  953. .file-link:hover {
  954. text-decoration: underline;
  955. color: #66b1ff;
  956. }
  957. /* 对话框样式优化 */
  958. ::v-deep .el-dialog__header {
  959. padding: 20px 25px 15px;
  960. border-bottom: 1px solid #ebeef5;
  961. background-color: #fafafa;
  962. }
  963. ::v-deep .el-dialog__title {
  964. font-size: 16px;
  965. font-weight: 500;
  966. color: #303133;
  967. }
  968. ::v-deep .el-dialog__body {
  969. padding: 25px;
  970. max-height: 60vh;
  971. overflow-y: auto;
  972. }
  973. ::v-deep .el-dialog__footer {
  974. padding: 15px 25px 20px;
  975. border-top: 1px solid #ebeef5;
  976. margin-top: 10px;
  977. background-color: #fafafa;
  978. }
  979. /* 按钮样式优化 */
  980. .cancel-btn {
  981. margin-right: 15px;
  982. }
  983. .save-btn {
  984. min-width: 80px;
  985. }
  986. /* 表格样式优化 */
  987. ::v-deep .el-table th {
  988. background-color: #f5f7fa;
  989. font-weight: 500;
  990. color: #606266;
  991. border-right: 1px solid #ebeef5;
  992. }
  993. ::v-deep .el-table td {
  994. color: #606266;
  995. border-right: 1px solid #ebeef5;
  996. }
  997. /* 输入框样式优化 */
  998. ::v-deep .el-input__inner,
  999. ::v-deep .el-select .el-input__inner,
  1000. ::v-deep .el-date-editor .el-input__inner {
  1001. border-radius: 4px;
  1002. transition: all 0.3s;
  1003. height: 32px;
  1004. line-height: 32px;
  1005. }
  1006. ::v-deep .el-input__inner:hover,
  1007. ::v-deep .el-select .el-input__inner:hover,
  1008. ::v-deep .el-date-editor .el-input__inner:hover {
  1009. border-color: #c0c4cc;
  1010. }
  1011. ::v-deep .el-input__inner:focus,
  1012. ::v-deep .el-select .el-input__inner:focus,
  1013. ::v-deep .el-date-editor .el-input__inner:focus {
  1014. border-color: #409eff;
  1015. outline: none;
  1016. }
  1017. /* 多行文本域样式 */
  1018. ::v-deep .el-textarea__inner {
  1019. resize: vertical;
  1020. border-radius: 4px;
  1021. min-height: 100px;
  1022. padding: 8px 12px;
  1023. }
  1024. /* 响应式设计 */
  1025. @media (max-width: 768px) {
  1026. .collective {
  1027. padding: 5px;
  1028. }
  1029. .collective-header {
  1030. flex-direction: column;
  1031. align-items: flex-start;
  1032. gap: 10px;
  1033. }
  1034. .form-row {
  1035. flex-direction: column;
  1036. margin-bottom: 15px;
  1037. }
  1038. .form-item {
  1039. margin-right: 0;
  1040. margin-bottom: 15px;
  1041. flex-direction: column;
  1042. align-items: flex-start;
  1043. }
  1044. .form-item:last-child {
  1045. margin-bottom: 0;
  1046. }
  1047. .form-label {
  1048. width: 100%;
  1049. text-align: left;
  1050. margin-bottom: 5px;
  1051. line-height: 1.5;
  1052. }
  1053. .form-input,
  1054. .form-select,
  1055. .form-textarea,
  1056. .time-picker,
  1057. .upload-file {
  1058. width: 100%;
  1059. max-width: none;
  1060. }
  1061. .date-picker {
  1062. width: 100%;
  1063. }
  1064. ::v-deep .el-dialog {
  1065. width: 95% !important;
  1066. margin: 5% auto;
  1067. max-width: 600px;
  1068. }
  1069. ::v-deep .el-dialog__header,
  1070. ::v-deep .el-dialog__body,
  1071. ::v-deep .el-dialog__footer {
  1072. padding: 15px;
  1073. }
  1074. ::v-deep .el-dialog__body {
  1075. max-height: 70vh;
  1076. }
  1077. .time-picker {
  1078. flex-direction: column;
  1079. align-items: stretch;
  1080. gap: 10px;
  1081. }
  1082. .date-range-separator {
  1083. display: none;
  1084. }
  1085. .dialog-footer {
  1086. text-align: center;
  1087. }
  1088. .cancel-btn,
  1089. .save-btn {
  1090. margin: 0 5px;
  1091. }
  1092. }
  1093. /* 补充资料弹窗样式优化 */
  1094. ::v-deep .supplement-dialog {
  1095. .el-dialog__header {
  1096. padding: 20px 25px 15px;
  1097. border-bottom: 1px solid #ebeef5;
  1098. background-color: #fafafa;
  1099. }
  1100. .el-dialog__title {
  1101. font-size: 16px;
  1102. font-weight: 500;
  1103. color: #303133;
  1104. }
  1105. .el-dialog__body {
  1106. padding: 25px;
  1107. }
  1108. .el-dialog__footer {
  1109. padding: 15px 25px 20px;
  1110. border-top: 1px solid #ebeef5;
  1111. background-color: #fafafa;
  1112. text-align: right;
  1113. }
  1114. }
  1115. .supplement-dialog-content {
  1116. padding: 0;
  1117. }
  1118. .supplement-form-item {
  1119. display: flex;
  1120. align-items: flex-start;
  1121. margin-bottom: 20px;
  1122. }
  1123. .supplement-form-item:last-child {
  1124. margin-bottom: 0;
  1125. }
  1126. .supplement-form-label {
  1127. display: inline-block;
  1128. width: 100px;
  1129. text-align: left;
  1130. color: #606266;
  1131. font-size: 14px;
  1132. line-height: 32px;
  1133. flex-shrink: 0;
  1134. margin-right: 12px;
  1135. }
  1136. .supplement-form-label.required::before {
  1137. content: '*';
  1138. color: #f56c6c;
  1139. margin-right: 4px;
  1140. }
  1141. .supplement-textarea {
  1142. flex: 1;
  1143. }
  1144. .supplement-select {
  1145. flex: 1;
  1146. min-width: 300px;
  1147. }
  1148. .supplement-checkbox-group {
  1149. display: flex;
  1150. flex-direction: column;
  1151. flex: 1;
  1152. }
  1153. .supplement-checkbox-group .el-checkbox {
  1154. margin-bottom: 8px;
  1155. }
  1156. .supplement-checkbox-group .el-checkbox:last-child {
  1157. margin-bottom: 0;
  1158. }
  1159. .supplement-dialog-footer {
  1160. text-align: right;
  1161. }
  1162. .supplement-dialog-footer .el-button {
  1163. margin-left: 10px;
  1164. }
  1165. /* 打印样式 */
  1166. @media print {
  1167. .collective {
  1168. padding: 0;
  1169. }
  1170. .collective-header-right {
  1171. display: none;
  1172. }
  1173. ::v-deep .el-button {
  1174. display: none;
  1175. }
  1176. ::v-deep .el-dialog {
  1177. box-shadow: none !important;
  1178. margin: 0 !important;
  1179. width: 100% !important;
  1180. }
  1181. ::v-deep .el-dialog__header,
  1182. ::v-deep .el-dialog__footer {
  1183. display: none;
  1184. }
  1185. ::v-deep .el-dialog__body {
  1186. padding: 0;
  1187. overflow: visible;
  1188. }
  1189. }
  1190. </style>