index.vue 16 KB

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