index.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. <template>
  2. <el-tabs type="card" v-model="activeTab" style="height: 100%" @tab-click="handleClick">
  3. <el-tab-pane v-for="tab in tabs" :key="tab.key" :label="tab.label" :name="tab.key">
  4. <div class="sensitive-words flex">
  5. <TreeSelect class="mr20" ref="treeSelectdRef" @treeCheck="getTreeCheck"></TreeSelect>
  6. <div class="table-box">
  7. <pageSearch
  8. ref="searchTableRef"
  9. :searchConfig="activeTab === '1' ? searchConfig : searchNonIndustryConfig"
  10. />
  11. <pageContent
  12. ref="tableListRef"
  13. :total="total"
  14. v-loading="loading"
  15. :contentConfig="activeTab === '1' ? contentConfig : contentNonIndustryConfig"
  16. :pageList="tableData"
  17. >
  18. <!-- 短信接收人 -->
  19. <template #msgRecipient="scope">
  20. <template :index="index" v-for="(item, index) in bj_msg_recipient">
  21. <el-tag
  22. :index="index"
  23. v-if="item.value == scope.row.msgRecipient"
  24. :type="scope.row.msgRecipient == '1' ? 'success' : 'danger'"
  25. >{{ item.label }}</el-tag
  26. >
  27. </template>
  28. </template>
  29. <!-- 通讯录状态 -->
  30. <template #abStatus="scope">
  31. <template :index="index" v-for="(item, index) in bj_ab_status">
  32. <el-tag
  33. :index="index"
  34. v-if="item.value == scope.row.abStatus"
  35. :type="scope.row.abStatus == '1' ? 'success' : 'danger'"
  36. >{{ item.label }}</el-tag
  37. >
  38. </template>
  39. </template>
  40. <template #button>
  41. <el-button type="primary" @click="handleImportShow()">导入</el-button>
  42. <el-button type="primary" @click="onImportTemplate()">下载模版</el-button>
  43. <el-button type="primary" @click="onAdd()">新增</el-button>
  44. <el-button type="primary" @click="onExport()">导出</el-button>
  45. </template>
  46. <template #operate="scope">
  47. <el-button type="primary" link @click="handleCheck(scope.row.liaisonId)"> 查看 </el-button>
  48. <template v-if="scope.row.abStatus == '1'">
  49. <el-button type="primary" link @click="handleEdit(scope.row.liaisonId)"> 编辑 </el-button>
  50. <el-button type="danger" link @click="onDelete(scope.row)"> 删除 </el-button>
  51. </template>
  52. <template v-esle>
  53. <el-button type="primary" link @click="handleStatus(scope.row, '启用', '1')">
  54. 启用
  55. </el-button>
  56. </template>
  57. </template>
  58. </pageContent>
  59. </div>
  60. </div>
  61. </el-tab-pane>
  62. </el-tabs>
  63. <pageDetail :modalConfig="activeTab === '1' ? detailConfig : detailNonIndustryConfig" ref="modalRef">
  64. </pageDetail>
  65. <pageImport
  66. v-model:isVisible="importDialog.isvisible"
  67. :title="importDialog.title"
  68. @refresh-table="handleQuery()"
  69. />
  70. </template>
  71. <script setup lang="ts">
  72. import contentConfig from './config/content.config';
  73. import contentNonIndustryConfig from './config/content.nonIndustry.config';
  74. import pageContent from '@/components/components/pageContent.vue';
  75. import searchConfig from './config/search.config';
  76. import searchNonIndustryConfig from './config/search.nonIndustry.config';
  77. import pageSearch from '@/components/components/pageSearch.vue';
  78. import detailConfig from './config/detail.config';
  79. import detailNonIndustryConfig from './config/detail.nonIndustry.config';
  80. import pageDetail from './components/detail.vue';
  81. import pageImport from './components/import.vue';
  82. import useSystemStore from '@/store/main';
  83. import TreeSelect from './components/treeSelect.vue';
  84. import { type TabsPaneContext } from 'element-plus';
  85. import { outTypeList } from '@/libs/commonMeth';
  86. import { changeInventoryStatus } from '@/api/notificationInfoManage/contactsmanage';
  87. const bj_msg_recipient = outTypeList('bj_msg_recipient'); //短信接收人
  88. const bj_ab_status: any = outTypeList('bj_ab_status'); //通讯录状态
  89. // 使用pinia数据
  90. const systemStore = useSystemStore();
  91. const { pageDetailInfo, searchObj } = storeToRefs(systemStore);
  92. const total = ref(0);
  93. const pageSize = ref([10, 20, 30]);
  94. const tableData = ref([]);
  95. const tableListRef: any = ref<InstanceType<typeof pageContent>>();
  96. const tabs = reactive([
  97. {
  98. key: '1',
  99. label: '行业内联络员',
  100. total: 0,
  101. tableData: [],
  102. loading: false,
  103. showDetail: true,
  104. },
  105. {
  106. key: '2',
  107. label: '行业外联络员',
  108. total: 0,
  109. tableData: [],
  110. loading: false,
  111. showDetail: true,
  112. },
  113. ]);
  114. const activeTab = ref('1');
  115. const searchTableRef: any = ref<InstanceType<typeof pageSearch>>();
  116. // 操作弹框
  117. import usePageModal from '@/components/components/hooks/usePageDetails';
  118. const { modalRef, handleNewDataClick, handleEditDataClick, handleCheckDataClick, handlePageDetail } =
  119. usePageModal();
  120. const getTreeCheck = async data => {
  121. if (activeTab.value == '1') {
  122. searchConfig.pageListParams.belongsDeptIds = data.join();
  123. } else {
  124. searchNonIndustryConfig.pageListParams.belongsDeptIds = data.join();
  125. }
  126. searchTableRef.value[0].handleQueryClick();
  127. };
  128. const handleQuery = async () => {
  129. loading.value = true;
  130. setTimeout(() => {
  131. if (treeSelectdRef.value) {
  132. treeSelectdRef.value[0].handleReset(false);
  133. }
  134. if (searchTableRef.value) {
  135. searchTableRef.value[0].handleResetClick();
  136. }
  137. loading.value = false;
  138. }, 500);
  139. };
  140. const treeSelectdRef = ref<InstanceType<typeof TreeSelect>>();
  141. const loading = ref(false);
  142. const handleClick = async (tab: TabsPaneContext) => {
  143. loading.value = true;
  144. setTimeout(() => {
  145. if (treeSelectdRef.value) {
  146. treeSelectdRef.value[0].handleReset(false);
  147. }
  148. if (searchTableRef.value) {
  149. searchTableRef.value[0].handleResetClick();
  150. }
  151. loading.value = false;
  152. }, 500);
  153. };
  154. const importDialog = reactive({
  155. isvisible: false,
  156. title: '通报联络员数据导入',
  157. });
  158. function handleImportShow() {
  159. importDialog.isvisible = true;
  160. }
  161. const handleEdit = async (id: string) => {
  162. await handlePageDetail(id);
  163. await handleEditDataClick();
  164. };
  165. const handleCheck = async (id: string) => {
  166. await handlePageDetail(id);
  167. await handleCheckDataClick();
  168. };
  169. // 新增按钮
  170. const onAdd = () => {
  171. handleNewDataClick();
  172. };
  173. const onImportTemplate = () => {
  174. const link = document.createElement('a');
  175. link.href = `/assets/address-book.xlsx`;
  176. link.download = '违法信息通报通讯录人员导入模板.xlsx'; // 指定下载后的文件名
  177. link.style.display = 'none';
  178. document.body.appendChild(link);
  179. link.click();
  180. document.body.removeChild(link);
  181. };
  182. const onExport = () => {
  183. ElMessage.success('小编在努力开发中。。。');
  184. return;
  185. };
  186. // 删除按钮
  187. function onDelete(row: any) {
  188. ElMessageBox.confirm(`确定删除联络人“${row.contactName}”条目信息吗?`, '删除提示', {
  189. confirmButtonText: '确定',
  190. cancelButtonText: '取消',
  191. type: 'warning',
  192. })
  193. .then(() => {
  194. systemStore.deletePageDataAction(contentConfig.pageName, row.liaisonId, {
  195. industryType: activeTab.value,
  196. });
  197. })
  198. .catch(() => {
  199. ElMessage({
  200. type: 'info',
  201. message: '取消删除',
  202. });
  203. });
  204. }
  205. // 状态按钮
  206. function handleStatus(row: any, status: string, str: string) {
  207. ElMessageBox.confirm(`是否${str}联络人“${row.contactName}”条目信息吗?`, '状态提示', {
  208. confirmButtonText: '确定',
  209. cancelButtonText: '取消',
  210. type: 'warning',
  211. })
  212. .then(async () => {
  213. const postData: any = await changeInventoryStatus(row.liaisonId, status);
  214. if (postData.code === 200) {
  215. tableListRef.value.fetchPageListData({ industryType: activeTab.value });
  216. ElMessage.success('操作成功!');
  217. } else {
  218. ElMessage.error('操作失败!');
  219. }
  220. })
  221. .catch(() => {
  222. ElMessage({
  223. type: 'info',
  224. message: '取消操作',
  225. });
  226. });
  227. }
  228. const handleDownload = async () => {
  229. ElMessageBox.confirm(`确定要导出所选数据信息?`, '提示', {
  230. confirmButtonText: '确定',
  231. cancelButtonText: '取消',
  232. distinguishCancelAndClose: true,
  233. })
  234. .then(async () => {
  235. const isLoading = ElLoading.service({
  236. lock: true,
  237. text: 'Loading',
  238. background: 'rgba(0, 0, 0, 0.7)',
  239. });
  240. let data: any = {};
  241. // 获取表格数据
  242. // data = cfgSelection.value;
  243. try {
  244. // 创建 Blob 对象
  245. const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
  246. // 获取列名
  247. const headers = [
  248. { key: 'uuid', label: '目标设备码' },
  249. { key: 'client_ip', label: '目标设备IP' },
  250. { key: 'type', label: '适用平台' },
  251. { key: 'remark', label: '目标设备名称' },
  252. ];
  253. const headerRow = headers.map(header => header.label).join(',');
  254. // 构造 CSV 内容
  255. const csvContent = [
  256. headerRow,
  257. ...data.map((row: any) => headers.map(header => row[header.key]).join(',')),
  258. ].join('\n');
  259. // 构造文件名
  260. const filename = `${timestamp}.csv`; // 指定下载文件的名称;
  261. // 创建 Blob 对象
  262. const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8' });
  263. // 创建下载链接
  264. const url = URL.createObjectURL(blob);
  265. const a = document.createElement('a');
  266. a.href = url;
  267. a.download = filename;
  268. a.click();
  269. URL.revokeObjectURL(url); // 释放 URL 对象
  270. } finally {
  271. isLoading.close();
  272. }
  273. })
  274. .catch(() => {});
  275. };
  276. // 筛选-状态赋值 bj_notification_status
  277. async function searchItem() {
  278. searchConfig.formItems.forEach(item => {
  279. if (item.prop === 'msgRecipient') {
  280. item.options = bj_msg_recipient;
  281. }
  282. if (item.prop === 'abStatus') {
  283. item.options = bj_ab_status;
  284. }
  285. });
  286. searchNonIndustryConfig.formItems.forEach(item => {
  287. if (item.prop === 'abStatus') {
  288. item.options = bj_ab_status;
  289. }
  290. });
  291. }
  292. searchItem();
  293. </script>
  294. <style scoped lang="scss">
  295. .sensitive-words {
  296. margin: 20px;
  297. height: calc(100vh - 20vh);
  298. margin-top: 0;
  299. }
  300. .status {
  301. cursor: pointer;
  302. position: relative;
  303. .status-tip {
  304. position: absolute;
  305. top: 2px;
  306. left: 60px;
  307. }
  308. }
  309. .dialog-tip {
  310. text-align: center;
  311. }
  312. .table-box {
  313. width: 75%;
  314. display: flex;
  315. flex-direction: column;
  316. }
  317. :deep .el-tabs__item.is-active {
  318. color: #fff;
  319. background-color: #409eff;
  320. }
  321. :deep .el-tabs__header {
  322. padding-left: 20px;
  323. background-color: #fff;
  324. }
  325. </style>