index.vue 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. <script lang="ts" setup>
  2. import { onMounted, provide, reactive, ref, Ref } from 'vue';
  3. import { Search } from '@element-plus/icons-vue';
  4. import { TemplateType } from '../utils/enum';
  5. import { DelObj, GetList } from '/@/views/efTools/automation/api';
  6. import SelectBotton from '/@/components/select-button/index.vue';
  7. import TimerBidTmpl from '/@/views/components/auto/auto-templates/timer-bid.vue';
  8. import TimerBudgetTmpl from '/@/views/components/auto/auto-templates/timer-budget.vue';
  9. import SwitchCampaignTmpl from '/@/views/components/auto/auto-templates/switch-campaign.vue';
  10. import TargetRuleTmpl from '/@/views/components/auto/auto-templates/target-rule.vue';
  11. import SearchTermTmpl from '/@/views/components/auto/auto-templates/search-term.vue';
  12. import NegKeywordTmpl from '/@/views/components/auto/auto-templates/neg-keyword.vue';
  13. import AdActivityDialog from './components/adActivityDialog.vue';
  14. import { AddObj, UpdateObj } from './api';
  15. import AutomatedRuleTips from '/@/views/efTools/automation/components/automatedRuleTips.vue';
  16. //自动化规则提示
  17. const autoInfo = ref(false);
  18. //关联广告活动弹窗
  19. const isDialogVisible = ref(false);
  20. const templateId = ref('');
  21. const activeModel = ref('');
  22. provide('isDialogVisible', isDialogVisible);
  23. //查询
  24. const templateList = ref('');
  25. const templateType = ref('');
  26. //创建,编辑
  27. const CreateTemplateOptions = ref(TemplateType.filter(item => item.value !== ''));
  28. const mode = ref('');
  29. const showDrawer = ref(false);
  30. const formData: Ref<AutoTemplate> = ref({
  31. name: '',
  32. rule: {
  33. type: 0,
  34. campaignType: '',
  35. campaignAd: [],
  36. action: {},
  37. activeModel: '',
  38. setTime: '',
  39. weekdays: [],
  40. conditions: [],
  41. },
  42. });
  43. const dyComponents = {
  44. 1: TimerBidTmpl,
  45. 2: TimerBudgetTmpl,
  46. 3: SwitchCampaignTmpl,
  47. 4: TargetRuleTmpl,
  48. 5: SearchTermTmpl,
  49. 6: NegKeywordTmpl,
  50. };
  51. function refreshTable() {
  52. showDrawer.value = false;
  53. getList();
  54. }
  55. const showDialog = (row: any) => {
  56. templateId.value = row.id;
  57. activeModel.value = row.rule.activeModel;
  58. isDialogVisible.value = true;
  59. };
  60. function handleClick() {
  61. autoInfo.value = true;
  62. }
  63. function createTmpl(val: number) {
  64. mode.value = 'add';
  65. delete formData.value.id;
  66. formData.value.name = '';
  67. formData.value.rule = {
  68. type: val,
  69. campaignType: '',
  70. campaignAd: [],
  71. action: {},
  72. activeModel: '',
  73. setTime: '',
  74. weekdays: [],
  75. conditions: [],
  76. };
  77. showDrawer.value = true;
  78. }
  79. function editTmpl(row: any) {
  80. mode.value = 'edit';
  81. formData.value.id = row.id;
  82. formData.value.name = row.name;
  83. formData.value.rule = row.rule;
  84. showDrawer.value = true;
  85. }
  86. async function deleteTmpl(row: any) {
  87. await DelObj(row.id);
  88. await getList();
  89. }
  90. async function submitFormData() {
  91. if (mode.value === 'add') {
  92. await AddObj(formData.value);
  93. } else if (mode.value === 'edit') {
  94. await UpdateObj(formData.value);
  95. }
  96. refreshTable();
  97. }
  98. //表格配置
  99. const gridOptions = reactive({
  100. //border: 'inner',
  101. height: 820,
  102. align: null,
  103. loading: false,
  104. rowConfig: {
  105. isHover: true,
  106. height: 45
  107. },
  108. columnConfig: {
  109. resizable: true,
  110. },
  111. pagerConfig: {
  112. enabled: true,
  113. total: 20,
  114. currentPage: 1,
  115. pageSize: 20,
  116. pageSizes: [10, 20, 30],
  117. },
  118. columns: [
  119. { field: 'id', title: 'ID', width: 140 },
  120. { field: 'name', title: '模板名称' },
  121. {
  122. field: 'rule.type',
  123. title: '模板类型',
  124. formatter: ({ cellValue }) => getTemplateTypeLabel(cellValue),
  125. slots: { default: 'type' }
  126. },
  127. { field: 'campaignNumber', title: '广告活动数量' },
  128. { field: 'creator_username', title: '创建人' },
  129. //{ field: 'createTime', title: '创建时间' },
  130. { field: 'modifier_username', title: '更新人' },
  131. //{ field: 'updateTime', title: '更新时间' },
  132. { title: '操作', width: 120, slots: { default: 'operate' } },
  133. ],
  134. toolbarConfig: {
  135. slots: {
  136. buttons: 'toolbar_buttons',
  137. },
  138. },
  139. data: [],
  140. });
  141. const gridEvents = {
  142. pageChange({ currentPage, pageSize }) {
  143. if (gridOptions.pagerConfig) {
  144. gridOptions.pagerConfig.currentPage = currentPage;
  145. gridOptions.pagerConfig.pageSize = pageSize;
  146. getList();
  147. }
  148. },
  149. };
  150. function handleTypeChange() {
  151. localStorage.setItem('templateType', JSON.stringify(templateType.value));
  152. getList();
  153. }
  154. function handleTemplateListChange() {
  155. localStorage.setItem('templateList', JSON.stringify(templateList.value));
  156. getList();
  157. }
  158. async function getList() {
  159. const savedTemplateType = localStorage.getItem('templateType');
  160. if (savedTemplateType) {
  161. templateType.value = JSON.parse(savedTemplateType);
  162. }
  163. const savedTemplateList = localStorage.getItem('templateList');
  164. if (savedTemplateList) {
  165. templateList.value = JSON.parse(savedTemplateList);
  166. }
  167. try {
  168. gridOptions.loading = true;
  169. const response = await GetList({
  170. page: gridOptions.pagerConfig.currentPage,
  171. limit: gridOptions.pagerConfig.pageSize,
  172. type: templateType.value,
  173. name: templateList.value,
  174. });
  175. gridOptions.data = response.data.map(item => ({
  176. ...item,
  177. rule: {
  178. ...item.rule,
  179. typeLabelWithColor: getTemplateTypeLabel(item.rule.type),
  180. },
  181. }));
  182. gridOptions.pagerConfig.total = response.total;
  183. } catch (error) {
  184. console.error('Error fetching task data:', error);
  185. } finally {
  186. gridOptions.loading = false;
  187. }
  188. }
  189. function getTemplateTypeLabel(type: number) {
  190. const template = TemplateType.find(t => t.value === type);
  191. if (template) {
  192. return { label: template.label, type: type };
  193. }
  194. return { label: '', type: '' };
  195. }
  196. const cellStyle = () => {
  197. return {
  198. fontSize: '13px',
  199. //fontWeight: '500',
  200. };
  201. };
  202. const headerCellStyle = () => {
  203. return {
  204. fontSize: '14px',
  205. fontWeight: '500',
  206. color: '#2d2d2d',
  207. };
  208. };
  209. onMounted(() => {
  210. getList();
  211. });
  212. </script>
  213. <template>
  214. <div class="flex" style="justify-content: space-between">
  215. <div class="mx-3 mt-3" style="display: flex; gap: 14px;">
  216. <el-input v-model="templateList"
  217. :prefix-icon="Search"
  218. clearable
  219. placeholder="模板名称"
  220. style="width: 240px"
  221. @change="handleTemplateListChange"
  222. />
  223. <el-select v-model="templateType" placeholder="所有类型" style="width: 240px" value-key="value"
  224. @change="handleTypeChange">
  225. <el-option
  226. v-for="item in TemplateType"
  227. :key="item.value"
  228. :label="item.label"
  229. :value="item.value"
  230. />
  231. </el-select>
  232. </div>
  233. <div class="mx-3 mt-3" style="display: flex; gap: 14px;">
  234. <el-button link style="color: #2b7ed9;font-size: 12px" @click="handleClick">
  235. <el-icon>
  236. <question-filled />
  237. </el-icon>
  238. 如何使用自动化规则?
  239. </el-button>
  240. </div>
  241. </div>
  242. <el-card class="mx-3 my-3">
  243. <vxe-grid :cell-style="cellStyle" :header-cell-style="headerCellStyle" show-overflow v-bind="gridOptions"
  244. v-on="gridEvents">
  245. <template #toolbar_buttons>
  246. <SelectBotton :options="CreateTemplateOptions" btn-title="新建模板" @click="createTmpl"></SelectBotton>
  247. </template>
  248. <template #operate="{ row }">
  249. <el-button icon="Edit" style="color: #0b52a7" type="text" @click="editTmpl(row)"></el-button>
  250. <el-button icon="SetUp" style="color: #0b52a7" type="text" @click="showDialog(row)"></el-button>
  251. <el-button icon="Delete" style="color: #0b52a7" type="text" @click="deleteTmpl(row)"></el-button>
  252. </template>
  253. <template #type="{row}">
  254. <!--<el-tag :type="getTagType(row.rule.typeLabelWithColor.type)">-->
  255. {{ row.rule.typeLabelWithColor.label }}
  256. <!--</el-tag>-->
  257. </template>
  258. </vxe-grid>
  259. </el-card>
  260. <el-drawer v-model="showDrawer" :close-on-click-modal="false" :destroy-on-close="true"
  261. :title="mode === 'add' ? '新建模板' : '编辑模板'"
  262. size="70%">
  263. <div style="padding: 0 15px">
  264. <component
  265. :is="dyComponents[formData.rule.type]"
  266. :data="formData"
  267. :mode="mode"
  268. :submitFormData="submitFormData"
  269. @refresh="refreshTable"></component>
  270. </div>
  271. </el-drawer>
  272. <AdActivityDialog v-model="isDialogVisible" :activeModel="activeModel" :templateId="templateId" @confirm="handleConfirm"/>
  273. <AutomatedRuleTips v-model="autoInfo"></AutomatedRuleTips>
  274. </template>
  275. <style>
  276. .custom-dialog .el-dialog__header {
  277. height: 60px;
  278. line-height: 60px;
  279. padding: 0 24px;
  280. background-color: #fff;
  281. border-bottom: 1px solid #e5e6eb;
  282. border-radius: 10px 10px 0 0;
  283. }
  284. </style>