UpdateProjectField.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <template>
  2. <el-dialog
  3. :title="`更新${fieldObj[field]}`"
  4. :visible="visible"
  5. :width="dialogWidth"
  6. :close-on-click-modal="false"
  7. @close="handleClose"
  8. >
  9. <template v-if="['name', 'editor', 'category', 'language', 'topic', 'reader', 'publisher'].includes(field)">
  10. <el-input v-model="stringValue" type="text" />
  11. </template>
  12. <div v-if="field === 'cover_image_file_url'" class="upload-image">
  13. <el-upload
  14. class="avatar-uploader"
  15. action="no"
  16. :http-request="upload"
  17. :before-upload="beforeUpload"
  18. accept="image/*"
  19. :show-file-list="false"
  20. >
  21. <img v-if="stringValue" :src="stringValue" class="avatar" />
  22. <i v-else class="el-icon-plus avatar-uploader-icon"></i>
  23. </el-upload>
  24. </div>
  25. <template v-if="['content_intro', 'background', 'author_intro'].includes(field)">
  26. <el-input v-model="stringValue" type="textarea" :autosize="{ minRows: 4 }" maxlength="1500" show-word-limit />
  27. </template>
  28. <template v-if="field === 'plan_publish_date'">
  29. <el-date-picker
  30. v-model="stringValue"
  31. type="date"
  32. placeholder="选择日期"
  33. format="yyyy-MM-dd"
  34. value-format="yyyy-MM-dd"
  35. />
  36. </template>
  37. <template v-if="['content_count_YG', 'word_count_YG'].includes(field)">
  38. <el-input v-model="stringValue" type="number" />
  39. </template>
  40. <div v-if="field === 'label_list'" class="label-input-content">
  41. <el-input v-model="labelInput" placeholder="请输入标签" @keyup.enter.native="labelChange" />
  42. <div class="label-list">
  43. <el-tag v-for="(tag, index) in arrayValue" :key="index" closable @close="arrayValue.splice(index, 1)">
  44. {{ tag }}
  45. </el-tag>
  46. </div>
  47. </div>
  48. <div slot="footer">
  49. <el-button @click="handleClose">取消</el-button>
  50. <el-button type="primary" @click="confirm">确定</el-button>
  51. </div>
  52. </el-dialog>
  53. </template>
  54. <script>
  55. import { fileUpload } from '@/api/app';
  56. export default {
  57. name: 'UpdateProjectField',
  58. props: {
  59. field: {
  60. type: String,
  61. required: true,
  62. },
  63. value: {
  64. type: [String, Number, Array, Object],
  65. required: true,
  66. },
  67. projectId: {
  68. type: String,
  69. required: true,
  70. },
  71. visible: {
  72. type: Boolean,
  73. default: false,
  74. },
  75. },
  76. data() {
  77. return {
  78. fieldObj: {
  79. // 单行文本
  80. name: '项目名称',
  81. category: '项目分类',
  82. language: '语种',
  83. topic: '所属课题',
  84. editor: '作者',
  85. reader: '读者对象',
  86. publisher: '出版单位',
  87. // 多行文本
  88. content_intro: '内容简介',
  89. background: '选题背景',
  90. author_intro: '作者简介',
  91. // 上传图片
  92. cover_image_file_url: '封面图片',
  93. // 日期
  94. plan_publish_date: '计划出版日期',
  95. // 数字
  96. content_count_YG: '预计容量(课数)',
  97. word_count_YG: '预计字数',
  98. // 对象
  99. label_list: '作品标签',
  100. },
  101. stringValue: this.value,
  102. arrayValue: [],
  103. imageId: '',
  104. labelInput: '',
  105. };
  106. },
  107. computed: {
  108. dialogWidth() {
  109. if (['content_count_YG', 'word_count_YG', 'plan_publish_date'].includes(this.field)) {
  110. return '260px';
  111. }
  112. if (this.field === 'label_list') {
  113. return '460px';
  114. }
  115. return '550px';
  116. },
  117. },
  118. watch: {
  119. value(newVal) {
  120. this.stringValue = newVal;
  121. if (this.field === 'label_list' && Array.isArray(newVal)) {
  122. this.arrayValue = [...newVal];
  123. }
  124. },
  125. },
  126. methods: {
  127. // 处理标签输入
  128. labelChange() {
  129. if (this.labelInput.trim() !== '') {
  130. this.arrayValue.push(this.labelInput.trim());
  131. this.labelInput = '';
  132. }
  133. },
  134. beforeUpload(file) {
  135. const isImage = /^image/.test(file.type);
  136. if (!isImage) {
  137. this.$message.error('上传的文件不是图片,请重新上传!');
  138. }
  139. return isImage;
  140. },
  141. upload(file) {
  142. if (file.file.size / 1048576 > 2) {
  143. return this.$message.warning(`${file.file.name}文件大小超出限制`);
  144. }
  145. fileUpload('Open', file, { isGlobalprogress: true }).then(({ file_info_list }) => {
  146. if (file_info_list.length > 0) {
  147. const { file_url, file_id } = file_info_list[0];
  148. this.stringValue = file_url;
  149. this.imageId = file_id;
  150. }
  151. });
  152. },
  153. handleClose() {
  154. this.$emit('update:visible', false);
  155. },
  156. confirm() {
  157. if (
  158. [
  159. 'name',
  160. 'editor',
  161. 'category',
  162. 'language',
  163. 'topic',
  164. 'reader',
  165. 'publisher',
  166. 'content_intro',
  167. 'background',
  168. 'author_intro',
  169. 'content_count_YG',
  170. 'word_count_YG',
  171. 'plan_publish_date',
  172. ].includes(this.field)
  173. ) {
  174. this.$emit('updateProjectFieldValue', this.field, this.stringValue);
  175. }
  176. if (this.field === 'cover_image_file_url') {
  177. this.$emit('updateProjectFieldValue', 'cover_image_file_id', this.imageId);
  178. }
  179. if (this.field === 'label_list') {
  180. this.$emit('updateProjectFieldValue', this.field, this.arrayValue);
  181. }
  182. this.handleClose();
  183. },
  184. },
  185. };
  186. </script>
  187. <style lang="scss" scoped>
  188. .upload-image {
  189. .avatar-uploader {
  190. :deep .el-upload {
  191. display: flex;
  192. align-items: center;
  193. justify-content: center;
  194. width: 418px;
  195. height: 280px;
  196. margin: 0 auto;
  197. overflow: hidden;
  198. cursor: pointer;
  199. border: 1px dashed #d9d9d9;
  200. border-radius: 6px;
  201. &:hover {
  202. border-color: #409eff;
  203. }
  204. }
  205. &-icon {
  206. width: 418px;
  207. height: 280px;
  208. font-size: 28px;
  209. line-height: 280px;
  210. color: #8c939d;
  211. text-align: center;
  212. }
  213. .avatar {
  214. display: block;
  215. max-width: 418px;
  216. max-height: 280px;
  217. }
  218. }
  219. }
  220. .label-input-content {
  221. display: flex;
  222. flex-direction: column;
  223. width: 420px;
  224. .label-list {
  225. display: flex;
  226. flex-wrap: wrap;
  227. gap: 4px;
  228. padding: 12px 8px;
  229. }
  230. .el-input {
  231. flex: 1;
  232. min-width: 120px;
  233. margin-left: 6px;
  234. }
  235. }
  236. </style>