addOrEdit.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. <template>
  2. <div>
  3. <el-card shadow="never">
  4. <el-tabs v-model="tabValue" type="card" @tab-click="handleTabClick">
  5. <el-tab-pane v-if="query.type != 'view'" label="稿纸信息" name="1">
  6. <MainBodyTemplate ref="mainBodyTemplate" :type="routerQuery.type" menu="notice" :disabled="disabled" @sendFiles="getFiles"></MainBodyTemplate>
  7. </el-tab-pane>
  8. <el-tab-pane label="正文" name="2">
  9. <div v-show="tabValue === '2'" style="min-height: 525px;">
  10. <tinymce-editor v-if="tinymceConfig && tabValue === '2'" :disabled="disabled" v-model="formData.content" :init="tinymceConfig" />
  11. </div>
  12. </el-tab-pane>
  13. <el-tab-pane label="附件查看" name="3">
  14. <div class="file-container">
  15. <el-row :gutter="20">
  16. <el-col :span="6">
  17. <div class="file-item" v-for="(item, index) in fileList" :key="item.id" @click="filesOpen(item)">
  18. <el-link type="primary">{{index + 1}}. {{item.name}}</el-link>
  19. <span v-if="!disabled" class="delete-icon" @click="deleteFile(index)">
  20. <i class="el-icon-delete"></i>
  21. </span>
  22. </div>
  23. </el-col>
  24. <el-col :span="18">
  25. <iframe class="file-iframe" style="width: 100%; height: 62vh;" v-if="fileList && fileList.length > 0" :src="currentFileUrl" frameborder="0" allowfullscreen="true"></iframe>
  26. </el-col>
  27. </el-row>
  28. </div>
  29. </el-tab-pane>
  30. <el-tab-pane v-if="formData?.processInstanceId && !isApprove && query.type != 'view'" label="流程详情" name="4">
  31. <bpmDetail
  32. v-if="formData.processInstanceId"
  33. :id="formData.processInstanceId"
  34. ></bpmDetail>
  35. </el-tab-pane>
  36. </el-tabs>
  37. <div v-if="!disabled" class="footer">
  38. <el-button type="primary" @click="save(0)" v-click-once>保存</el-button>
  39. <el-button type="primary" @click="save(1)" v-click-once>提交</el-button>
  40. <el-button @click="cancel">取消</el-button>
  41. </div>
  42. </el-card>
  43. <process-submit-dialog
  44. :processSubmitDialogFlag.sync="processSubmitDialogFlag"
  45. v-if="processSubmitDialogFlag"
  46. ref="processSubmitDialogRef"
  47. @reload="cancel"
  48. ></process-submit-dialog>
  49. </div>
  50. </template>
  51. <script>
  52. import MainBodyTemplate from '@/views/bpm/documents/documentTemplate/components/mainBodyTemplate.vue'
  53. import TinymceEditor from '@/components/TinymceEditor/index.vue';
  54. import { docTplTemplateById } from '@/api/documents/doc-manage';
  55. import { noticeDocumentCreateAPI, noticeDocumentByIdAPI, noticeDocumentUpdateAPI } from '@/api/documents/noticeIssuance/index.js';
  56. import bpmDetail from '@/views/bpm/processInstance/detailNew.vue';
  57. import { queryIds } from '@/components/addDoc/api/index'
  58. import { getCode } from '@/api/codeManagement';
  59. import { uploadFile } from '@/api/system/file/index.js';
  60. import processSubmitDialog from '@/BIZComponents/enventSubmitDialog/processSubmitDialog'
  61. import { setFileUrl } from '@/components/addDoc/util.js'
  62. export default {
  63. components: {
  64. MainBodyTemplate,
  65. TinymceEditor,
  66. bpmDetail,
  67. processSubmitDialog
  68. },
  69. props: {
  70. query: {
  71. default: () => {
  72. return {
  73. id: '',
  74. type: ''
  75. }
  76. }
  77. },
  78. isApprove: {
  79. default: false
  80. }
  81. },
  82. data() {
  83. return {
  84. drawer: false,
  85. businessId: '',
  86. processSubmitDialogFlag: false,
  87. currentFileUrl: '',
  88. tabValue: '1',
  89. formData: {
  90. code: '',
  91. name: '',
  92. status: true,
  93. content: '',
  94. fields: [],
  95. },
  96. fileList: [],
  97. tinymceConfig: {
  98. height: 525,
  99. resize: false,
  100. autoresize_bottom_margin: 0,
  101. auto_focus: false,
  102. scroll_padding: 0,
  103. scroll_padding_bottom: 0,
  104. images_upload_handler: (blobInfo, success, error) => {
  105. const file = blobInfo.blob();
  106. console.log('file~~~', file);
  107. // 判断 file 是否为有效的文件对象
  108. if (!file || !(file instanceof File) || file.size === 0) {
  109. return;
  110. }
  111. // 使用 axios 上传,实际开发这段建议写在 api 中再调用 api
  112. uploadFile({
  113. module: 'main',
  114. multiPartFile: file
  115. }).then((res) => {
  116. if (res.data) {
  117. console.log('images_upload_handler~~~', res);
  118. success(res.data.url);
  119. } else {
  120. error(res.message);
  121. }
  122. }).catch(error => {
  123. this.$message.error('文件上传失败');
  124. });
  125. }
  126. },
  127. }
  128. },
  129. created() {
  130. // this.routerQuery = this.isApprove ? this.query : this.$route.query;
  131. this.routerQuery = this.query;
  132. this.tabValue = this.query.type == 'view' ? '3' : '1';
  133. console.log('this.query~~~', this.query);
  134. this.$nextTick(() => {
  135. this.getDetail();
  136. })
  137. },
  138. computed: {
  139. disabled() {
  140. return this.routerQuery.type == 'detail' || this.routerQuery.type == 'view';
  141. },
  142. },
  143. methods: {
  144. // openDrawer(query) {
  145. // this.routerQuery = this.isApprove ? this.query : query;
  146. // this.drawer = true;
  147. // this.$nextTick(() => {
  148. // this.getDetail();
  149. // })
  150. // },
  151. filesOpen(item) {
  152. this.currentFileUrl = setFileUrl(item);
  153. console.log('currentFileUrl~~~', this.currentFileUrl);
  154. },
  155. async getFiles(ids) {
  156. if(ids) {
  157. let res = await queryIds({ ids: "'" + ids + "'" });
  158. this.fileList = res || [];
  159. this.filesOpen(res?.[0] || '');
  160. }
  161. },
  162. deleteFile(index) {
  163. this.fileList.splice(index, 1);
  164. this.$refs.mainBodyTemplate.setFiles(this.fileList);
  165. this.filesOpen(this.fileList.length > 0 ? this.fileList[0] : '');
  166. },
  167. async getDetail() {
  168. const requestUrl = this.routerQuery.type == 'add' ? docTplTemplateById : noticeDocumentByIdAPI;
  169. let res = await requestUrl(this.routerQuery.id);
  170. this.businessId = this.routerQuery.type == 'add' ? '' : res.id;
  171. console.log('type~~~', this.routerQuery.type);
  172. // 如果是新增,将发文编号设置到 fields 中
  173. if (this.routerQuery.type == 'add' && res.fields) {
  174. const documentNumberField = res.fields.find((item) => item.fieldKey == 'documentNumber');
  175. if (documentNumberField) {
  176. documentNumberField.defaultValue = await getCode('fm_document_number_code');
  177. console.log('documentNumberField~~~', documentNumberField, await getCode('fm_document_number_code'));
  178. }
  179. }
  180. this.formData = res;
  181. let ids =this.formData.fields.find((item) => item.fieldKey == 'attachments')?.defaultValue || '';
  182. this.getFiles(ids);
  183. console.log(this.formData, this.$refs.mainBodyTemplate);
  184. this.$nextTick(() => {
  185. this.$refs.mainBodyTemplate && this.$refs.mainBodyTemplate.setData(this.formData.fields);
  186. })
  187. },
  188. async getTemplateDetail() {
  189. let res = await docTplTemplateById(this.routerQuery.id);
  190. // res.status = res.status == 1 ? true : false;
  191. this.formData = res;
  192. let ids =this.formData.fields.find((item) => item.fieldKey == 'attachments')?.defaultValue || '';
  193. this.getFiles(ids);
  194. console.log(this.formData, this.$refs.mainBodyTemplate);
  195. this.$refs.mainBodyTemplate.setData(this.formData.fields);
  196. },
  197. handleTabClick(tab) {
  198. this.tabValue = tab.name;
  199. },
  200. async save(type) {
  201. try {
  202. // 校验子组件 mainBodyTemplate 的必填项
  203. const mainBodyValid = await this.$refs.mainBodyTemplate.$refs.form.validate().catch(() => false);
  204. if (!mainBodyValid) {
  205. this.$message.warning('请完善稿纸信息的必填项');
  206. return;
  207. }
  208. // 获取自定义字段数据
  209. const customFields = this.$refs.mainBodyTemplate.generateCustomFields();
  210. // 将 customFields 放到 formData 字段
  211. this.formData.fields = customFields;
  212. this.formData.status = this.formData.status ? 1 : 0;
  213. if(this.routerQuery.type == 'add') {
  214. this.formData.templateId = this.formData.id;
  215. delete this.formData.id;
  216. }
  217. console.log('提交数据:', this.formData);
  218. // 提交到后端
  219. const loading = this.$loading({ lock: true });
  220. const requestUrl = this.routerQuery.type == 'add' ? noticeDocumentCreateAPI : noticeDocumentUpdateAPI;
  221. requestUrl(this.formData)
  222. .then((res) => {
  223. if(type == 1) {
  224. loading.close();
  225. this.submit(res);
  226. }else {
  227. loading.close();
  228. this.$message.success('保存成功');
  229. this.cancel();
  230. }
  231. })
  232. .catch((e) => {
  233. loading.close();
  234. console.error('保存失败:', e);
  235. });
  236. } catch (error) {
  237. console.error('保存异常:', error);
  238. }
  239. },
  240. async submit(res) {
  241. const data = await noticeDocumentByIdAPI(
  242. this.businessId || res
  243. );
  244. this.processSubmitDialogFlag = true;
  245. this.$nextTick(() => {
  246. let params = {
  247. businessId: data.id,
  248. businessKey: 'fm_notice_document_approval',
  249. formCreateUserId: data.createUserId,
  250. variables: {
  251. businessCode: data.docNo,
  252. businessName: data.title,
  253. businessType: '通知公文'
  254. }
  255. };
  256. this.$refs.processSubmitDialogRef.init(params);
  257. });
  258. },
  259. cancel() {
  260. this.tabValue = '1';
  261. this.$emit('done');
  262. },
  263. }
  264. }
  265. </script>
  266. <style scoped>
  267. .el-card {
  268. min-height: 600px;
  269. }
  270. .footer {
  271. text-align: center;
  272. margin-top: 20px;
  273. }
  274. .file-container {
  275. padding: 20px;
  276. }
  277. .file-item {
  278. font-size: 14px;
  279. margin-bottom: 10px;
  280. display: flex;
  281. align-items: center;
  282. }
  283. .delete-icon {
  284. color: red;
  285. cursor: pointer;
  286. margin-left: 20px;
  287. }
  288. </style>