add.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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="dict in service_content" :key="dict.value" :value="dict.value">{{ dict.label }}</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 { CustomerInfoVO } from '@/api/customer/customerFile/customerInfo/types';
  229. import type { MaintainInfoForm } from '@/api/customer/maintainInfo/types';
  230. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  231. const { service_content, service_time_type, maintenance_type } = toRefs<any>(
  232. proxy?.useDict('service_content', 'service_time_type', 'maintenance_type')
  233. );
  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. // 客户信息(选择企业后自动带出)
  243. const customerInfo = reactive({
  244. customerNo: '',
  245. enterpriseScale: '',
  246. industryCategory: '',
  247. cooperationLevel: '',
  248. memberLevel: '',
  249. phone: '',
  250. address: '',
  251. provincialCityCounty: '',
  252. salesPerson: '',
  253. servicePerson: ''
  254. });
  255. // 表单数据
  256. const form = reactive<any>({
  257. customerId: undefined,
  258. applicantName: '',
  259. applicantPhone: '',
  260. serviceTime: '',
  261. monthMainten: undefined,
  262. remainingMainten: undefined,
  263. maintenLimit: undefined,
  264. serviceEngineer: '',
  265. engineerPhone: '',
  266. serviceStartTime: '',
  267. serviceEndTime: '',
  268. maintainType: '',
  269. serviceContent: [],
  270. maintainFile: '',
  271. otherService: '',
  272. status: '0'
  273. });
  274. // 表单验证规则
  275. const rules = {
  276. customerId: [{ required: true, message: '请选择企业名称', trigger: 'change' }],
  277. applicantName: [{ required: true, message: '请输入申请人名称', trigger: 'blur' }],
  278. applicantPhone: [
  279. { required: true, message: '请输入申请人手机号', trigger: 'blur' },
  280. { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
  281. ],
  282. serviceEngineer: [{ required: true, message: '请选择服务工程师', trigger: 'change' }]
  283. };
  284. // 初始化
  285. onMounted(async () => {
  286. // 加载客户列表
  287. await loadCustomerList();
  288. const _id = route.query.id;
  289. if (_id) {
  290. isEdit.value = true;
  291. await loadMaintainData(_id);
  292. }
  293. });
  294. // 加载客户列表
  295. const loadCustomerList = async () => {
  296. try {
  297. const res = await listCustomerInfo();
  298. customerList.value = res.rows || [];
  299. } catch (error) {
  300. console.error('加载客户列表失败:', error);
  301. ElMessage.error('加载客户列表失败');
  302. }
  303. };
  304. // 选择企业后加载企业信息
  305. const handleCustomerChange = async (customerId: string | number) => {
  306. if (!customerId) return;
  307. try {
  308. const res = await getCustomerInfo(customerId);
  309. const data = res.data;
  310. // 填充企业基本信息 - 使用API获取真实数据
  311. customerInfo.customerNo = data.customerNo;
  312. customerInfo.cooperationLevel = getCustomerLevelName(data.customerLevelId);
  313. customerInfo.memberLevel = getCustomerLevelName(data.customerLevelId);
  314. customerInfo.phone = data.landline || '';
  315. customerInfo.address = data.address || '';
  316. customerInfo.provincialCityCounty = data.provincialCityCounty || '';
  317. customerInfo.industryCategory = data.industryCategory || '-';
  318. customerInfo.enterpriseScale = data.enterpriseScale || '-';
  319. // 填充销售信息
  320. if (data.customerSalesInfoVo) {
  321. customerInfo.salesPerson = getSalesPersonName(data.customerSalesInfoVo.salesPersonId);
  322. customerInfo.servicePerson = getServiceStaffName(data.customerSalesInfoVo.serviceStaffId);
  323. }
  324. } catch (error) {
  325. console.error('加载企业信息失败:', error);
  326. ElMessage.error('加载企业信息失败');
  327. }
  328. };
  329. // 格式化方法
  330. const getCustomerLevelName = (id: string | number | undefined) => {
  331. const map: Record<string, string> = { '1': 'A级', '2': 'B级', '3': 'C级', '4': 'D级' };
  332. return map[String(id)] || '-';
  333. };
  334. const getSalesPersonName = (id: string | number | undefined) => {
  335. const map: Record<string, string> = { '1': '张三', '2': '李四', '3': '王五', '4': '赵六' };
  336. return map[String(id)] || '-';
  337. };
  338. const getServiceStaffName = (id: string | number | undefined) => {
  339. const map: Record<string, string> = { '1': '客服A', '2': '客服B', '3': '客服C', '4': '客服D' };
  340. return map[String(id)] || '-';
  341. };
  342. // 加载维保数据
  343. const loadMaintainData = async (id: string | number) => {
  344. try {
  345. const res = await getMaintainInfo(id);
  346. const data = res.data;
  347. // 将服务内容字符串转换为数组
  348. if (data.serviceContent && typeof data.serviceContent === 'string') {
  349. data.serviceContent = data.serviceContent.split(',').filter((item: string) => item.trim());
  350. }
  351. Object.assign(form, data);
  352. // 如果有客户ID,加载客户信息
  353. if (form.customerId) {
  354. await handleCustomerChange(form.customerId);
  355. }
  356. } catch (error) {
  357. console.error('加载维保数据失败:', error);
  358. ElMessage.error('加载维保数据失败');
  359. }
  360. };
  361. // 文件变化
  362. const handleFileChange = (file: any, uploadFileList: any[]) => {
  363. fileList.value = uploadFileList;
  364. console.log('文件变化:', file, uploadFileList);
  365. };
  366. // 提交表单
  367. const handleSubmit = async () => {
  368. try {
  369. await maintainFormRef.value?.validate();
  370. submitLoading.value = true;
  371. // 准备提交数据,将 serviceContent 数组转换为逗号分隔的字符串
  372. const submitData = {
  373. ...form,
  374. serviceContent: Array.isArray(form.serviceContent) ? form.serviceContent.join(',') : form.serviceContent
  375. };
  376. if (isEdit.value) {
  377. await updateMaintainInfo(submitData);
  378. ElMessage.success('修改成功');
  379. } else {
  380. await addMaintainInfo(submitData);
  381. ElMessage.success('添加成功');
  382. }
  383. router.back();
  384. } catch (error) {
  385. console.error('保存失败:', error);
  386. ElMessage.error('保存失败,请重试');
  387. } finally {
  388. submitLoading.value = false;
  389. }
  390. };
  391. </script>