index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. <template>
  2. <div class="h-full flex">
  3. <div class="p-5 w-80 pr-0">
  4. <div class="bg-white w-full h-full shadow-md rounded-md flex flex-col">
  5. <div class="flex-1 p-3 overflow-y-auto">
  6. <!-- 筛选条件 -->
  7. <el-form :model="filterForm" label-width="70px" style="max-width: 600px">
  8. <el-form-item v-for="(item, index) in filterItems" :key="index" :label="item.label">
  9. <el-input v-if="item.type === 'input'" v-model="filterForm[item.key as keyof FilterForm]" clearable
  10. placeholder="请输入"></el-input>
  11. <el-select v-else v-model="filterForm[item.key as keyof FilterForm]" placeholder="请选择" clearable>
  12. <el-option v-for="option in item.options" :key="option.id" :label="option.name" :value="option.id" />
  13. </el-select>
  14. </el-form-item>
  15. </el-form>
  16. </div>
  17. <div class="w-full flex p-3 shadow-[0_-3px_5px_0px_rgba(0,0,0,0.2)]">
  18. <El-button class="w-full" @click="resetForm()" :loading="allLoading.formTableLading">重置</El-Button>
  19. <El-button type="primary" class="w-full" :loading="allLoading.formTableLading"
  20. @click="getContactPerson()">搜索</El-Button>
  21. </div>
  22. </div>
  23. </div>
  24. <div class="flex-1 p-5 overflow-auto">
  25. <div class="bg-white w-full h-full p-3 shadow-md rounded-md flex flex-col">
  26. <div class="flex justify-end pb-3">
  27. <!-- 操作按钮 -->
  28. <!-- <el-button v-for="(button, index) in actionButtons" :key="index" type="primary">{{ button.text }}</el-button> -->
  29. <el-button type="primary" @click="editContacts(false)">新建联系人</el-button>
  30. <el-button type="primary" @click="batchDeteleItem" :disabled="batchTableData.length <= 0">批量删除</el-button>
  31. <el-button type="primary" @click="showVisible('deteleContactsVisible')">回收站</el-button>
  32. <el-button type="primary" @click="showVisible('importVisible')">导入</el-button>
  33. <el-button type="primary" @click="exportCustomerTableList()" :loading="allLoading.exoprtLoading">导出</el-button>
  34. </div>
  35. <div class="flex-1 w-full overflow-hidden">
  36. <!-- 表格 -->
  37. <el-table ref="contactsTableRef" :data="formTable" border v-loading="allLoading.formTableLading"
  38. style="width: 100%;height: 100%;" @selection-change="changeBatch">
  39. <el-table-column type="selection" width="55" />
  40. <el-table-column v-for="(column, index) in tableColumns" :key="index" :prop="column.prop"
  41. :label="column.label" :width="column.width">
  42. <template #default="scope">
  43. <template v-if="column.event === 'toDetali'">
  44. <el-button link type="primary" size="large" @click="toDetali(scope.row)">{{ scope.row.name
  45. }}</el-button>
  46. </template>
  47. <template v-if="column.event === 'getSex'">
  48. {{ getSex(scope.row.sex) }}
  49. </template>
  50. </template>
  51. </el-table-column>
  52. <el-table-column :label="'操作'" :width="'140px'" fixed="right">
  53. <template #default="scope">
  54. <el-button link type="primary" size="large" @click="editContacts(scope.row)">编辑</el-button>
  55. <el-button link type="danger" size="large"
  56. @click="contactsDeteleItem(scope.row.id, scope.row.customName)">删除</el-button>
  57. </template>
  58. </el-table-column>
  59. </el-table>
  60. </div>
  61. <div class="flex justify-end pt-3">
  62. <!-- 分页 -->
  63. <el-pagination layout="total, prev, pager, next, sizes" @size-change="handleSizeChange"
  64. @current-change="handleCurrentChange" :total="tableTotal" :hide-on-single-page="true" />
  65. </div>
  66. </div>
  67. </div>
  68. <!-- 弹窗 -->
  69. <el-dialog v-model="allVisible.editContactsVisible" width="1000" :show-close="false" top="10vh">
  70. <template #header="{ close, titleId, titleClass }">
  71. <div class="flex justify-between items-center border-b pb-3 dialog-header">
  72. <h4 :id="titleId">{{ allText.editContactsText }}</h4>
  73. <div>
  74. <el-button type="primary" :loading="allLoading.editContactsSaveLoading"
  75. @click="editContactsSave(true)">保存并新建</el-button>
  76. <el-button type="primary" :loading="allLoading.editContactsSaveLoading"
  77. @click="editContactsSave(false)">保存</el-button>
  78. <el-button @click="closeVisible('editContactsVisible')">取消</el-button>
  79. </div>
  80. </div>
  81. </template>
  82. <div class="h-[60vh] overflow-y-auto scroll-bar pt-3">
  83. <div class="ml-4 mr-4">
  84. <GenerateForm ref="contactsTemplateRef" :data="contactsTemplate" :value="contactsTemplateValue"
  85. :key="contactsTemplateRefKey" v-loading="allLoading.contactsTemplateRefLoading" />
  86. </div>
  87. </div>
  88. </el-dialog>
  89. <!-- 回收站 -->
  90. <DeteleTables :visibles="allVisible.deteleContactsVisible" @closeVisible="closeVisible" />
  91. <!-- 导入 -->
  92. <el-dialog v-model="allVisible.importVisible" width="680" :show-close="false" top="10vh">
  93. <template #header="{ close, titleId, titleClass }">
  94. <div class="flex justify-between items-center border-b pb-3 dialog-header">
  95. <h4 :id="titleId">导入联系人</h4>
  96. <div class="flex">
  97. <el-upload class="upload-demo mr-3" :limit="1" :show-file-list="false" accept=".xlsx"
  98. :http-request="importBusiness">
  99. <el-button type="primary" :loading="allLoading.importLoading">导入</el-button>
  100. </el-upload>
  101. <el-button @click="allVisible.importVisible = false">取消</el-button>
  102. </div>
  103. </div>
  104. </template>
  105. <div class="p-8">
  106. <div class="ml-4 mr-4">
  107. <div class="flex items-center">1、点击下载 <el-link type="primary"
  108. @click="downloadTemplate(IMPORTMOD, allText.importText)">{{ allText.importText }}</el-link></div>
  109. <div class="mt-4">2、填写excel文件、联系人、客户名称必填</div>
  110. </div>
  111. </div>
  112. </el-dialog>
  113. </div>
  114. </template>
  115. <script lang="ts" setup>
  116. import { ref, reactive, onMounted, inject } from "vue";
  117. import { getAllListByCode, getFromValue, resetFromValue, getTemplateKey, confirmAction, downloadTemplate, downloadFile } from '@/utils/tools'
  118. import { post, get, uploadFile } from "@/utils/request";
  119. import { actionButtons, tableColumns, GETSYSFILED, GETPERSONNEL, GETGENERATEFOEM, MOD, URL_PAGECONTACTS, getSex, URL_ADD, URL_UPLOAD, URL_BATCHDETELE, URL_DETELERECYCLE, IMPORTMOD } from "./api";
  120. import { useRouter, useRoute } from "vue-router";
  121. import { GenerateForm } from '@zmjs/form-design';
  122. import { URL_FETALL } from "../customer/api";
  123. import { ElTable, UploadRequestOptions } from "element-plus";
  124. import DeteleTables from './component/deteleTables.vue'
  125. const router = useRouter()
  126. const globalPopup = inject<GlobalPopup>('globalPopup')
  127. const filterForm = reactive<FilterForm>({ // 筛选条件
  128. contactPerson: "",
  129. customerId: "",
  130. phoneNumber: '',
  131. responsibleId: '',
  132. createId: '',
  133. email: '',
  134. });
  135. const formTablePaging = reactive({ // 分页条件
  136. pageIndex: 1,
  137. pageSize: 10,
  138. })
  139. const tableTotal = ref(0)
  140. const selectData = reactive({ // 下拉数据
  141. Personnel: [] as personnelInterface[],
  142. Customer: [] as any[],
  143. })
  144. const filterItems = ref<FilterItem[]>([
  145. { label: '联系人', key: 'contactPerson', type: 'input' },
  146. { label: '客户名称', key: 'customerId', type: 'select', options: selectData.Customer },
  147. { label: '电话号码', key: 'phoneNumber', type: 'input' },
  148. { label: '邮箱', key: 'email', type: 'input' },
  149. { label: '负责人', key: 'responsibleId', type: 'select', options: selectData.Personnel },
  150. { label: '创建人', key: 'createId', type: 'select', options: selectData.Personnel },
  151. ])
  152. const contactsTemplate = ref({
  153. list: [],
  154. config: {}
  155. })
  156. const contactsTemplateValue = ref({})
  157. const contactsTemplateRefKey = ref(1)
  158. const contactsTemplateRef = ref<typeof GenerateForm>()
  159. const contactsTableRef = ref<InstanceType<typeof ElTable>>()
  160. const formTable = ref([]) // 表格数据
  161. const batchTableData = ref([])
  162. const allLoading = reactive({ // 按钮加载 Loading
  163. formTableLading: false,
  164. editContactsSaveLoading: false,
  165. contactsTemplateRefLoading: false,
  166. importLoading: false,
  167. exoprtLoading: false
  168. })
  169. const allVisible = reactive({
  170. editContactsVisible: false,
  171. taskModalVisible: false,
  172. deteleContactsVisible: false,
  173. importVisible: false
  174. })
  175. const allText = reactive({
  176. editContactsText: '新建联系人',
  177. importText: '联系人导入模板.xlsx',
  178. exportText: '联系人导出.xlsx'
  179. })
  180. // 方法
  181. function exportCustomerTableList() {
  182. allLoading.exoprtLoading = true
  183. let valueForm = getFromValue(filterForm)
  184. post('接口名称', { ...valueForm }).then((res) => {
  185. downloadFile(res.data, allText.exportText)
  186. }).finally(() => {
  187. allLoading.exoprtLoading = false
  188. })
  189. }
  190. async function importBusiness(param: UploadRequestOptions) {
  191. allLoading.importLoading = true
  192. const formData = new FormData();
  193. formData.append('multipartFile', param.file)
  194. const res = await uploadFile('接口名称', formData).finally(() => {
  195. allLoading.importLoading = false
  196. })
  197. if (res.code == 'ok') {
  198. globalPopup?.showSuccess('导入成功' || '')
  199. getContactPerson()
  200. return
  201. }
  202. globalPopup?.showError(res.msg || '')
  203. }
  204. function batchDeteleItem() {
  205. const value = batchTableData.value.map((item: any) => item.id).join(',')
  206. const label = batchTableData.value.map((item: any) => item.customName).join(',')
  207. contactsDeteleItem(value, label, true)
  208. }
  209. function contactsDeteleItem(value: string | number, label: string, batch: boolean = false) {
  210. confirmAction(`确定${batch ? '批量' : ''}删除【${label}】客户吗?`).then(() => {
  211. let url = batch ? URL_BATCHDETELE : URL_DETELERECYCLE
  212. post(url, { ids: value }).then(res => {
  213. if (res.code != 'ok') {
  214. globalPopup?.showError(res.msg)
  215. return
  216. }
  217. globalPopup?.showSuccess('删除成功')
  218. changeBatch(false)
  219. getContactPerson()
  220. }).catch((err) => {
  221. globalPopup?.showError(err.message)
  222. })
  223. })
  224. }
  225. function changeBatch(flag: boolean = true) {
  226. if (flag) {
  227. batchTableData.value = contactsTableRef.value && contactsTableRef.value.getSelectionRows()
  228. } else {
  229. batchTableData.value = []
  230. contactsTableRef.value && contactsTableRef.value.clearSelection()
  231. }
  232. }
  233. function editContactsSave(flag: boolean) {
  234. contactsTemplateRef.value?.getData().then((res: any) => {
  235. allLoading.editContactsSaveLoading = true
  236. let url = allText.editContactsText == '新建联系人' ? URL_ADD : URL_UPLOAD
  237. post(url, { ...contactsTemplateValue.value, ...res }).then((_res) => {
  238. allVisible.editContactsVisible = flag
  239. globalPopup?.showSuccess('保存成功')
  240. if (flag) {
  241. contactsTemplateRef.value?.reset()
  242. allText.editContactsText = '新建联系人'
  243. }
  244. getContactPerson()
  245. }).finally(() => {
  246. allLoading.editContactsSaveLoading = false
  247. })
  248. }).catch((_err: any) => {
  249. console.log(_err)
  250. globalPopup?.showError('请填写完整')
  251. })
  252. }
  253. function editContacts(row: any) { // row 有数据代表编辑
  254. showVisible('editContactsVisible')
  255. if (row) {
  256. const templateKey = getTemplateKey(contactsTemplate.value.list)
  257. const formVal: templateKey = { id: row.id }
  258. for (let i in templateKey) {
  259. formVal[templateKey[i]] = templateKey[i] == 'sex' ? row[templateKey[i]] + '' : row[templateKey[i]]
  260. }
  261. setTemplateVal(formVal)
  262. allText.editContactsText = '编辑联系人'
  263. } else {
  264. setTemplateVal()
  265. allText.editContactsText = '新建联系人'
  266. }
  267. }
  268. function setTemplateVal(val: any = {}) {
  269. contactsTemplateValue.value = val
  270. allLoading.contactsTemplateRefLoading = true
  271. setTimeout(() => {
  272. contactsTemplateRefKey.value++
  273. allLoading.contactsTemplateRefLoading = false
  274. }, 1000);
  275. }
  276. function toDetali(row: any) {
  277. router.push({
  278. path: `${MOD}/detail`,
  279. query: { id: row.name }
  280. })
  281. }
  282. function getContactPerson() {
  283. allLoading.formTableLading = true
  284. const formVal = getFromValue(filterForm)
  285. post(URL_PAGECONTACTS, { ...formVal, ...formTablePaging }).then((res) => {
  286. const { records, total } = res.data
  287. formTable.value = records
  288. tableTotal.value = total
  289. }).finally(() => {
  290. allLoading.formTableLading = false
  291. })
  292. }
  293. function resetForm() {
  294. let newResetForm = resetFromValue(filterForm)
  295. Object.assign(filterForm, newResetForm)
  296. getContactPerson()
  297. }
  298. async function getSystemField() {
  299. const { data } = await post(GETPERSONNEL, {})
  300. selectData.Personnel = data.map((item: any) => {
  301. const { id, name, phone, jobNumber } = item
  302. return {
  303. id, name, phone, jobNumber
  304. }
  305. })
  306. const res = await get(URL_FETALL, {})
  307. selectData.Customer = (res.data || []).map((item: any) => {
  308. const { id, customName } = item
  309. return {
  310. id,
  311. name: customName
  312. }
  313. })
  314. const datas = await get(GETGENERATEFOEM)
  315. contactsTemplate.value = JSON.parse(datas.data[0].config)
  316. setFilterItems()
  317. }
  318. function handleSizeChange(val: number) {
  319. formTablePaging.pageIndex = 1
  320. formTablePaging.pageSize = val
  321. getContactPerson()
  322. }
  323. function handleCurrentChange(val: number) {
  324. formTablePaging.pageIndex = val
  325. getContactPerson()
  326. }
  327. function showVisible(type: keyof typeof allVisible) {
  328. allVisible[type] = true
  329. }
  330. function closeVisible(type: keyof typeof allVisible) {
  331. allVisible[type] = false
  332. }
  333. function setFilterItems() {
  334. console.log(selectData)
  335. filterItems.value = [
  336. { label: '联系人', key: 'contactPerson', type: 'input' },
  337. { label: '客户名称', key: 'customerId', type: 'select', options: selectData.Customer },
  338. { label: '电话号码', key: 'phoneNumber', type: 'input' },
  339. { label: '邮箱', key: 'email', type: 'input' },
  340. { label: '负责人', key: 'responsibleId', type: 'select', options: selectData.Personnel },
  341. { label: '创建人', key: 'createId', type: 'select', options: selectData.Personnel },
  342. ]
  343. }
  344. onMounted(() => {
  345. getSystemField()
  346. getContactPerson()
  347. })
  348. </script>
  349. <style lang="scss" scoped></style>