addEditDrawer.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. <template>
  2. <el-drawer v-model="visible" :title="title" :size="'50%'" :before-close="handleClose" destroy-on-close :close-on-click-modal="true">
  3. <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
  4. <!-- <el-form-item label="项目编号" prop="projectNo">
  5. <el-input v-model="form.projectNo" placeholder="请输入项目编号" />
  6. </el-form-item> -->
  7. <el-form-item label="项目logo" prop="projectLogo">
  8. <div class="logo-upload" @click="showFileSelector = true">
  9. <img v-if="form.projectLogo" :src="form.projectLogo" alt="项目logo" class="logo-image" />
  10. <div v-else class="logo-placeholder">
  11. <el-icon :size="40"><Plus /></el-icon>
  12. <span>点击上传</span>
  13. </div>
  14. </div>
  15. <FileSelector v-model="showFileSelector" :allowed-types="[1]" @confirm="handleFileConfirm" />
  16. </el-form-item>
  17. <el-form-item label="项目名称" prop="projectName">
  18. <el-input v-model="form.projectName" placeholder="请输入项目名称" />
  19. </el-form-item>
  20. <el-form-item label="负责人" prop="leaderId">
  21. <el-select v-model="form.leaderId" placeholder="请选择负责人" filterable @change="handleLeaderChange">
  22. <el-option v-for="staff in staffList" :key="staff.staffId" :label="staff.staffName" :value="staff.staffId" />
  23. </el-select>
  24. </el-form-item>
  25. <el-form-item label="备注" prop="remark">
  26. <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
  27. </el-form-item>
  28. </el-form>
  29. <template #footer>
  30. <div class="drawer-footer">
  31. <el-button @click="handleClose">取 消</el-button>
  32. <el-button :loading="buttonLoading" type="primary" @click="handleSubmit">确 定</el-button>
  33. </div>
  34. </template>
  35. </el-drawer>
  36. </template>
  37. <script setup lang="ts">
  38. import { ref, watch, onMounted } from 'vue';
  39. import { ProjectInfoForm } from '@/api/project/projectInfo/types';
  40. import { addProjectInfo, updateProjectInfo } from '@/api/project/projectInfo';
  41. import FileSelector from '@/components/FileSelector/index.vue';
  42. import { ElMessage } from 'element-plus';
  43. import { Plus } from '@element-plus/icons-vue';
  44. import { listComStaff } from '@/api/company/comStaff';
  45. import { ComStaffVO } from '@/api/company/comStaff/types';
  46. interface Props {
  47. modelValue: boolean;
  48. title?: string;
  49. formData?: ProjectInfoForm;
  50. }
  51. interface Emits {
  52. (e: 'update:modelValue', value: boolean): void;
  53. (e: 'success'): void;
  54. }
  55. const props = withDefaults(defineProps<Props>(), {
  56. title: '添加项目信息'
  57. });
  58. const emit = defineEmits<Emits>();
  59. const formRef = ref();
  60. const buttonLoading = ref(false);
  61. const visible = ref(false);
  62. const showFileSelector = ref(false);
  63. const staffList = ref<ComStaffVO[]>([]);
  64. const initFormData: ProjectInfoForm = {
  65. id: undefined,
  66. projectNo: undefined,
  67. projectLogo: undefined,
  68. projectName: undefined,
  69. projectType: undefined,
  70. leaderId: undefined,
  71. leaderName: undefined,
  72. status: undefined,
  73. remark: undefined
  74. };
  75. const form = ref<ProjectInfoForm>({ ...initFormData });
  76. const rules = {};
  77. watch(
  78. () => props.modelValue,
  79. (val) => {
  80. visible.value = val;
  81. if (val && props.formData) {
  82. form.value = { ...props.formData };
  83. } else if (val) {
  84. form.value = { ...initFormData };
  85. }
  86. }
  87. );
  88. watch(visible, (val) => {
  89. emit('update:modelValue', val);
  90. });
  91. const handleClose = () => {
  92. visible.value = false;
  93. formRef.value?.resetFields();
  94. };
  95. const handleFileConfirm = (files: any[]) => {
  96. if (files && files.length > 0) {
  97. form.value.projectLogo = files[0].url;
  98. }
  99. };
  100. const handleLeaderChange = (value: string | number) => {
  101. const selectedStaff = staffList.value.find((staff) => staff.staffId === value);
  102. if (selectedStaff) {
  103. form.value.leaderName = selectedStaff.staffName;
  104. }
  105. };
  106. const loadStaffList = async () => {
  107. try {
  108. const res = await listComStaff({ pageNum: 1, pageSize: 1000 });
  109. staffList.value = res.rows || [];
  110. } catch (error) {
  111. console.error('加载员工列表失败:', error);
  112. }
  113. };
  114. onMounted(() => {
  115. loadStaffList();
  116. });
  117. const handleSubmit = async () => {
  118. await formRef.value?.validate(async (valid: boolean) => {
  119. if (valid) {
  120. buttonLoading.value = true;
  121. try {
  122. if (form.value.id) {
  123. await updateProjectInfo(form.value);
  124. } else {
  125. await addProjectInfo(form.value);
  126. }
  127. ElMessage.success('操作成功');
  128. visible.value = false;
  129. emit('success');
  130. } finally {
  131. buttonLoading.value = false;
  132. }
  133. }
  134. });
  135. };
  136. </script>
  137. <style scoped lang="scss">
  138. .drawer-footer {
  139. display: flex;
  140. justify-content: flex-end;
  141. gap: 10px;
  142. }
  143. .logo-upload {
  144. width: 100px;
  145. height: 100px;
  146. border-radius: 50%;
  147. border: 2px dashed #d9d9d9;
  148. display: flex;
  149. align-items: center;
  150. justify-content: center;
  151. cursor: pointer;
  152. overflow: hidden;
  153. transition: all 0.3s;
  154. &:hover {
  155. border-color: #409eff;
  156. }
  157. .logo-image {
  158. width: 100%;
  159. height: 100%;
  160. object-fit: cover;
  161. }
  162. .logo-placeholder {
  163. display: flex;
  164. flex-direction: column;
  165. align-items: center;
  166. justify-content: center;
  167. color: #8c939d;
  168. font-size: 12px;
  169. span {
  170. margin-top: 8px;
  171. }
  172. }
  173. }
  174. </style>