CustomerInfo.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. <template>
  2. <div class="content" v-loading="loading">
  3. <div class="user-name">
  4. <i class="iconfont icon-icon_factory1" style="color:#0084ff;margin-right:10px;"></i>{{ detailsData.name }}
  5. </div>
  6. <div class="line">
  7. <span class="title_" v-if="detailsData.customerCode">客户代码:<span style="color:#000">{{ detailsData.customerCode }}</span></span>
  8. <span class="title_" v-if="detailsData.customerCode && detailsData.status" style="margin: 0 6px">|</span>
  9. <span class="title_" v-if="detailsData.status">客户类型:<span style="color:#000">{{ dictValueLabel(detailsData.status, customerStatus) }}</span></span>
  10. </div>
  11. <div class="line" v-if="detailsData.source">
  12. <span class="title_">客户来源:</span>
  13. <span>{{ dictValueLabel(detailsData.source, customerSource) }}</span>
  14. </div>
  15. <div class="line">
  16. <span class="title_">地址:</span>
  17. <span
  18. >{{ detailsData.countryName }} , {{ detailsData.provinceName }} ,
  19. {{ detailsData.cityName }}
  20. <span v-show="detailsData.address"> , {{ detailsData.address }}</span>
  21. </span>
  22. </div>
  23. <div class="contacts" v-if="detailsData.customerUserList.length > 0">
  24. <div style="display: flex; justify-content: space-between">
  25. <span> 相关联系人: </span>
  26. <el-button type="primary" size="small" style="padding: 0px" text @click="handleAddUserList(detailsData)">添加</el-button>
  27. </div>
  28. <div>
  29. <div v-for="(item, index) in detailsData.customerUserList" :key="index" class="item" v-show="!(index > 1)">
  30. <div class="img">
  31. <i class="iconfont icon-iconm_kehd" style="font-size: 26px; color: #cccccc; margin-top: 2px"></i>
  32. </div>
  33. <div class="details">
  34. <div>
  35. <span> {{ item.name }} </span>
  36. </div>
  37. <div class="information">
  38. <div class="first"><span class="val">Tel:</span>{{ getPhone(item) }}</div>
  39. <div style="display: flex; justify-content: space-between; height: 20px; line-height: 20px">
  40. <span class="val" style="flex: 1">Email:</span>{{ item.email }}
  41. <img
  42. src="@/assets/images/portrait/icon_email.png"
  43. alt=""
  44. style="cursor: pointer; margin-left: 10px; transform: translateY(-1px)"
  45. @click="handleSendEmail(item)"
  46. v-show="item.email" />
  47. </div>
  48. </div>
  49. </div>
  50. </div>
  51. <div style="float: right" v-if="detailsData.customerUserList && detailsData.customerUserList.length > 1">
  52. <el-button type="primary" link size="small">更多联系人</el-button>
  53. </div>
  54. </div>
  55. </div>
  56. <el-dialog :title="'添加联系人'" v-if="dialogVisible" v-model="dialogVisible" width="800" v-loading="loadingOperation">
  57. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="submit">
  58. <template #person>
  59. <div style="width: 100%">
  60. <el-table :data="formData.data.customerUserList" style="width: 100%; margin-top: 16px">
  61. <el-table-column label="联系人" width="160">
  62. <template #default="{ row, $index }">
  63. <div style="width: 100%">
  64. <el-form-item :prop="'customerUserList.' + $index + '.name'" :rules="rules.name2" :inline-message="true">
  65. <el-input v-model="row.name" placeholder="请输入联系人" />
  66. </el-form-item>
  67. </div>
  68. </template>
  69. </el-table-column>
  70. <el-table-column label="电子邮箱">
  71. <template #default="{ row, $index }">
  72. <div style="width: 100%">
  73. <el-form-item :prop="'customerUserList.' + $index + '.email'" :rules="rules.email" :inline-message="true">
  74. <el-input v-model="row.email" placeholder="请输入电子邮箱" />
  75. </el-form-item>
  76. </div>
  77. </template>
  78. </el-table-column>
  79. <el-table-column align="center" label="操作" width="120" fixed="right">
  80. <template #default="{ row, $index }">
  81. <el-button type="primary" link @click="clickInformationMore(row, $index)">更多</el-button>
  82. </template>
  83. </el-table-column>
  84. </el-table>
  85. </div>
  86. </template>
  87. </byForm>
  88. <template #footer>
  89. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  90. <el-button type="primary" @click="submitForm()" size="large" :loading="submitLoading">确 定</el-button>
  91. </template>
  92. </el-dialog>
  93. <el-dialog title="更多联系方式" v-if="openPerson" v-model="openPerson" width="700">
  94. <el-form :label-position="'top'" :model="formPerson.data" :rules="rulesPerson" ref="person">
  95. <el-form-item label="联系人" prop="name">
  96. <el-input v-model="formPerson.data.name" />
  97. </el-form-item>
  98. <el-form-item label="电子邮箱" prop="email">
  99. <el-input v-model="formPerson.data.email" />
  100. </el-form-item>
  101. <el-form-item label="更多联系方式">
  102. <div style="width: 100%">
  103. <el-button type="primary" @click="clickAddMoreInformation">添 加</el-button>
  104. <el-table :data="formPerson.data.contact" style="width: 100%; margin-top: 16px">
  105. <el-table-column label="类型" width="180">
  106. <template #default="{ row, $index }">
  107. <div style="width: 100%">
  108. <el-form-item :prop="'contact.' + $index + '.type'" :rules="rulesPerson.type" :inline-message="true">
  109. <el-select v-model="row.type" placeholder="请选择类型" style="width: 100%">
  110. <el-option v-for="item in contactType" :key="item.value" :label="item.label" :value="item.value" />
  111. </el-select>
  112. </el-form-item>
  113. </div>
  114. </template>
  115. </el-table-column>
  116. <el-table-column label="联系号码">
  117. <template #default="{ row, $index }">
  118. <div style="width: 100%">
  119. <el-form-item :prop="'contact.' + $index + '.contactNo'" :rules="rulesPerson.contactNo" :inline-message="true">
  120. <el-input v-model="row.contactNo" placeholder="请输入联系号码" />
  121. </el-form-item>
  122. </div>
  123. </template>
  124. </el-table-column>
  125. <el-table-column align="center" label="操作" width="120" fixed="right">
  126. <template #default="{ $index }">
  127. <el-button type="primary" link @click="clickInformationDelete($index)">删除</el-button>
  128. </template>
  129. </el-table-column>
  130. </el-table>
  131. </div>
  132. </el-form-item>
  133. </el-form>
  134. <template #footer>
  135. <el-button @click="openPerson = false" size="large">取 消</el-button>
  136. <el-button type="primary" @click="submitPerson()" size="large">确 定</el-button>
  137. </template>
  138. </el-dialog>
  139. </div>
  140. </template>
  141. <script setup>
  142. import { ElMessage } from "element-plus";
  143. import byForm from "@/components/byForm/index";
  144. const props = defineProps({
  145. customerId: {
  146. type: String,
  147. },
  148. });
  149. const { proxy } = getCurrentInstance();
  150. const loading = ref(false);
  151. const submitLoading = ref(false);
  152. let detailsData = ref({
  153. customerUserList: [],
  154. });
  155. let formData = reactive({
  156. data: {},
  157. });
  158. let formPerson = reactive({
  159. data: {},
  160. });
  161. const formOption = reactive({
  162. inline: true,
  163. labelWidth: 100,
  164. itemWidth: 100,
  165. rules: [],
  166. });
  167. let rules = ref({
  168. name: [{ required: true, message: "请输入客户名称", trigger: "blur" }],
  169. name2: [{ required: true, message: "请输入联系人", trigger: "blur" }],
  170. email: [{ required: true, message: "请输入电子邮箱", trigger: "blur" }],
  171. countryId: [{ required: true, message: "请选择国家", trigger: "change" }],
  172. provinceId: [{ required: true, message: "请选择省/州", trigger: "change" }],
  173. cityId: [{ required: true, message: "请选择城市", trigger: "change" }],
  174. source: [{ required: true, message: "请选择客户来源", trigger: "change" }],
  175. status: [{ required: true, message: "请选择类型", trigger: "change" }],
  176. });
  177. let rulesPerson = ref({
  178. name: [{ required: true, message: "请输入联系人", trigger: "blur" }],
  179. email: [{ required: true, message: "请输入电子邮箱", trigger: "blur" }],
  180. type: [{ required: true, message: "请选择类型", trigger: "change" }],
  181. contactNo: [{ required: true, message: "请输入联系号码", trigger: "blur" }],
  182. });
  183. const formConfig = computed(() => {
  184. return [
  185. {
  186. type: "slot",
  187. slotName: "person",
  188. label: "客户联系人",
  189. },
  190. ];
  191. });
  192. const dialogVisible = ref(false);
  193. const openPerson = ref(false);
  194. const getData = () => {
  195. loading.value = true;
  196. proxy.post("/customer/detail", { id: props.customerId }).then((res) => {
  197. detailsData.value = res;
  198. setTimeout(() => {
  199. loading.value = false;
  200. }, 200);
  201. });
  202. };
  203. const customerSource = ref([]);
  204. const customerStatus = ref([]);
  205. const contactType = ref([]);
  206. const getDict = () => {
  207. proxy.getDictOne(["customer_source", "customer_status", "contact_type"]).then((res) => {
  208. customerSource.value = res["customer_source"].map((x) => ({
  209. label: x.dictValue,
  210. value: x.dictKey,
  211. }));
  212. customerStatus.value = res["customer_status"].map((x) => ({
  213. label: x.dictValue,
  214. value: x.dictKey,
  215. }));
  216. contactType.value = res["contact_type"].map((x) => ({
  217. label: x.dictValue,
  218. value: x.dictKey,
  219. }));
  220. });
  221. };
  222. getDict();
  223. onMounted(() => {
  224. if (props.customerId) {
  225. getData();
  226. }
  227. });
  228. const handleSendEmail = (item) => {
  229. proxy.$router.push({
  230. path: "/connect/E-mail/mail",
  231. query: {
  232. mail: item.email,
  233. },
  234. });
  235. };
  236. const handleAddUserList = (res) => {
  237. formData.data.customerUserList = [
  238. {
  239. name: "",
  240. email: "",
  241. },
  242. ];
  243. dialogVisible.value = true;
  244. };
  245. const moreIndex = ref(-1);
  246. const clickInformationMore = (item, index) => {
  247. moreIndex.value = index;
  248. if (item.contactJson) {
  249. item.contact = JSON.parse(item.contactJson);
  250. } else {
  251. item.contact = [];
  252. }
  253. formPerson.data = proxy.deepClone(item);
  254. openPerson.value = true;
  255. };
  256. const clickAddMoreInformation = () => {
  257. if (formPerson.data.contact && formPerson.data.contact.length > 0) {
  258. formPerson.data.contact.push({
  259. type: "",
  260. contactNo: "",
  261. });
  262. } else {
  263. formPerson.data.contact = [
  264. {
  265. type: "",
  266. contactNo: "",
  267. },
  268. ];
  269. }
  270. };
  271. const clickInformationDelete = (index) => {
  272. formPerson.data.contact.splice(index, 1);
  273. };
  274. const person = ref(null);
  275. const submit = ref(null);
  276. const submitPerson = () => {
  277. person.value.validate((valid) => {
  278. if (valid) {
  279. formPerson.data.contactJson = JSON.stringify(formPerson.data.contact);
  280. formData.data.customerUserList[moreIndex.value] = formPerson.data;
  281. openPerson.value = false;
  282. }
  283. });
  284. };
  285. const submitForm = () => {
  286. submit.value.handleSubmit(() => {
  287. if (formData.data.customerUserList && formData.data.customerUserList.length > 0) {
  288. submitLoading.value = true;
  289. const data = {
  290. customerId: detailsData.value.id,
  291. ...formData.data.customerUserList[0],
  292. };
  293. proxy.post("/customerUser/add", data).then(
  294. () => {
  295. ElMessage({
  296. message: "添加成功",
  297. type: "success",
  298. });
  299. dialogVisible.value = false;
  300. getData();
  301. },
  302. (err) => {
  303. submitLoading.value = false;
  304. }
  305. );
  306. } else {
  307. ElMessage("请添加客户联系人");
  308. }
  309. });
  310. };
  311. const getPhone = (res) => {
  312. if (res.contactJson) {
  313. let contactJson = JSON.parse(res.contactJson);
  314. if (contactJson && contactJson.length > 0) {
  315. return contactJson[0].contactNo;
  316. }
  317. }
  318. };
  319. </script>
  320. <style lang="scss" scoped>
  321. .user-name{
  322. font-weight: bold;
  323. border-bottom:1px solid #dcdcdc;
  324. line-height: 30px;
  325. margin-bottom: 20px;
  326. }
  327. .content {
  328. font-size: 12px;
  329. padding: 10px;
  330. .company {
  331. margin-bottom: 10px;
  332. }
  333. .company-name {
  334. font-weight: 600;
  335. font-size: 13px;
  336. color: #333333;
  337. }
  338. .contacts {
  339. margin-top: 15px;
  340. .item {
  341. padding: 10px;
  342. display: flex;
  343. margin: 6px 0px;
  344. border: 1px dashed #dddddd;
  345. .img {
  346. width: 40px;
  347. height: 40px;
  348. border-radius: 50%;
  349. background: #eeeeee;
  350. text-align: center;
  351. line-height: 40px;
  352. }
  353. .details {
  354. margin-left: 10px;
  355. display: flex;
  356. flex: 1;
  357. flex-direction: column;
  358. justify-content: space-between;
  359. .information {
  360. display: flex;
  361. align-items: center;
  362. flex-wrap: wrap;
  363. .first {
  364. margin-right: 10px;
  365. height: 20px;
  366. line-height: 20px;
  367. }
  368. .val {
  369. color: #999999;
  370. }
  371. }
  372. }
  373. }
  374. .more {
  375. text-align: right;
  376. }
  377. }
  378. }
  379. .title_ {
  380. color: #999999;
  381. }
  382. .line {
  383. margin-bottom: 6px;
  384. }
  385. .img {
  386. // width: 15px;
  387. // height: 15px;
  388. // object-fit: contain;
  389. cursor: pointer;
  390. }
  391. ::v-deep(.el-button--small) {
  392. --el-button-size: 20px;
  393. }
  394. </style>