Browse Source

项目信息管理更新

dsy 1 tuần trước cách đây
mục cha
commit
a1634b71da

+ 1 - 1
.env

@@ -11,4 +11,4 @@ VUE_APP_BookWebSI = '/GCLSBookWebSI/ServiceInterface'
 VUE_APP_EepServer = '/EEPServer/SI'
 
 #version
-VUE_APP_VERSION = '2025.11.10'
+VUE_APP_VERSION = '2025.11.12'

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "eep_page",
-  "version": "2025.11.10",
+  "version": "2025.11.12",
   "private": true,
   "main": "main.js",
   "description": "智慧梧桐数字教材编辑器",

BIN
public/favicon.ico


+ 21 - 0
src/api/project.js

@@ -174,6 +174,27 @@ export function SetProjectLeader(data) {
 }
 
 /**
+ * @description 更改项目指定字段的值
+ * @param {object} data
+ * @param {string} data.project_id 项目ID
+ * @param {string} data.field_name 字段名称
+ * @param {string} data.value 字段值
+ */
+export function UpdateProjectFieldValue(data) {
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=project_manager-UpdateProjectFieldValue`, data);
+}
+
+/**
+ * @description 设置项目标签
+ * @param {object} data
+ * @param {string} data.project_id 项目ID
+ * @param {array<string>} data.label_list 标签列表
+ */
+export function SetProjectLabel(data) {
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=project_manager-SetProjectLabel`, data);
+}
+
+/**
  * @description 添加审校批注
  * @param {object} data
  * @param {string} data.courseware_id 课件ID

+ 33 - 26
src/components/CommonPreview.vue

@@ -26,7 +26,7 @@
       <aside v-if="navigationShow" class="left-menu">
         <div class="courseware-info">
           <div class="cover-image">
-            <img v-if="project.cover_image_file_url.length > 0" :src="project.cover_image_file_url" alt="" />
+            <img v-if="project.cover_image_file_url.length > 0" :src="project.cover_image_file_url" alt="cover-image" />
           </div>
           <div class="info-content">
             <div class="catalogue-icon">
@@ -36,13 +36,8 @@
               <div class="name nowrap-ellipsis" :title="courseware_info.book_name">
                 {{ courseware_info.book_name }}
               </div>
-              <div>
-                <span>主编 </span>
-                <span>{{ project.editor }}</span>
-              </div>
-              <div>
-                <span>副主编 </span>
-                <span>{{ project.associate_editor }}</span>
+              <div class="editor" :title="project.editor">
+                {{ project.editor }}
               </div>
             </div>
           </div>
@@ -92,8 +87,8 @@
         <aside v-if="!sidebarShow" class="sidebar-bar">
           <aside class="toolbar">
             <div class="toolbar-special">
-              <img :src="require('@/assets/icon/sidebar-fullscreen.png')" alt="全屏" />
-              <img :src="require('@/assets/icon/sidebar-toolkit.png')" alt="工具箱" />
+              <!-- <img :src="require('@/assets/icon/sidebar-fullscreen.png')" alt="全屏" />
+              <img :src="require('@/assets/icon/sidebar-toolkit.png')" alt="工具箱" /> -->
               <img :src="require(`@/assets/icon/arrow-down.png`)" alt="伸缩" @click="toggleSidebarShow" />
             </div>
           </aside>
@@ -107,8 +102,8 @@
       <aside v-if="sidebarShow" ref="sidebarMenu" class="sidebar">
         <aside class="toolbar">
           <div class="toolbar-special">
-            <img :src="require('@/assets/icon/sidebar-fullscreen.png')" alt="全屏" />
-            <img :src="require('@/assets/icon/sidebar-toolkit.png')" alt="工具箱" />
+            <!-- <img :src="require('@/assets/icon/sidebar-fullscreen.png')" alt="全屏" />
+            <img :src="require('@/assets/icon/sidebar-toolkit.png')" alt="工具箱" /> -->
           </div>
           <div v-if="sidebarShow" class="toolbar-list">
             <div
@@ -289,17 +284,17 @@ export default {
   },
   data() {
     const sidebarIconList = [
-      { icon: 'search', title: '搜索', handle: '', param: {} },
+      // { icon: 'search', title: '搜索', handle: '', param: {} },
       { icon: 'mindmap', title: '思维导图', handle: 'openMindMap', param: {} },
-      { icon: 'knowledge', title: '知识图谱', handle: '', param: {} },
-      { icon: 'totalResources', title: '总资源', handle: '', param: {} },
-      { icon: 'collect', title: '收藏', handle: '', param: {} },
+      // { icon: 'knowledge', title: '知识图谱', handle: '', param: {} },
+      // { icon: 'totalResources', title: '总资源', handle: '', param: {} },
+      // { icon: 'collect', title: '收藏', handle: '', param: {} },
       { icon: 'audio', title: '音频', handle: 'openDrawer', param: { type: '1' } },
       { icon: 'image', title: '图片', handle: 'openDrawer', param: { type: '0' } },
       { icon: 'video', title: '视频', handle: 'openDrawer', param: { type: '2' } },
-      { icon: 'note', title: '笔记', handle: '', param: {} },
-      { icon: 'translate', title: '翻译', handle: '', param: {} },
-      { icon: 'setting', title: '设置', handle: '', param: {} },
+      // { icon: 'note', title: '笔记', handle: '', param: {} },
+      // { icon: 'translate', title: '翻译', handle: '', param: {} },
+      // { icon: 'setting', title: '设置', handle: '', param: {} },
     ];
 
     if (this.isShowAudit) {
@@ -372,8 +367,7 @@ export default {
       navigationShow: true,
       sidebarShow: true,
       project: {
-        editor: '', // 主编
-        associate_editor: '', // 副主编
+        editor: '', // 作者
         cover_image_file_id: null, // 封面图片ID
         cover_image_file_url: '', // 封面图片URL
       },
@@ -831,7 +825,7 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
     min-width: 1110px;
     padding: 15px 0;
     overflow: auto;
-    background: url('@/assets/preview-bg.png') repeat;
+    background-color: #ececec;
 
     .catalogue-bar {
       position: absolute;
@@ -915,14 +909,14 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
       width: $courseware-left-margin;
       min-width: $courseware-left-margin;
       max-width: $courseware-left-margin;
-      background-color: #f9f9f9;
+      background-color: $courseware-bgColor;
     }
 
     .preview-right {
       width: $courseware-right-margin;
       min-width: $courseware-right-margin;
       max-width: $courseware-right-margin;
-      background-color: #f9f9f9;
+      background-color: $courseware-bgColor;
     }
 
     &.no-audit {
@@ -951,13 +945,16 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
         border-bottom: $border;
 
         .cover-image {
+          display: flex;
+          align-items: center;
+          justify-content: center;
           width: 111px;
           height: 157px;
           background-color: rgba(229, 229, 229, 100%);
 
           img {
-            width: 100%;
-            height: 100%;
+            max-width: 111px;
+            max-height: 157px;
           }
         }
 
@@ -982,6 +979,16 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
             .name {
               font-weight: bold;
             }
+
+            .editor {
+              display: -webkit-box;
+              overflow: hidden;
+              text-overflow: ellipsis;
+              word-break: break-word;
+              white-space: normal;
+              -webkit-line-clamp: 2; /* 多行省略行数,按需调整 */
+              -webkit-box-orient: vertical;
+            }
           }
         }
       }

+ 1 - 0
src/styles/variables.scss

@@ -19,6 +19,7 @@ $right-color: #30a47d;
 $right-bc-color: #e8f7f2;
 $label-color: #076aff;
 $setting-active-color: #4176ff;
+$courseware-bgColor: #fdfdfd; // 教材内容背景色
 
 // px
 $header-h: 64px; // 顶部内容高度

+ 1 - 1
src/views/book/courseware/preview/CoursewarePreview.vue

@@ -404,7 +404,7 @@ export default {
     height: 15px;
     pointer-events: none;
     content: '';
-    background: #f9f9f9;
+    background: $courseware-bgColor;
   }
 
   &::before {

+ 18 - 17
src/views/create_project/createProject.vue

@@ -62,12 +62,8 @@
           </div>
 
           <div class="project-item">
-            <label>主编</label>
-            <el-input v-model="project.editor" type="text" placeholder="请输入主编" maxlength="20" />
-          </div>
-          <div class="project-item">
-            <label>副主编</label>
-            <el-input v-model="project.associate_editor" type="text" placeholder="请输入副主编" maxlength="20" />
+            <label>作者</label>
+            <el-input v-model="project.editor" type="text" placeholder="请输入作者" maxlength="20" />
           </div>
         </div>
       </el-form-item>
@@ -108,14 +104,20 @@
       <el-form-item label="预计字数" prop="word_count_YG">
         <el-input v-model="project.word_count_YG" type="number" />
       </el-form-item>
-      <el-form-item label="计划出版时间" prop="plan_publish_date">
-        <el-date-picker v-model="project.plan_publish_date" type="date" placeholder="选择日期" />
+      <el-form-item label="计划出版日期" prop="plan_publish_date">
+        <el-date-picker
+          v-model="project.plan_publish_date"
+          type="date"
+          format="YYYY-MM-DD"
+          value-format="YYYY-MM-DD"
+          placeholder="选择日期"
+        />
       </el-form-item>
       <el-form-item label="读者对象" prop="reader">
         <el-input v-model="project.reader" type="text" placeholder="请输入读者对象" maxlength="20" />
       </el-form-item>
-      <el-form-item prop="leader_id_list" class="label-tworow">
-        <span slot="label">邀请其他<br />项目组长</span>
+      <el-form-item prop="leader_id_list">
+        <span slot="label">项目组长</span>
         <el-input v-model="leaderNames" type="text">
           <el-button slot="append" @click="selectLeader">选择</el-button>
         </el-input>
@@ -171,13 +173,12 @@ export default {
         author_intro: '',
         content_count_YG: 100,
         word_count_YG: 100000,
-        plan_publish_date: '', // 计划出版时间
+        plan_publish_date: '', // 计划出版日期
         reader: '', // 读者对象
         leader_id_list: [], // 组长列表
         member_id_list: [], // 组员列表
         cover_image_file_id: '', // 封面图片文件ID
-        editor: '', // 主编
-        associate_editor: '', // 副主编
+        editor: '', // 作者
       },
       imageUrl: '', // 封面图片URL
       formRules: {
@@ -303,7 +304,7 @@ export default {
               align-items: center;
               justify-content: center;
               width: 418px;
-              height: 280px;
+              height: 235px;
               overflow: hidden;
               cursor: pointer;
               border: 1px dashed #d9d9d9;
@@ -316,9 +317,9 @@ export default {
 
             &-icon {
               width: 418px;
-              height: 280px;
+              height: 235px;
               font-size: 28px;
-              line-height: 280px;
+              line-height: 235px;
               color: #8c939d;
               text-align: center;
             }
@@ -326,7 +327,7 @@ export default {
             .avatar {
               display: block;
               max-width: 418px;
-              max-height: 280px;
+              max-height: 235px;
             }
           }
         }

+ 3 - 3
src/views/create_project/selectProjectMembers.vue

@@ -29,7 +29,7 @@
     </el-table>
     <PaginationPage :total="total" @getList="getUserList" />
 
-    <div v-if="isMember" class="member-container">
+    <div class="member-container">
       <div class="top">
         <span class="title">已选成员</span>
         <span class="link" @click="addSelectedUsers">添加</span>
@@ -171,14 +171,14 @@ export default {
       this.$refs.user.clearSelection();
     },
     confirm() {
-      if (this.selectedUsers.length === 0 && this.isMember) {
+      if (this.selectedUsers.length === 0) {
         this.$message.warning('请至少选择一名成员');
         return;
       }
       if (this.isMember) {
         this.$emit('confirm', this.selectedUsers);
       } else {
-        this.$emit('confirm', this.$refs.user.selection);
+        this.$emit('confirm', this.selectedUsers);
       }
       this.dialogClose();
     },

+ 99 - 62
src/views/personal_workbench/project/ProjectInfoManage.vue

@@ -19,12 +19,12 @@
         <span class="label">项目名称</span>
         <div class="project-item">
           <span>{{ project.name }}</span>
-          <span class="link">更改</span>
+          <span class="link" @click="showUpdateField('name', project.name)">更改</span>
         </div>
         <span class="label">项目分类</span>
         <div class="project-item">
           <span>{{ project.category }}</span>
-          <span class="link">更改</span>
+          <span class="link" @click="showUpdateField('category', project.category)">更改</span>
         </div>
 
         <span class="label" style="line-height: 290px">教材封面</span>
@@ -33,7 +33,7 @@
             <img :src="project.cover_image_file_url" alt="cover image" />
           </div>
           <div v-else></div>
-          <span class="link">更改</span>
+          <span class="link" @click="showUpdateField('cover_image_file_url', project.cover_image_file_url)">更改</span>
         </div>
 
         <div class="label label-list">
@@ -41,18 +41,17 @@
           <span>出版单位</span>
           <span>作品标签</span>
           <span>所属课题</span>
-          <span>主编</span>
-          <span>副主编</span>
+          <span>作者</span>
         </div>
         <div class="project-item info-list">
           <div class="info-item">
             <span>{{ project.language }}</span>
-            <span class="link">更改</span>
+            <span class="link" @click="showUpdateField('language', project.language)">更改</span>
           </div>
 
           <div class="info-item">
             <span>{{ project.publisher }}</span>
-            <span class="link">更改</span>
+            <span class="link" @click="showUpdateField('publisher', project.publisher)">更改</span>
           </div>
 
           <div class="info-item">
@@ -61,58 +60,59 @@
                 {{ label }}{{ index < project.label_list.length - 1 ? ',' : '' }}
               </span>
             </span>
-            <span class="link">更改</span>
+            <span class="link" @click="showUpdateField('label_list', project.label_list)">更改</span>
           </div>
 
           <div class="info-item">
             <span>{{ project.topic }}</span>
-            <span class="link">更改</span>
+            <span class="link" @click="showUpdateField('topic', project.topic)">更改</span>
           </div>
 
           <div class="info-item">
             <span>{{ project.editor }}</span>
-            <span class="link">更改</span>
-          </div>
-          <div class="info-item">
-            <span>{{ project.associate_editor }}</span>
-            <span class="link">更改</span>
+            <span class="link" @click="showUpdateField('editor', project.editor)">更改</span>
           </div>
         </div>
+      </div>
 
-        <span class="label">作品标签</span>
+      <div class="table-twocolumn">
+        <span class="label">内容简介</span>
         <div class="project-item">
-          <span class="link">更改</span>
+          <span>{{ project.content_intro }}</span>
+          <span class="link" @click="showUpdateField('content_intro', project.content_intro)">更改</span>
         </div>
-        <span class="label">语种</span>
+        <span class="label">选题背景</span>
         <div class="project-item">
-          <span>{{ project.language }}</span>
-          <span class="link">更改</span>
+          <span>{{ project.background }}</span>
+          <span class="link" @click="showUpdateField('background', project.background)">更改</span>
         </div>
-        <span class="label">所属课题</span>
+        <span class="label">作者简介</span>
         <div class="project-item">
-          <span>{{ project.topic }}</span>
-          <span class="link">更改</span>
+          <span>{{ project.author_intro }}</span>
+          <span class="link" @click="showUpdateField('author_intro', project.author_intro)">更改</span>
         </div>
+      </div>
 
+      <div class="table-fourcolumn">
         <span class="label" style="line-height: 16px">预计容量<br />(课数)</span>
         <div class="project-item">
           <span>{{ project.content_count_YG }}</span>
-          <span class="link">更改</span>
+          <span class="link" @click="showUpdateField('content_count_YG', project.content_count_YG)">更改</span>
         </div>
         <span class="label">预计字数</span>
         <div class="project-item">
           <span>{{ project.word_count_YG }}</span>
-          <span class="link">更改</span>
+          <span class="link" @click="showUpdateField('word_count_YG', project.word_count_YG)">更改</span>
         </div>
-        <span class="label">计划出版时间</span>
+        <span class="label">计划出版日期</span>
         <div class="project-item">
           <span>{{ project.plan_publish_date }}</span>
-          <span class="link">更改</span>
+          <span class="link" @click="showUpdateField('plan_publish_date', project.plan_publish_date)">更改</span>
         </div>
         <span class="label">读者对象</span>
         <div class="project-item">
           <span>{{ project.reader }}</span>
-          <span class="link">更改</span>
+          <span class="link" @click="showUpdateField('reader', project.reader)">更改</span>
         </div>
         <span class="label">项目组长</span>
         <div class="project-item">
@@ -133,48 +133,45 @@
           <span>{{ project.create_time }}</span>
         </div>
       </div>
-
-      <div class="table-twocolumn">
-        <span class="label">内容简介</span>
-        <div class="project-item">
-          <span>{{ project.content_intro }}</span>
-          <span class="link">更改</span>
-        </div>
-        <span class="label">选题背景</span>
-        <div class="project-item">
-          <span>{{ project.background }}</span>
-          <span class="link">更改</span>
-        </div>
-        <span class="label">作者简介</span>
-        <div class="project-item">
-          <span>{{ project.author_intro }}</span>
-          <span class="link">更改</span>
-        </div>
-      </div>
     </main>
 
-    <selectMembers
+    <SelectMembers
       :visible.sync="visibleMembers"
       :title="selectMembersTitle"
       :selected-list="list[type]"
       :type="type"
       @confirm="handleSelectedMembers"
     />
+    <UpdateProjectField
+      :visible.sync="visibleUpdateField"
+      :project-id="id"
+      :field="curField"
+      :value="curFieldValue"
+      @updateProjectFieldValue="updateProjectFieldValue"
+    />
   </div>
 </template>
 
 <script>
-import { GetProjectInfo, SetProjectMember, SetProjectLeader } from '@/api/project';
+import {
+  GetProjectInfo,
+  SetProjectMember,
+  SetProjectLeader,
+  UpdateProjectFieldValue,
+  SetProjectLabel,
+} from '@/api/project';
 import { GetUserList_ID } from '@/api/user';
 
-import selectMembers from '@/views/create_project/selectProjectMembers.vue';
+import SelectMembers from '@/views/create_project/selectProjectMembers.vue';
 import MenuPage from '@/views/personal_workbench/common/menu.vue';
+import UpdateProjectField from './components/UpdateProjectField.vue';
 
 export default {
   name: 'ProjectInfoManage',
   components: {
-    selectMembers,
+    SelectMembers,
     MenuPage,
+    UpdateProjectField,
   },
   data() {
     return {
@@ -200,7 +197,7 @@ export default {
         author_intro: '',
         content_count_YG: 100,
         word_count_YG: 100000,
-        plan_publish_date: '', // 计划出版时间
+        plan_publish_date: '', // 计划出版日期
         reader: '', // 读者对象
         leader_id_list: [], // 组长列表
         leader_name_desc: '', // 组长名称描述
@@ -208,14 +205,13 @@ export default {
         member_name_desc: '', // 组员名称描述
         creator_name: '', // 创建人名称
         create_time: '', // 创建时间
-        editor: '', // 主编
-        associate_editor: '', // 副主编
+        editor: '', // 作者
         cover_image_file_id: null, // 封面图片ID
         cover_image_file_url: '', // 封面图片URL
       },
-      formRules: {
-        name: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
-      },
+      visibleUpdateField: false,
+      curField: '',
+      curFieldValue: '',
     };
   },
   created() {
@@ -223,8 +219,10 @@ export default {
   },
   methods: {
     getProjectInfo() {
-      GetProjectInfo({ id: this.id }).then(({ project_info }) => {
+      GetProjectInfo({ id: this.id }).then(({ project_info, member_list, leader_list }) => {
         this.project = project_info;
+        this.project.leader_name_desc = leader_list.map((user) => user.name).join(',');
+        this.project.member_name_desc = member_list.map((user) => user.name).join(',');
         this.getUserList_ID(project_info.leader_id_list, 'leader');
         this.getUserList_ID(project_info.member_id_list, 'member');
       });
@@ -268,10 +266,8 @@ export default {
       GetUserList_ID({ id_list }).then(({ user_list }) => {
         if (type === 'leader') {
           this.list.leader = user_list;
-          this.project.leader_name_desc = user_list.map((user) => user.user_name).join(',');
         } else if (type === 'member') {
           this.list.member = user_list;
-          this.project.member_name_desc = user_list.map((user) => user.user_name).join(',');
         }
       });
     },
@@ -295,6 +291,42 @@ export default {
         this.getProjectInfo();
       });
     },
+    /**
+     * 显示更新字段对话框
+     * @param {string} field - 字段名称
+     * @param {any} value - 当前字段值
+     */
+    showUpdateField(field, value) {
+      this.curField = field;
+      this.curFieldValue = value;
+      this.visibleUpdateField = true;
+    },
+    /**
+     * 更新项目字段值
+     * @param {string} field_name - 字段名称
+     * @param {any} value - 新的字段值
+     */
+    updateProjectFieldValue(field_name, value) {
+      if (field_name === 'label_list') {
+        SetProjectLabel({
+          project_id: this.id,
+          label_list: value,
+        }).then(() => {
+          this.$message.success('项目标签更新成功');
+          this.getProjectInfo();
+        });
+        return;
+      }
+
+      UpdateProjectFieldValue({
+        project_id: this.id,
+        field_name,
+        value,
+      }).then(() => {
+        this.$message.success('项目更新成功');
+        this.getProjectInfo();
+      });
+    },
   },
 };
 </script>
@@ -375,21 +407,26 @@ export default {
           align-items: center;
           justify-content: center;
           width: 373px;
-          height: 289px;
+          height: 248px;
           overflow: hidden;
 
           img {
             display: block;
             flex: none;
             max-width: 373px;
-            max-height: 289px;
+            max-height: 248px;
           }
         }
       }
     }
 
-    .table-fourcolumn {
-      grid-template-rows: 40px 298px repeat(5, minmax(40px, auto));
+    .table-fourcolumn:first-child {
+      grid-template-rows: 40px 258px;
+      grid-template-columns: 120px 1fr 120px 1fr;
+    }
+
+    .table-fourcolumn:nth-child(3) {
+      grid-template-rows: repeat(2, minmax(40px, auto));
       grid-template-columns: 120px 1fr 120px 1fr;
     }
 

+ 252 - 0
src/views/personal_workbench/project/components/UpdateProjectField.vue

@@ -0,0 +1,252 @@
+<template>
+  <el-dialog
+    :title="`更新${fieldObj[field]}`"
+    :visible="visible"
+    :width="dialogWidth"
+    :close-on-click-modal="false"
+    @close="handleClose"
+  >
+    <template v-if="['name', 'editor', 'category', 'language', 'topic', 'reader', 'publisher'].includes(field)">
+      <el-input v-model="stringValue" type="text" />
+    </template>
+
+    <div v-if="field === 'cover_image_file_url'" class="upload-image">
+      <el-upload
+        class="avatar-uploader"
+        action="no"
+        :http-request="upload"
+        :before-upload="beforeUpload"
+        accept="image/*"
+        :show-file-list="false"
+      >
+        <img v-if="stringValue" :src="stringValue" class="avatar" />
+        <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+      </el-upload>
+    </div>
+
+    <template v-if="['content_intro', 'background', 'author_intro'].includes(field)">
+      <el-input v-model="stringValue" type="textarea" :autosize="{ minRows: 4 }" maxlength="1500" show-word-limit />
+    </template>
+
+    <template v-if="field === 'plan_publish_date'">
+      <el-date-picker
+        v-model="stringValue"
+        type="date"
+        placeholder="选择日期"
+        format="yyyy-MM-dd"
+        value-format="yyyy-MM-dd"
+      />
+    </template>
+
+    <template v-if="['content_count_YG', 'word_count_YG'].includes(field)">
+      <el-input v-model="stringValue" type="number" />
+    </template>
+
+    <div v-if="field === 'label_list'" class="label-input-content">
+      <el-input v-model="labelInput" placeholder="请输入标签" @keyup.enter.native="labelChange" />
+      <div class="label-list">
+        <el-tag v-for="(tag, index) in arrayValue" :key="index" closable @close="arrayValue.splice(index, 1)">
+          {{ tag }}
+        </el-tag>
+      </div>
+    </div>
+
+    <div slot="footer">
+      <el-button @click="handleClose">取消</el-button>
+      <el-button type="primary" @click="confirm">确定</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { fileUpload } from '@/api/app';
+
+export default {
+  name: 'UpdateProjectField',
+  props: {
+    field: {
+      type: String,
+      required: true,
+    },
+    value: {
+      type: [String, Number, Array, Object],
+      required: true,
+    },
+    projectId: {
+      type: String,
+      required: true,
+    },
+    visible: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      fieldObj: {
+        // 单行文本
+        name: '项目名称',
+        category: '项目分类',
+        language: '语种',
+        topic: '所属课题',
+        editor: '作者',
+        reader: '读者对象',
+        publisher: '出版单位',
+        // 多行文本
+        content_intro: '内容简介',
+        background: '选题背景',
+        author_intro: '作者简介',
+        // 上传图片
+        cover_image_file_url: '封面图片',
+        // 日期
+        plan_publish_date: '计划出版日期',
+        // 数字
+        content_count_YG: '预计容量(课数)',
+        word_count_YG: '预计字数',
+        // 对象
+        label_list: '作品标签',
+      },
+      stringValue: this.value,
+      arrayValue: [],
+      imageId: '',
+      labelInput: '',
+    };
+  },
+  computed: {
+    dialogWidth() {
+      if (['content_count_YG', 'word_count_YG', 'plan_publish_date'].includes(this.field)) {
+        return '260px';
+      }
+      if (this.field === 'label_list') {
+        return '460px';
+      }
+      return '550px';
+    },
+  },
+  watch: {
+    value(newVal) {
+      this.stringValue = newVal;
+
+      if (this.field === 'label_list' && Array.isArray(newVal)) {
+        this.arrayValue = [...newVal];
+      }
+    },
+  },
+  methods: {
+    // 处理标签输入
+    labelChange() {
+      if (this.labelInput.trim() !== '') {
+        this.arrayValue.push(this.labelInput.trim());
+        this.labelInput = '';
+      }
+    },
+    beforeUpload(file) {
+      const isImage = /^image/.test(file.type);
+      if (!isImage) {
+        this.$message.error('上传的文件不是图片,请重新上传!');
+      }
+      return isImage;
+    },
+    upload(file) {
+      if (file.file.size / 1048576 > 2) {
+        return this.$message.warning(`${file.file.name}文件大小超出限制`);
+      }
+      fileUpload('Open', file, { isGlobalprogress: true }).then(({ file_info_list }) => {
+        if (file_info_list.length > 0) {
+          const { file_url, file_id } = file_info_list[0];
+          this.stringValue = file_url;
+          this.imageId = file_id;
+        }
+      });
+    },
+    handleClose() {
+      this.$emit('update:visible', false);
+    },
+    confirm() {
+      if (
+        [
+          'name',
+          'editor',
+          'category',
+          'language',
+          'topic',
+          'reader',
+          'publisher',
+          'content_intro',
+          'background',
+          'author_intro',
+          'content_count_YG',
+          'word_count_YG',
+          'plan_publish_date',
+        ].includes(this.field)
+      ) {
+        this.$emit('updateProjectFieldValue', this.field, this.stringValue);
+      }
+      if (this.field === 'cover_image_file_url') {
+        this.$emit('updateProjectFieldValue', 'cover_image_file_id', this.imageId);
+      }
+      if (this.field === 'label_list') {
+        this.$emit('updateProjectFieldValue', this.field, this.arrayValue);
+      }
+      this.handleClose();
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.upload-image {
+  .avatar-uploader {
+    :deep .el-upload {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      width: 418px;
+      height: 280px;
+      margin: 0 auto;
+      overflow: hidden;
+      cursor: pointer;
+      border: 1px dashed #d9d9d9;
+      border-radius: 6px;
+
+      &:hover {
+        border-color: #409eff;
+      }
+    }
+
+    &-icon {
+      width: 418px;
+      height: 280px;
+      font-size: 28px;
+      line-height: 280px;
+      color: #8c939d;
+      text-align: center;
+    }
+
+    .avatar {
+      display: block;
+      max-width: 418px;
+      max-height: 280px;
+    }
+  }
+}
+
+.label-input-content {
+  display: flex;
+  flex-direction: column;
+  width: 420px;
+
+  .label-list {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 4px;
+    padding: 12px 8px;
+  }
+
+  .el-input {
+    flex: 1;
+    min-width: 120px;
+    margin-left: 6px;
+  }
+}
+</style>