add.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. <template>
  2. <div class="p-4">
  3. <!-- 页面标题和按钮 -->
  4. <div class="flex justify-between items-center mb-4">
  5. <div class="flex items-center gap-2">
  6. <el-button icon="ArrowLeft" @click="router.back()">返回</el-button>
  7. <span class="text-lg font-medium">{{ isEdit ? '编辑' : '新增' }}维保</span>
  8. </div>
  9. </div>
  10. <!-- 企业基本信息 -->
  11. <el-card shadow="never" class="mb-4">
  12. <template #header>
  13. <span class="font-medium">企业基本信息</span>
  14. </template>
  15. <el-form :model="form" label-width="140px">
  16. <el-row :gutter="20">
  17. <el-col :span="8">
  18. <el-form-item label="企业名称" prop="customerId">
  19. <el-select v-model="form.customerId" placeholder="请选择企业" class="w-full" filterable @change="handleCustomerChange">
  20. <el-option v-for="customer in customerList" :key="customer.id" :label="customer.companyName" :value="customer.id" />
  21. </el-select>
  22. </el-form-item>
  23. </el-col>
  24. </el-row>
  25. <el-row :gutter="20">
  26. <el-col :span="8">
  27. <el-form-item label="企业规模">
  28. <el-input v-model="customerInfo.enterpriseScale" disabled />
  29. </el-form-item>
  30. </el-col>
  31. <el-col :span="8">
  32. <el-form-item label="所属行业">
  33. <el-input v-model="customerInfo.industryCategory" disabled />
  34. </el-form-item>
  35. </el-col>
  36. <el-col :span="8">
  37. <el-form-item label="合作等级">
  38. <el-input v-model="customerInfo.cooperationLevel" disabled />
  39. </el-form-item>
  40. </el-col>
  41. </el-row>
  42. <el-row :gutter="20">
  43. <el-col :span="8">
  44. <el-form-item label="会员等级">
  45. <el-input v-model="customerInfo.memberLevel" disabled />
  46. </el-form-item>
  47. </el-col>
  48. <el-col :span="8">
  49. <el-form-item label="固定电话">
  50. <el-input v-model="customerInfo.phone" disabled />
  51. </el-form-item>
  52. </el-col>
  53. </el-row>
  54. <el-row :gutter="20">
  55. <el-col :span="8">
  56. <el-form-item label="办公地址">
  57. <el-input v-model="customerInfo.provincialCityCounty" disabled />
  58. </el-form-item>
  59. </el-col>
  60. <el-col :span="8">
  61. <el-form-item>
  62. <el-input v-model="customerInfo.address" disabled />
  63. </el-form-item>
  64. </el-col>
  65. </el-row>
  66. </el-form>
  67. </el-card>
  68. <!-- 销售信息 -->
  69. <el-card shadow="never" class="mb-4">
  70. <template #header>
  71. <span class="font-medium">销售信息</span>
  72. </template>
  73. <el-form :model="form" label-width="140px">
  74. <el-row :gutter="20">
  75. <el-col :span="12">
  76. <el-form-item label="业务员">
  77. <el-input v-model="customerInfo.salesPerson" disabled placeholder="请选择" />
  78. </el-form-item>
  79. </el-col>
  80. <el-col :span="12">
  81. <el-form-item label="客服人员">
  82. <el-input v-model="customerInfo.servicePerson" disabled placeholder="请选择" />
  83. </el-form-item>
  84. </el-col>
  85. </el-row>
  86. </el-form>
  87. </el-card>
  88. <!-- 维保信息 -->
  89. <el-card shadow="never" class="mb-4">
  90. <template #header>
  91. <span class="font-medium">维保信息</span>
  92. </template>
  93. <el-form ref="maintainFormRef" :model="form" :rules="rules" label-width="140px">
  94. <el-row :gutter="20">
  95. <el-col :span="8">
  96. <el-form-item label="申请人名称" prop="applicantName">
  97. <el-input v-model="form.applicantName" placeholder="请输入申请人名称" />
  98. </el-form-item>
  99. </el-col>
  100. <el-col :span="8">
  101. <el-form-item label="申请人手机号" prop="applicantPhone">
  102. <el-input v-model="form.applicantPhone" placeholder="请输入申请人手机号" />
  103. </el-form-item>
  104. </el-col>
  105. <el-col :span="8">
  106. <el-form-item label="服务时间(月)" prop="serviceTime">
  107. <el-select v-model="form.serviceTime" placeholder="请选择服务时间" class="w-full" filterable>
  108. <el-option v-for="dict in service_time_type" :key="dict.value" :label="dict.label" :value="dict.value" />
  109. </el-select>
  110. </el-form-item>
  111. </el-col>
  112. </el-row>
  113. <el-row :gutter="20">
  114. <el-col :span="8">
  115. <el-form-item label="月度维保次数" prop="monthMainten">
  116. <el-input-number
  117. v-model="form.monthMainten"
  118. :min="0"
  119. :controls="false"
  120. class="w-full"
  121. placeholder="请输入月度维保次数"
  122. style="width: 100%"
  123. />
  124. </el-form-item>
  125. </el-col>
  126. <el-col :span="8">
  127. <el-form-item label="剩余维保次数" prop="remainingMainten">
  128. <el-input
  129. v-model="form.remainingMainten"
  130. :min="0"
  131. :controls="false"
  132. class="w-full"
  133. placeholder="请输入剩余维保次数"
  134. style="width: 100%"
  135. />
  136. </el-form-item>
  137. </el-col>
  138. <el-col :span="8">
  139. <el-form-item label="维保次数限制" prop="maintenLimit">
  140. <el-input v-model="form.maintenLimit" :min="0" class="w-full" :controls="false" placeholder="请输入维保次数限制" style="width: 100%" />
  141. </el-form-item>
  142. </el-col>
  143. </el-row>
  144. <el-row :gutter="20">
  145. <el-col :span="8">
  146. <el-form-item label="服务工程师" prop="serviceEngineer">
  147. <el-select v-model="form.serviceEngineer" placeholder="请选择" class="w-full" filterable>
  148. <el-option label="工程师A" value="工程师A" />
  149. <el-option label="工程师B" value="工程师B" />
  150. <el-option label="工程师C" value="工程师C" />
  151. </el-select>
  152. </el-form-item>
  153. </el-col>
  154. <el-col :span="8">
  155. <el-form-item label="工程师电话" prop="engineerPhone">
  156. <el-input v-model="form.engineerPhone" placeholder="请输入工程师电话" />
  157. </el-form-item>
  158. </el-col>
  159. <el-col :span="8">
  160. <el-form-item label="开始时间" prop="serviceStartTime">
  161. <el-date-picker
  162. v-model="form.serviceStartTime"
  163. type="date"
  164. placeholder="请选择"
  165. class="w-full"
  166. value-format="YYYY-MM-DD"
  167. style="width: 100%"
  168. />
  169. </el-form-item>
  170. </el-col>
  171. </el-row>
  172. <el-row :gutter="20">
  173. <el-col :span="8">
  174. <el-form-item label="结束时间" prop="serviceEndTime">
  175. <el-date-picker
  176. v-model="form.serviceEndTime"
  177. type="date"
  178. placeholder="请选择"
  179. class="w-full"
  180. value-format="YYYY-MM-DD"
  181. style="width: 100%"
  182. />
  183. </el-form-item>
  184. </el-col>
  185. <el-col :span="8">
  186. <el-form-item label="维保类型" prop="maintainType">
  187. <el-select v-model="form.maintainType" placeholder="请选择" class="w-full" filterable>
  188. <el-option v-for="dict in maintenance_type" :key="dict.value" :label="dict.label" :value="dict.value" />
  189. </el-select>
  190. </el-form-item>
  191. </el-col>
  192. </el-row>
  193. <el-row :gutter="20">
  194. <el-col :span="24">
  195. <el-form-item label="服务内容" prop="serviceContent">
  196. <el-checkbox-group v-model="form.serviceContent">
  197. <el-checkbox v-for="item in serviceContentList" :key="item.id" :value="item.id">{{ item.itemName }}</el-checkbox>
  198. </el-checkbox-group>
  199. </el-form-item>
  200. </el-col>
  201. </el-row>
  202. <el-row :gutter="20">
  203. <el-col :span="24">
  204. <el-form-item label="维保合同" prop="maintainFile">
  205. <el-upload action="#" :auto-upload="false" :file-list="fileList" :on-change="handleFileChange">
  206. <el-button type="primary">点击上传</el-button>
  207. </el-upload>
  208. </el-form-item>
  209. </el-col>
  210. </el-row>
  211. <el-row :gutter="20">
  212. <el-col :span="24">
  213. <el-form-item label="其他服务" prop="otherService">
  214. <el-input v-model="form.otherService" type="textarea" :rows="3" placeholder="请输入其他服务" />
  215. </el-form-item>
  216. </el-col>
  217. </el-row>
  218. </el-form>
  219. <el-button type="primary" @click="handleSubmit" :loading="submitLoading">提交</el-button>
  220. </el-card>
  221. </div>
  222. </template>
  223. <script setup lang="ts" name="MaintainInfoAdd">
  224. import { addMaintainInfo, updateMaintainInfo, getMaintainInfo } from '@/api/customer/maintainInfo';
  225. import { listCustomerInfo, getCustomerInfo } from '@/api/customer/customerFile/customerInfo';
  226. import { getEnterpriseScale } from '@/api/customer/customerCategory/enterpriseScale';
  227. import { getIndustryCategory } from '@/api/customer/customerCategory/industryCategory';
  228. import { listServerItem } from '@/api/customer/serverItem';
  229. import { CustomerInfoVO } from '@/api/customer/customerFile/customerInfo/types';
  230. import type { ServerItemVO } from '@/api/customer/serverItem/types';
  231. import type { MaintainInfoForm } from '@/api/customer/maintainInfo/types';
  232. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  233. const { service_time_type, maintenance_type } = toRefs<any>(proxy?.useDict('service_time_type', 'maintenance_type'));
  234. const route = useRoute();
  235. const router = useRouter();
  236. const formRef = ref<any>(null);
  237. const maintainFormRef = ref<any>(null);
  238. const submitLoading = ref(false);
  239. const isEdit = ref(false);
  240. const fileList = ref<any[]>([]);
  241. const customerList = ref<CustomerInfoVO[]>([]);
  242. const serviceContentList = ref<ServerItemVO[]>([]);
  243. // 客户信息(选择企业后自动带出)
  244. const customerInfo = reactive({
  245. customerNo: '',
  246. enterpriseScale: '',
  247. industryCategory: '',
  248. cooperationLevel: '',
  249. memberLevel: '',
  250. phone: '',
  251. address: '',
  252. provincialCityCounty: '',
  253. salesPerson: '',
  254. servicePerson: ''
  255. });
  256. // 表单数据
  257. const form = reactive<any>({
  258. customerId: undefined,
  259. applicantName: '',
  260. applicantPhone: '',
  261. serviceTime: '',
  262. monthMainten: undefined,
  263. remainingMainten: undefined,
  264. maintenLimit: undefined,
  265. serviceEngineer: '',
  266. engineerPhone: '',
  267. serviceStartTime: '',
  268. serviceEndTime: '',
  269. maintainType: '',
  270. serviceContent: [],
  271. maintainFile: '',
  272. otherService: '',
  273. status: '0'
  274. });
  275. // 表单验证规则
  276. const rules = {
  277. customerId: [{ required: true, message: '请选择企业名称', trigger: 'change' }],
  278. applicantName: [{ required: true, message: '请输入申请人名称', trigger: 'blur' }],
  279. applicantPhone: [
  280. { required: true, message: '请输入申请人手机号', trigger: 'blur' },
  281. { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
  282. ],
  283. serviceEngineer: [{ required: true, message: '请选择服务工程师', trigger: 'change' }]
  284. };
  285. // 初始化
  286. onMounted(async () => {
  287. // 加载客户列表
  288. await loadCustomerList();
  289. // 加载服务内容列表
  290. await loadServiceContentList();
  291. const _id = route.query.id;
  292. if (_id) {
  293. isEdit.value = true;
  294. await loadMaintainData(_id as any);
  295. }
  296. });
  297. // 加载客户列表
  298. const loadCustomerList = async () => {
  299. try {
  300. const res = await listCustomerInfo();
  301. customerList.value = res.rows || [];
  302. } catch (error) {
  303. console.error('加载客户列表失败:', error);
  304. ElMessage.error('加载客户列表失败');
  305. }
  306. };
  307. // 加载服务内容列表
  308. const loadServiceContentList = async () => {
  309. try {
  310. const res = await listServerItem();
  311. serviceContentList.value = res.rows || [];
  312. } catch (error) {
  313. console.error('加载服务内容列表失败:', error);
  314. ElMessage.error('加载服务内容列表失败');
  315. }
  316. };
  317. // 选择企业后加载企业信息
  318. const handleCustomerChange = async (customerId: string | number) => {
  319. if (!customerId) return;
  320. try {
  321. const res = await getCustomerInfo(customerId);
  322. const data = res.data;
  323. // 填充企业基本信息 - 使用API获取真实数据
  324. customerInfo.customerNo = data.customerNo;
  325. // customerInfo.memberLevel = getCustomerLevelName(data.customerLevelId);
  326. customerInfo.phone = data.landline || '';
  327. customerInfo.address = data.address || '';
  328. customerInfo.provincialCityCounty = data.provincialCityCounty || '';
  329. customerInfo.industryCategory = data.industryCategory || '-';
  330. customerInfo.enterpriseScale = data.enterpriseScale || '-';
  331. // 填充销售信息
  332. if (data.customerSalesInfoVo) {
  333. customerInfo.salesPerson = res.data.customerSalesInfoVo?.salesPerson;
  334. customerInfo.servicePerson = res.data.customerSalesInfoVo?.serviceStaff;
  335. }
  336. } catch (error) {
  337. ElMessage.error('加载企业信息失败');
  338. }
  339. };
  340. // 加载维保数据
  341. const loadMaintainData = async (id: string | number) => {
  342. try {
  343. const res = await getMaintainInfo(id);
  344. const data = res.data;
  345. // 将服务内容字符串(ID列表)转换为数组
  346. if (data.serviceContent && typeof data.serviceContent === 'string') {
  347. data.serviceContent = data.serviceContent.split(',').filter((item: string) => item.trim());
  348. }
  349. Object.assign(form, data);
  350. // 如果有客户ID,加载客户信息
  351. if (form.customerId) {
  352. await handleCustomerChange(form.customerId);
  353. }
  354. } catch (error) {
  355. ElMessage.error('加载维保数据失败');
  356. }
  357. };
  358. // 文件变化
  359. const handleFileChange = (file: any, uploadFileList: any[]) => {
  360. fileList.value = uploadFileList;
  361. console.log('文件变化:', file, uploadFileList);
  362. };
  363. // 提交表单
  364. const handleSubmit = async () => {
  365. try {
  366. await maintainFormRef.value?.validate();
  367. submitLoading.value = true;
  368. // 准备提交数据,将 serviceContent 数组(ID列表)转换为逗号分隔的字符串
  369. const submitData = {
  370. ...form,
  371. serviceContent: Array.isArray(form.serviceContent) ? form.serviceContent.join(',') : form.serviceContent
  372. };
  373. if (isEdit.value) {
  374. await updateMaintainInfo(submitData);
  375. ElMessage.success('修改成功');
  376. } else {
  377. await addMaintainInfo(submitData);
  378. ElMessage.success('添加成功');
  379. }
  380. router.back();
  381. } catch (error) {
  382. console.error('保存失败:', error);
  383. ElMessage.error('保存失败,请重试');
  384. } finally {
  385. submitLoading.value = false;
  386. }
  387. };
  388. </script>