IotProjectInfoForm.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. <template>
  2. <ContentWrap v-loading="formLoading">
  3. <el-form
  4. ref="formRef"
  5. :model="formData"
  6. :rules="formRules"
  7. label-width="120px"
  8. v-loading="formLoading"
  9. >
  10. <el-row>
  11. <el-col :span="12">
  12. <el-form-item label="客户名称" prop="manufacturerId">
  13. <el-select
  14. clearable
  15. @clear="zzClear"
  16. v-model="formData.manufactureName"
  17. :placeholder="t('deviceForm.mfgHolder')"
  18. @click="openCustomerZz"
  19. />
  20. </el-form-item>
  21. </el-col>
  22. <el-col :span="12">
  23. <el-form-item :label="t('project.payment')" prop="payment">
  24. <el-select v-model="formData.payment" placeholder="请选择" clearable>
  25. <el-option
  26. v-for="dict in getStrDictOptions(DICT_TYPE.PMS_PROJECT_SETTLEMENT)"
  27. :key="dict.id"
  28. :label="dict.label"
  29. :value="dict.value"
  30. />
  31. </el-select>
  32. </el-form-item>
  33. </el-col>
  34. </el-row>
  35. <el-row>
  36. <el-col :span="12">
  37. <el-form-item label="合同名称" prop="contractName">
  38. <el-input v-model="formData.contractName" placeholder="请输入合同名称" />
  39. </el-form-item>
  40. </el-col>
  41. <el-col :span="12">
  42. <el-form-item label="合同编号" prop="contractCode">
  43. <el-input v-model="formData.contractCode" placeholder="请输入合同编号" />
  44. </el-form-item>
  45. </el-col>
  46. </el-row>
  47. <el-row>
  48. <el-col :span="12">
  49. <el-form-item label="总数" prop="workloadTotal">
  50. <el-input v-model="formData.workloadTotal" placeholder="请输入工作量总数" />
  51. </el-form-item>
  52. </el-col>
  53. <el-col :span="12">
  54. <el-form-item label="已完成" prop="workloadFinish">
  55. <el-input v-model="formData.workloadFinish" placeholder="已完成工作量" disabled/>
  56. </el-form-item>
  57. </el-col>
  58. </el-row>
  59. <el-row>
  60. <el-col :span="12">
  61. <el-form-item label="开始时间" prop="startTime">
  62. <el-date-picker
  63. style="width: 150%"
  64. v-model="formData.startTime"
  65. type="date"
  66. value-format="x"
  67. placeholder="选择开始时间"
  68. />
  69. </el-form-item>
  70. </el-col>
  71. <el-col :span="12">
  72. <el-form-item label="完成时间" prop="endTime">
  73. <el-date-picker
  74. style="width: 150%"
  75. v-model="formData.endTime"
  76. type="date"
  77. value-format="x"
  78. placeholder="选择完成时间"
  79. />
  80. </el-form-item>
  81. </el-col>
  82. </el-row>
  83. <el-row>
  84. <el-col :span="12">
  85. <el-form-item :label="t('iotDevice.company')" prop="deptId">
  86. <el-tree-select
  87. :disabled="isDeptDisabled"
  88. v-model="formData.deptId"
  89. :data="deptList"
  90. :props="defaultProps"
  91. check-strictly
  92. node-key="id"
  93. filterable
  94. placeholder="请选择所属公司"
  95. />
  96. </el-form-item>
  97. </el-col>
  98. <el-col :span="12">
  99. <el-form-item label="责任人" prop="responsiblePerson">
  100. <el-tooltip
  101. v-if="selectedUserNames"
  102. effect="dark"
  103. placement="top"
  104. :content="getFullSelectedUserNames()"
  105. >
  106. <span class="user-names">
  107. {{ selectedUserNames }}
  108. </span>
  109. </el-tooltip>
  110. <el-button
  111. type="primary"
  112. size="small"
  113. @click="openUserDialog"
  114. style="margin-left: 10px;"
  115. :disabled="!formData.deptId"
  116. >
  117. 选择责任人
  118. </el-button>
  119. <div v-if="!formData.deptId" class="el-form-item__error">请先选择所属公司</div>
  120. </el-form-item>
  121. </el-col>
  122. </el-row>
  123. <el-row>
  124. <el-col :span="12">
  125. <el-form-item :label="t('project.overseaFlag')" prop="payment">
  126. <el-select v-model="formData.overseas" placeholder="请选择" clearable>
  127. <el-option
  128. v-for="dict in getIntDictOptions(DICT_TYPE.PMS_PROJECT_OVERSEA_FLAG)"
  129. :key="dict.id"
  130. :label="dict.label"
  131. :value="dict.value"
  132. />
  133. </el-select>
  134. </el-form-item>
  135. </el-col>
  136. <el-col :span="12">
  137. <el-form-item :label="t('project.area')" prop="payment">
  138. <el-select v-model="formData.overseasArea" placeholder="请选择" clearable>
  139. <el-option
  140. v-for="dict in getStrDictOptions(DICT_TYPE.PMS_PROJECT_AREA)"
  141. :key="dict.id"
  142. :label="dict.label"
  143. :value="dict.value"
  144. />
  145. </el-select>
  146. </el-form-item>
  147. </el-col>
  148. </el-row>
  149. <el-row>
  150. <el-col :span="24">
  151. <el-form-item label="备注" prop="remark">
  152. <el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" />
  153. </el-form-item>
  154. </el-col>
  155. </el-row>
  156. </el-form>
  157. </ContentWrap>
  158. <CustomerList ref="customerZzFormRef" @choose="customerZzChoose" />
  159. <!-- 责任人选择对话框 -->
  160. <el-dialog
  161. v-model="userDialogVisible"
  162. title="选择责任人"
  163. width="1000px"
  164. :before-close="handleUserDialogClose"
  165. class="user-select-dialog"
  166. >
  167. <div class="transfer-container">
  168. <el-transfer
  169. v-model="selectedUserIds"
  170. :data="userList"
  171. :titles="['可选人员', '已选人员']"
  172. :props="{ key: 'id', label: 'nickname' }"
  173. filterable
  174. class="transfer-component"
  175. >
  176. <template #default="{ option }">
  177. <el-tooltip
  178. effect="dark"
  179. placement="top"
  180. :content="`${option.nickname} - ${option.deptName || '未分配部门'}`"
  181. >
  182. <span class="transfer-option-text">
  183. {{ option.nickname }} - {{ option.deptName || '未分配部门' }}
  184. </span>
  185. </el-tooltip>
  186. </template>
  187. </el-transfer>
  188. </div>
  189. <template #footer>
  190. <span class="dialog-footer">
  191. <el-button @click="handleUserDialogClose">取消</el-button>
  192. <el-button type="primary" @click="confirmUserSelection">确定</el-button>
  193. </span>
  194. </template>
  195. </el-dialog>
  196. <ContentWrap>
  197. <el-form style="float: right">
  198. <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
  199. <el-button @click="close">取 消</el-button>
  200. </el-form>
  201. </ContentWrap>
  202. </template>
  203. <script setup lang="ts">
  204. import { IotProjectInfoApi, IotProjectInfoVO } from '@/api/pms/iotprojectinfo'
  205. import {defaultProps,handleTree} from "@/utils/tree";
  206. import * as DeptApi from "@/api/system/dept";
  207. import IotProjectTaskForm from '@/views/pms/iotprojectinfo/IotProjectTaskForm.vue'
  208. import CustomerList from '@/views/pms/device/CustomerList.vue'
  209. import {ref} from "vue";
  210. import {useUserStore} from "@/store/modules/user";
  211. import {IotProjectTaskApi, IotProjectTaskVO} from "@/api/pms/iotprojecttask";
  212. import {ElMessageBox} from "element-plus";
  213. import {updateConfig} from "@/api/infra/config";
  214. import {useTagsViewStore} from "@/store/modules/tagsView";
  215. import * as UserApi from "@/api/system/user";
  216. import {UserVO} from "@/api/system/user";
  217. import {DICT_TYPE, getIntDictOptions, getStrDictOptions} from "@/utils/dict";
  218. /** 项目信息 表单 */
  219. defineOptions({ name: 'IotProjectInfo' })
  220. const { params, name } = useRoute() // 查询参数
  221. const id = params.id
  222. const { delView } = useTagsViewStore() // 视图操作
  223. const { currentRoute, push } = useRouter()
  224. const { t } = useI18n() // 国际化
  225. const message = useMessage() // 消息弹窗
  226. const deptList = ref<Tree[]>([]) // 树形结构
  227. const dialogVisible = ref(true) // 弹窗的是否展示
  228. const dialogTitle = ref('') // 弹窗的标题
  229. const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  230. const taskList = ref<IotProjectTaskVO[]>([]) // 列表的数据
  231. const formType = ref('') // 表单的类型:create - 新增;update - 修改
  232. const loading = ref(true) // 列表的加载中
  233. const simpleUsers = ref<UserVO[]>([]) // 责任人列表
  234. // 添加责任人相关变量
  235. const userDialogVisible = ref(false);
  236. const userList = ref([]); // 所有用户列表
  237. const selectedUserIds = ref([]); // 选中的用户ID
  238. const selectedUserNames = ref(''); // 选中的用户名称显示
  239. const selectedUserList = ref([]); // 存储选中的用户对象列表
  240. const formData = ref({
  241. id: undefined,
  242. deptId: undefined,
  243. deptName: undefined,
  244. contractName: undefined,
  245. contractCode: undefined,
  246. workloadTotal: undefined,
  247. workloadFinish: undefined,
  248. startTime: undefined,
  249. endTime: undefined,
  250. location: undefined,
  251. technique: undefined,
  252. payment: undefined,
  253. userName: useUserStore().getUser.name,
  254. userId: useUserStore().getUser.userId,
  255. })
  256. const close = () => {
  257. delView(unref(currentRoute))
  258. push({ name: 'iotProjectInfo', params:{}})
  259. }
  260. const queryParams = reactive({
  261. projectId:undefined
  262. })
  263. const formRules = reactive({
  264. manufacturerId: [{ required: true, message: '客户不能为空', trigger: 'blur' }],
  265. payment: [{ required: true, message: '结算方式不能为空', trigger: 'blur' }],
  266. contractName: [{ required: true, message: '合同名称不能为空', trigger: 'blur' }],
  267. contractCode: [{ required: true, message: '合同编码不能为空', trigger: 'blur' }],
  268. workloadTotal: [{ required: true, message: '工作量总数不能为空', trigger: 'blur' }],
  269. startTime: [{ required: true, message: '开始时间不能为空', trigger: 'blur' }],
  270. endTime: [{ required: true, message: '结束时间不能为空', trigger: 'blur' }],
  271. })
  272. const formRef1 = ref() // 表单 Ref
  273. const openForm = (type: string, id?: number) => {
  274. formRef1.value.open(type, id)
  275. }
  276. const zzClear = () =>{
  277. formData.value.manufacturerId = undefined
  278. formData.value.manufactureName = undefined
  279. }
  280. const customerZzChoose = (row) => {
  281. formData.value.manufacturerId = row.id
  282. // zzLabel.value = row.name
  283. formData.value.manufactureName = row.name
  284. }
  285. const customerZzFormRef = ref()
  286. const openCustomerZz = () => {
  287. customerZzFormRef.value.open()
  288. }
  289. // 格式化用户名称显示
  290. const formatUserNames = (users) => {
  291. if (!users || users.length === 0) return '';
  292. const names = users.map(user => user.nickname);
  293. if (names.length <= 2) {
  294. return names.join(', ');
  295. } else {
  296. return `${names[0]}, ${names[1]}...`;
  297. }
  298. };
  299. // 根据用户ID获取用户信息
  300. const fetchUserInfoByIds = async (userIds) => {
  301. if (!userIds || userIds.length === 0) {
  302. selectedUserList.value = [];
  303. selectedUserNames.value = '';
  304. return;
  305. }
  306. try {
  307. const params = {
  308. userIds: userIds
  309. };
  310. const response = await UserApi.companyDeptsEmployee(params); // 假设有这个API
  311. selectedUserList.value = response;
  312. selectedUserNames.value = formatUserNames(response);
  313. } catch (error) {
  314. console.error('获取用户信息失败:', error);
  315. ElMessage.error('获取用户信息失败');
  316. }
  317. };
  318. // 根据部门ID获取部门名称
  319. const getDeptNames = (deptIds) => {
  320. if (!deptIds || deptIds.length === 0) return '';
  321. const names = [];
  322. const findDept = (list, id) => {
  323. for (const item of list) {
  324. if (item.id === id) {
  325. names.push(item.name);
  326. return true;
  327. }
  328. if (item.children && findDept(item.children, id)) {
  329. return true;
  330. }
  331. }
  332. return false;
  333. };
  334. deptIds.forEach(id => findDept(deptList.value, id));
  335. return names.join(', ');
  336. };
  337. // 计算属性:判断部门选择框是否应该禁用
  338. const isDeptDisabled = computed(() => {
  339. return formType.value === 'update' || deptList.value.length === 1;
  340. });
  341. // 打开用户选择对话框
  342. const openUserDialog = async () => {
  343. try {
  344. // 获取用户列表,传递部门ID参数
  345. const params = {
  346. deptIds: [formData.value.deptId] // 将部门ID转换为数组格式
  347. };
  348. // 获取用户列表
  349. const response = await UserApi.companyDeptsEmployee(params);
  350. userList.value = response;
  351. // 设置当前已选中的用户
  352. selectedUserIds.value = formData.value.responsiblePerson || [];
  353. userDialogVisible.value = true;
  354. } catch (error) {
  355. console.error('获取用户列表失败:', error);
  356. ElMessage.error('获取用户列表失败');
  357. }
  358. };
  359. // 确认用户选择
  360. const confirmUserSelection = () => {
  361. // 更新表单数据
  362. formData.value.responsiblePerson = [...selectedUserIds.value];
  363. // 更新显示的用户名称
  364. updateSelectedUserNames();
  365. userDialogVisible.value = false;
  366. };
  367. // 更新显示的用户名称
  368. const updateSelectedUserNames = () => {
  369. console.log('已经保存的责任人:' + formData.value.responsiblePerson)
  370. if (!formData.value.responsiblePerson || formData.value.responsiblePerson.length === 0) {
  371. selectedUserNames.value = '';
  372. return;
  373. }
  374. const selectedUsers = userList.value.filter(user =>
  375. formData.value.responsiblePerson.includes(user.id)
  376. );
  377. const names = selectedUsers.map(user => user.nickname);
  378. if (names.length <= 2) {
  379. selectedUserNames.value = names.join(', ');
  380. } else {
  381. selectedUserNames.value = `${names[0]}, ${names[1]}...`;
  382. }
  383. };
  384. // 关闭用户选择对话框
  385. const handleUserDialogClose = () => {
  386. userDialogVisible.value = false;
  387. };
  388. const tableData = ref([
  389. {
  390. id: 1,
  391. wellName: '',
  392. wellType: '',
  393. location: '',
  394. technique: '',
  395. workloadDesign: '',
  396. deptIds: [],
  397. remark:'',
  398. editData: {},
  399. editing:true,
  400. originalData: {},
  401. errors: {}
  402. },
  403. ]);
  404. let deptInfo: any[] = "";
  405. /** 打开弹窗 */
  406. const open = async () => {
  407. resetForm()
  408. // 修改时,设置数据
  409. if (id) {
  410. formType.value = 'update';
  411. formLoading.value = true
  412. try {
  413. formData.value = await IotProjectInfoApi.getIotProjectInfo(id)
  414. // 如果已有责任人数据,获取用户信息并显示
  415. if (formData.value.responsiblePerson && formData.value.responsiblePerson.length > 0) {
  416. await fetchUserInfoByIds(formData.value.responsiblePerson);
  417. selectedUserIds.value = [...formData.value.responsiblePerson];
  418. }
  419. // 如果已有责任人数据,更新显示
  420. if (formData.value.responsiblePerson) {
  421. // updateSelectedUserNames();
  422. }
  423. } finally {
  424. formLoading.value = false
  425. }
  426. } else {
  427. formType.value = 'create';
  428. // 如果只有一个部门,则自动选中
  429. if (deptList.value.length === 1) {
  430. formData.value.deptId = deptList.value[0].id;
  431. }
  432. }
  433. }
  434. defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  435. /** 提交表单 */
  436. const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
  437. const formRef = ref() // 表单 Ref
  438. const submitForm = async () => {
  439. // 校验表单
  440. await formRef.value.validate()
  441. // 提交请求
  442. formLoading.value = true
  443. try {
  444. // formData.value.deptId = useUserStore().getUser.deptId;
  445. const data = {
  446. projectData: formData.value as unknown as IotProjectInfoVO,
  447. //taskList:tableData.value
  448. }
  449. if (formType.value === 'create') {
  450. await IotProjectInfoApi.createIotProjectInfo(data)
  451. message.success(t('common.createSuccess'))
  452. } else {
  453. await IotProjectInfoApi.updateIotProjectInfo(data)
  454. message.success(t('common.updateSuccess'))
  455. }
  456. dialogVisible.value = false
  457. // 发送操作成功的事件
  458. emit('success')
  459. close()
  460. } finally {
  461. formLoading.value = false
  462. }
  463. }
  464. /** 重置表单 */
  465. const resetForm = () => {
  466. formData.value = {
  467. id: undefined,
  468. deptId: undefined,
  469. deptName: undefined,
  470. contractName: undefined,
  471. contractCode: undefined,
  472. workloadTotal: undefined,
  473. workloadFinish: undefined,
  474. startTime: undefined,
  475. endTime: undefined,
  476. location: undefined,
  477. technique: undefined,
  478. payment: undefined,
  479. userName: undefined,
  480. userId: undefined,
  481. responsiblePerson: [], // 重置责任人字段
  482. }
  483. selectedUserNames.value = '';
  484. formRef.value?.resetFields()
  485. }
  486. onMounted(async () => {
  487. // deptList.value = handleTree(await DeptApi.getSimpleDeptList())
  488. // 查询当前登录人所属的 公司级部门 如果部门列表只有一个值 默认选中
  489. deptList.value = await DeptApi.companyLevelDepts()
  490. // 如果只有一个部门,则自动选中
  491. if (deptList.value.length === 1) {
  492. formData.value.deptId = deptList.value[0].id;
  493. }
  494. open();
  495. })
  496. const showCloumn = false;
  497. // 表格数据
  498. // 计算正在编辑的行数
  499. const editingRowsCount = computed(() => {
  500. return tableData.value.filter(row => row.editing).length;
  501. });
  502. // 格式化日期
  503. const formatDate = (timestamp) => {
  504. const date = new Date(timestamp);
  505. return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
  506. };
  507. // 为编辑中的行添加特殊样式
  508. const rowClassName = ({ row }) => {
  509. return row.editing ? 'editable-row' : '';
  510. };
  511. // 添加新行
  512. const addNewRow = () => {
  513. const newId = tableData.value.length > 0
  514. ? Math.max(...tableData.value.map(item => item.id)) + 1
  515. : 1;
  516. const newRow = {
  517. id: newId,
  518. wellName: '',
  519. wellType: '',
  520. location: '',
  521. technique: '',
  522. workloadDesign: '',
  523. deptIds: [],
  524. remark:'',
  525. editing: true,
  526. editData: {
  527. wellName: '',
  528. wellType: '',
  529. location: '',
  530. technique: '',
  531. workloadDesign: '',
  532. deptIds:[],
  533. remark:'',
  534. },
  535. originalData: {},
  536. errors: {}
  537. };
  538. tableData.value.unshift(newRow);
  539. };
  540. // 编辑行
  541. const editRow = (row) => {
  542. // 保存原始数据用于取消编辑时恢复
  543. row.originalData = {...row};
  544. // 设置编辑数据
  545. row.editData = {
  546. id: row.id,
  547. wellName: row.wellName,
  548. wellType: row.wellType,
  549. location: row.location,
  550. technique: row.technique,
  551. workloadDesign: row.workloadDesign,
  552. deptIds: row.deptIds,
  553. remark:row.remark,
  554. };
  555. // 进入编辑状态
  556. row.editing = true;
  557. // 清空错误信息
  558. row.errors = {};
  559. };
  560. // 验证行数据
  561. const validateRow = (row) => {
  562. row.errors = {};
  563. let valid = true;
  564. if (!row.editData.wellName || row.editData.wellName.trim() === '') {
  565. row.errors.name = '井号不能为空';
  566. valid = false;
  567. }
  568. if (!row.editData.wellType || row.editData.wellType.trim() === '') {
  569. row.errors.email = '井型不能为空';
  570. valid = false;
  571. }
  572. return valid;
  573. };
  574. // 保存行
  575. const saveRow = (row) => {
  576. if (!validateRow(row)) return;
  577. // 将编辑数据应用到行
  578. row.id = row.editData.id;
  579. row.wellName = row.editData.wellName;
  580. row.wellType = row.editData.wellType;
  581. row.location = row.editData.location;
  582. row.technique = row.editData.technique;
  583. row.workloadDesign = row.editData.workloadDesign;
  584. row.deptIds = row.editData.deptIds;
  585. row.remark = row.editData.remark;
  586. // 退出编辑状态
  587. row.editing = false;
  588. };
  589. // 生成Tooltip要显示的完整责任人名称字符串
  590. const getFullSelectedUserNames = () => {
  591. if (!selectedUserList.value || selectedUserList.value.length === 0) {
  592. return '';
  593. }
  594. return selectedUserList.value.map(user => user.nickname).join(', ');
  595. };
  596. // 保存所有更改
  597. const saveAll = () => {
  598. let allValid = true;
  599. // 验证所有编辑中的行
  600. tableData.value.forEach(row => {
  601. if (row.editing && !validateRow(row)) {
  602. allValid = false;
  603. }
  604. });
  605. if (!allValid) {
  606. ElMessage.error('部分数据验证失败,请检查输入');
  607. return;
  608. }
  609. // 保存所有编辑中的行
  610. tableData.value.forEach(row => {
  611. if (row.editing) {
  612. row.id = row.editData.id;
  613. row.wellName = row.editData.wellName;
  614. row.wellType = row.editData.wellType;
  615. row.location = row.editData.location;
  616. row.technique = row.editData.technique;
  617. row.workloadDesign = row.editData.workloadDesign;
  618. row.deptIds = row.editData.deptIds;
  619. row.remark = row.editData.remark;
  620. }
  621. });
  622. ElMessage.success('所有更改已保存');
  623. };
  624. // 取消编辑
  625. const cancelEdit = (row) => {
  626. // 恢复原始数据
  627. if (row.originalData.id) {
  628. row.id = row.originalData.id;
  629. row.wellName = row.originalData.wellName;
  630. row.wellType = row.originalData.wellType;
  631. row.location = row.originalData.location;
  632. row.technique = row.originalData.technique;
  633. row.workloadDesign = row.originalData.workloadDesign;
  634. row.deptIds = row.originalData.deptIds;
  635. row.remark = row.originalData.remark;
  636. } else {
  637. // 如果是新增行,则删除
  638. const index = tableData.value.indexOf(row);
  639. if (index !== -1) {
  640. tableData.value.splice(index, 1);
  641. }
  642. }
  643. row.editing = false;
  644. };
  645. // 删除行
  646. const deleteRow = (index) => {
  647. tableData.value.splice(index, 1);
  648. ElMessage.success('行已删除');
  649. };
  650. </script>
  651. <style scoped>
  652. .user-names {
  653. padding: 0px 10px;
  654. border: 1px solid #dcdfe6;
  655. border-radius: 4px;
  656. background-color: #f5f7fa;
  657. display: inline-block;
  658. min-width: 200px;
  659. max-height: 32px;
  660. }
  661. .transfer-container {
  662. text-align: center;
  663. padding: 20px 0;
  664. }
  665. /* 3. 直接调整 el-transfer 左右窗口的宽度 */
  666. :deep(.el-transfer-panel) {
  667. width: 40% !important; /* 强制设置左右面板宽度,确保两侧面板对等 */
  668. }
  669. .transfer-component {
  670. width: 100%;
  671. min-width: 600px;
  672. }
  673. :deep(.el-transfer-panel__item) {
  674. white-space: nowrap;
  675. overflow: hidden;
  676. text-overflow: ellipsis;
  677. max-width: 100%;
  678. padding: 6px 6px;
  679. }
  680. .transfer-option-text {
  681. display: inline-block;
  682. max-width: 100%;
  683. }
  684. :deep(.el-transfer-panel__list) {
  685. width: 100% !important; /* 使面板内部内容宽度占满 */
  686. }
  687. </style>