index.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <template>
  2. <div class="layout-padding">
  3. <div class="layout-padding-auto layout-padding-view">
  4. <el-row shadow="hover" class="ml10">
  5. <el-form :inline="true" :model="state.queryForm" @keyup.enter="query" ref="queryRef">
  6. <!-- <el-form-item :label="'规则名称'" prop="ruleName">
  7. <el-input :placeholder="'请输入规则名称'" v-model="state.queryForm.ruleName" />
  8. </el-form-item>
  9. <el-form-item :label="'触发信息'" prop="triggerCondition">
  10. <el-input :placeholder="'请输入触发信息'" v-model="state.queryForm.triggerCondition" />
  11. </el-form-item> -->
  12. <el-form-item :label="'推送时间'" prop="createTime">
  13. <el-date-picker :disabled-date="disabledDate" :end-placeholder="'结束日期'" :start-placeholder="'开始日期'"
  14. format="YYYY-MM-DD HH:mm:ss" range-separator="至" type="datetimerange" v-model="state.queryForm.createTime" />
  15. </el-form-item>
  16. <el-form-item>
  17. <el-button @click="query" class="ml10" icon="search" type="primary">
  18. {{ t('common.queryBtn') }}
  19. </el-button>
  20. <el-button @click="resetQuery" icon="Refresh">{{ t('common.resetBtn') }}</el-button>
  21. </el-form-item>
  22. </el-form>
  23. </el-row>
  24. <el-table ref="tableRef" :data="state.dataList" row-key="id" style="width: 100%" v-loading="state.loading" border
  25. :cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle?.headerCellStyle">
  26. <el-table-column :formatter="statusFormatter" :label="'推送IP'" prop="pushIP" min-width="200"
  27. show-overflow-tooltip></el-table-column>
  28. <el-table-column :formatter="statusFormatter" :label="'推送域名'" prop="pushDomain" min-width="200"
  29. show-overflow-tooltip></el-table-column>
  30. <el-table-column :formatter="statusFormatter" :label="'推送内容'" prop="pushContent" min-width="300"
  31. show-overflow-tooltip>
  32. <template #default="{ row }">
  33. <el-image v-if="row.pushType" :src="row.pushContent" style="width: 100px; height: 100px;" />
  34. <div v-else>{{ row.pushContent }}</div>
  35. </template>
  36. </el-table-column>
  37. <el-table-column :formatter="statusFormatter" :label="'推送方式'" prop="pushType" min-width="200"
  38. show-overflow-tooltip>
  39. <template #default="{ row }">
  40. {{pushMode.filter(item => item.value == row.pushAction)[0]?.label}}
  41. </template>
  42. </el-table-column>
  43. <el-table-column :formatter="statusFormatter" :label="'推送频率'" prop="pushFrequency" min-width="120"
  44. show-overflow-tooltip>
  45. </el-table-column>
  46. <el-table-column :formatter="statusFormatter" :label="'推送时间'" prop="createTime" min-width="200"
  47. show-overflow-tooltip></el-table-column>
  48. <el-table-column :formatter="statusFormatter" :label="'延时推送'" prop="delayPush" min-width="200"
  49. show-overflow-tooltip></el-table-column>
  50. <el-table-column :formatter="statusFormatter" :label="'推送状态'" prop="pushStatus" min-width="120"
  51. show-overflow-tooltip>
  52. <template #default="{ row }">
  53. {{ row.pushStatus ? '已推送' : '未推送' }}
  54. </template>
  55. </el-table-column>
  56. <el-table-column :formatter="statusFormatter" :label="'推送详情'" prop="pushDetail" min-width="250">
  57. <template #default="{ row }">
  58. <div class="trigger-info" @click="showTriggerInfo(row)">
  59. {{ row.pushDetail }}
  60. </div>
  61. </template>
  62. </el-table-column>
  63. </el-table>
  64. <pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination" />
  65. </div>
  66. <dataInfoModal ref="richContentDialogRef"></dataInfoModal>
  67. </div>
  68. </template>
  69. <script lang="ts" name="marketingApps" setup>
  70. import { getPushPage } from '/@/api/marketing/apps';
  71. import { BasicTableProps, useTable } from '/@/hooks/table';
  72. import { useI18n } from 'vue-i18n';
  73. import { ref, reactive, onMounted, defineAsyncComponent } from 'vue'
  74. const dataInfoModal = defineAsyncComponent(() => import('/@/views/marketing/data/dataInfoModal.vue'));
  75. import { ElImage } from 'element-plus';
  76. import lockScreen from '/@/assets/lockScreen.png';
  77. import { fetchItemList } from '/@/api/admin/dict';
  78. const { t } = useI18n();
  79. const getDataListWithProcess = (params: any): Promise<any> => {
  80. return new Promise((resolve, reject) => {
  81. getPushPage(params).then((res: any) => {
  82. console.log(res, 'res');
  83. try {
  84. if (res.data && res.data.records && res.data.records.length > 0) {
  85. res.data.records = res.data.records.map((item: any) => {
  86. let parsedData: any = null;
  87. try {
  88. if (item.triggerCondition) {
  89. parsedData = JSON.parse(item.triggerCondition);
  90. }
  91. } catch (error) {
  92. console.warn('解析触发器条件失败:', item.triggerCondition, error);
  93. }
  94. return {
  95. ...item,
  96. _keywords: parsedData?.keywords || [],
  97. _ip: parsedData?.ip || '',
  98. _domain: parsedData?.domain || ''
  99. };
  100. });
  101. }
  102. resolve(res);
  103. } catch (error: any) {
  104. console.error('数据处理失败:', error);
  105. reject(error);
  106. }
  107. }).catch((error: any) => {
  108. reject(error);
  109. });
  110. });
  111. };
  112. // 定义变量内容
  113. const tableRef = ref();
  114. const queryRef = ref();
  115. const state: BasicTableProps = reactive<BasicTableProps>({
  116. pageList: getDataListWithProcess,
  117. createdIsNeed: false,
  118. queryForm: {
  119. ruleName: '',
  120. triggerCondition: '',
  121. },
  122. pagination: {
  123. current: 1,
  124. size: 10,
  125. total: 0,
  126. pageSizes: [5, 10, 20, 50, 100]
  127. },
  128. });
  129. const pushMode = ref<any>([]);
  130. const disabledDate = (time: Date) => {
  131. return time.getTime() > Date.now();
  132. }
  133. interface SourceData {
  134. ruleName: string;
  135. triggerCondition: string;
  136. triggerTime: string;
  137. pushStatus: string;
  138. pushContent: string;
  139. pushFrequency: string;
  140. pushTime: string;
  141. }
  142. const richContentDialogRef = ref();
  143. const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state);
  144. // 搜索事件
  145. const query = (refresh: boolean = false) => {
  146. state.dataList = [];
  147. getDataList(refresh);
  148. };
  149. // 清空搜索条件
  150. const resetQuery = () => {
  151. queryRef.value.resetFields();
  152. state.dataList = [];
  153. getDataList();
  154. };
  155. const statusFormatter = (row: any, column: any, cellValue: any, index: any) => {
  156. return cellValue || '--';
  157. }
  158. const showTriggerInfo = (row: any) => {
  159. // 信息详情弹窗
  160. richContentDialogRef.value.openDialog(
  161. row.pushDetail,
  162. {
  163. createTime: row.createTime,
  164. triggerKeyword: row._keywords
  165. }
  166. )
  167. }
  168. const getFetchItemList = async () => {
  169. const res = await fetchItemList({
  170. dictType: 'pushMode',
  171. });
  172. pushMode.value = res.data.records.map((item: any) => ({
  173. label: item.description,
  174. value: item.value
  175. }));
  176. console.log(pushMode, 'pushMode');
  177. }
  178. onMounted(() => {
  179. getFetchItemList();
  180. query();
  181. });
  182. </script>
  183. <style scoped lang="scss">
  184. :deep(.el-link__inner) {
  185. display: inline-block;
  186. width: 100%;
  187. justify-content: start;
  188. }
  189. :deep(.el-link.is-underline:hover:after) {
  190. display: none;
  191. }
  192. .table-tabs {
  193. margin-bottom: 10px;
  194. }
  195. .trigger-info {
  196. overflow: hidden;
  197. text-align: center;
  198. width: 100%;
  199. text-overflow: ellipsis;
  200. overflow: hidden;
  201. white-space: nowrap;
  202. color: #409eff;
  203. cursor: pointer;
  204. }
  205. .header-wrapper {
  206. display: inline-flex;
  207. align-items: center;
  208. }
  209. .header-icon {
  210. margin-left: 5px;
  211. color: #999;
  212. font-size: 14px;
  213. cursor: help;
  214. &:hover {
  215. color: #409eff;
  216. }
  217. }
  218. </style>