adActivityDialog.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. <script lang="ts" setup>
  2. /**
  3. * @Name: adActivityDialog.vue
  4. * @Description:广告关联活动弹窗
  5. * @Author: xinyan
  6. */
  7. import { computed, onMounted, reactive, ref, toRefs, watch } from 'vue';
  8. import { getAdGroupList, getRelationCampaign, updateAdCampaign } from '/@/views/efTools/automation/api';
  9. import { storeToRefs } from 'pinia';
  10. import { useShopInfo } from '/@/stores/shopInfo';
  11. import { ElMessage } from 'element-plus';
  12. import TargetRuleDialog from '/@/views/efTools/automation/components/targetRuleDialog.vue';
  13. import { DocumentAdd } from '@element-plus/icons-vue';
  14. const props = defineProps({
  15. templateId: {
  16. type: [String, Number],
  17. required: true,
  18. },
  19. activeModel: {
  20. type: String,
  21. },
  22. modelValue: {
  23. type: Boolean,
  24. required: true,
  25. },
  26. });
  27. const emits = defineEmits([ 'confirmSuccess']);
  28. const shopInfo = useShopInfo();
  29. const { profile } = storeToRefs(shopInfo);
  30. const { templateId } = toRefs(props);
  31. const { activeModel } = toRefs(props);
  32. // const dialogVisible = ref(false);
  33. const dialogVisible = defineModel({ default: false });
  34. const targetRuleDialogVisible = ref(false);
  35. // 定向规则
  36. //const adGroupId = ref('')
  37. //const campaignId = ref('')
  38. const selectedTargetedRow = ref(null);
  39. const targetLength = ref(0);
  40. let selectedGroups = [];
  41. // 筛选条件
  42. const searchAdCampaign = ref('');
  43. const selectedCampaignType = ref('sp');
  44. const selectedAdGroup = ref('');
  45. const selectedStatus = ref('');
  46. const campaignType = [
  47. { value: 'sb', label: 'SB' },
  48. { value: 'sp', label: 'SP' },
  49. { value: 'sd', label: 'SD' },
  50. ];
  51. const adGroups = ref([]);
  52. const campaignStatus = [
  53. { value: 0, label: '未存档' },
  54. { value: 'ENABLED', label: '已启用' },
  55. { value: 'PAUSED', label: '已暂停' },
  56. ];
  57. // 表格
  58. const currentPage = ref(1);
  59. const pageSize = ref(25);
  60. const total = ref(0);
  61. const loading = ref(false);
  62. const xGridOne = ref(null);
  63. const xGridTwo = ref(null);
  64. let selectedAds = ref([]);
  65. const selectedColumns = computed(() => [
  66. {
  67. field: 'campaignName',
  68. title: '广告活动',
  69. slots: { default: 'campaignName_default' },
  70. treeNode: activeModel.value == 'specified' || activeModel.value == 'adGroup'
  71. },
  72. { title: '操作', width: 100, align: 'center', slots: { header: 'header_operation', default: 'default_operation' } }
  73. ]);
  74. const treeProps = computed(() => {
  75. // activeModel.value = 'specified';
  76. if (activeModel.value === 'adGroup' || activeModel.value === 'specified') {
  77. return {
  78. rowField: 'campaignId',
  79. childrenField: 'campaignGroupInfo', // 子节点字段
  80. expandAll: true,
  81. };
  82. }
  83. return {};
  84. });
  85. const gridOptions = reactive({
  86. border: 'inner',
  87. height: 500,
  88. rowConfig: {
  89. isHover: true,
  90. keyField: 'campaignId',
  91. },
  92. treeConfig: treeProps,
  93. checkboxConfig: {
  94. labelField: 'name',
  95. reserve: true,
  96. checkStrictly: false,
  97. checkMethod: ({ row }) => {
  98. if (activeModel.value === 'specified') {
  99. // 如果是 specified 模式,只有已选择的行可以被取消选中
  100. return row.isSelected;
  101. }
  102. return true; // 其他模式下都可以选中
  103. }
  104. },
  105. columns: computed(() => [
  106. {
  107. field: 'campaignName',
  108. title: '广告活动',
  109. slots: { default: 'campaignName_default' },
  110. treeNode: activeModel.value == 'specified' || activeModel.value == 'adGroup'
  111. },
  112. {
  113. type: 'checkbox',
  114. width: 55,
  115. fixed: 'right',
  116. slots: activeModel.value == 'specified' ? { header: 'checkbox_header', checkbox: 'checkbox_cell' } : ''
  117. },
  118. ]),
  119. data: []
  120. });
  121. console.log('gridOptions', gridOptions);
  122. console.log('activeModel', activeModel.value);
  123. function handleCurrentChange(newPage) {
  124. currentPage.value = newPage;
  125. loading.value = true;
  126. fetchAdCampaign();
  127. }
  128. // 处理分页器每页显示条目数变化
  129. function handleSizeChange(newSize) {
  130. pageSize.value = newSize;
  131. currentPage.value = 1;
  132. fetchAdCampaign();
  133. }
  134. function handleAdCampaignChange() {
  135. localStorage.setItem('searchAdCampaign', JSON.stringify(searchAdCampaign.value));
  136. fetchAdCampaign();
  137. }
  138. async function fetchAdCampaign() {
  139. const savedAdCampaign = localStorage.getItem('searchAdCampaign');
  140. if (savedAdCampaign) {
  141. searchAdCampaign.value = JSON.parse(savedAdCampaign);
  142. }
  143. try {
  144. loading.value = true;
  145. const cachedSelectedAds = [...selectedAds.value];
  146. if (profile.value.profile_id && templateId.value){
  147. const resp = await getRelationCampaign({
  148. profileId: profile.value.profile_id,
  149. templateId: templateId.value,
  150. campaignName: searchAdCampaign.value,
  151. portfolioId: selectedAdGroup.value,
  152. campaignStatus: selectedStatus.value,
  153. campaignType: selectedCampaignType.value,
  154. page: currentPage.value,
  155. limit: pageSize.value,
  156. });
  157. gridOptions.data = resp.data;
  158. total.value = resp.total;
  159. currentPage.value = resp.page;
  160. }
  161. } catch (error) {
  162. ElMessage.error('请求广告活动数据失败');
  163. } finally {
  164. loading.value = false;
  165. }
  166. }
  167. // 处理表格复选框选择变化(是否为树形结构)
  168. // const handleGridChange = (event) => {
  169. // if (activeModel.value == 'specified' || activeModel.value == 'adGroup') {
  170. // handleSelectionChange(event);
  171. // } else {
  172. // handelSelect(event);
  173. // }
  174. // };
  175. function handleGridChange({ records, row, checked }) {
  176. if (activeModel.value === 'specified') {
  177. if (row) {
  178. if (!checked) {
  179. row.isSelected = false;
  180. updateSelectedAds();
  181. }
  182. } else {
  183. // 全选/取消全选
  184. records.forEach(record => {
  185. if (record.isSelected) {
  186. record.isSelected = checked;
  187. }
  188. });
  189. updateSelectedAds();
  190. }
  191. } else if (activeModel.value === 'adGroup') {
  192. handleSelectionChange({ records });
  193. } else {
  194. handelSelect({ records });
  195. }
  196. }
  197. function toggleCheckboxEvent(row) {
  198. if (activeModel.value === 'specified') {
  199. if (row.isSelected) {
  200. // 只有已选择的行可以被取消选中
  201. xGridOne.value.setCheckboxRow(row, false);
  202. handleGridChange({ records: [row], row, checked: false });
  203. }
  204. } else {
  205. // 其他模式下正常切换复选框状态
  206. xGridOne.value.toggleCheckboxRow(row);
  207. }
  208. }
  209. // 非树形结构的表格选择变化
  210. function handelSelect({ records }) {
  211. selectedAds.value = [
  212. ...selectedAds.value.filter(ad => ad.page !== currentPage.value),
  213. ...records.map(ad => ({ ...ad, page: currentPage.value }))
  214. ];
  215. }
  216. function updateSelectedAds() {
  217. selectedAds.value = gridOptions.data
  218. .filter(ad => ad.campaignGroupInfo && ad.campaignGroupInfo.some(group => group.isSelected))
  219. .map(ad => ({
  220. ...ad,
  221. campaignGroupInfo: ad.campaignGroupInfo.filter(group => group.isSelected),
  222. page: currentPage.value
  223. }));
  224. console.log('selectedAds.value', selectedAds.value);
  225. }
  226. // 树形结构的表格选择变化
  227. function handleSelectionChange({ records }) {
  228. selectedGroups = selectedGroups.filter(group => {
  229. return records.some(record => record.adGroupId === group.adGroupId);
  230. });
  231. let updatedRecords = [];
  232. const parentCampaignMap = new Map();
  233. records.forEach(record => {
  234. if (record.adGroupId) {
  235. // 这是一个广告组(子节点)
  236. const parentCampaign = gridOptions.data.find(campaign =>
  237. campaign.campaignGroupInfo.some(group => group.adGroupId === record.adGroupId)
  238. );
  239. if (parentCampaign) {
  240. // 如果父节点已经存在,则将子节点添加到父节点的 campaignGroupInfo 中
  241. if (parentCampaignMap.has(parentCampaign.campaignId)) {
  242. parentCampaignMap.get(parentCampaign.campaignId).campaignGroupInfo.push(record);
  243. } else {
  244. // 如果父节点不存在,则创建一个新的父节点对象
  245. parentCampaignMap.set(parentCampaign.campaignId, {
  246. campaignType: parentCampaign.campaignType,
  247. campaignId: parentCampaign.campaignId,
  248. campaignName: parentCampaign.campaignName,
  249. campaignGroupInfo: [record]
  250. });
  251. }
  252. }
  253. }
  254. });
  255. // 将所有父节点对象添加到 updatedRecords
  256. updatedRecords = Array.from(parentCampaignMap.values());
  257. // 更新选中的广告
  258. selectedAds.value = [
  259. ...updatedRecords.map(ad => ({ ...ad, page: currentPage.value })),
  260. ];
  261. }
  262. // 选择定向按钮
  263. function handleSelectTarget(row) {
  264. // 获取父节点数据
  265. const parent = gridOptions.data.find(campaign =>
  266. campaign.campaignGroupInfo.some(group => group.adGroupId === row.adGroupId)
  267. );
  268. selectedTargetedRow.value = {
  269. campaignType: parent.campaignType,
  270. campaignId: parent.campaignId,
  271. adGroupId: row.adGroupId,
  272. isSelected: row.isSelected || false,
  273. keywordInfo: row.keywordInfo || [],
  274. campaignTargetInfo: row.campaignTargetInfo || [],
  275. };
  276. targetRuleDialogVisible.value = true;
  277. }
  278. // 选择定向弹窗确认按钮
  279. function handleConfirm({ campaignInfo, targetType }) {
  280. if (!selectedTargetedRow.value) return;
  281. // 找到父级广告活动
  282. const parentCampaign = gridOptions.data.find(campaign =>
  283. campaign.campaignGroupInfo.some(group => group.adGroupId === selectedTargetedRow.value.adGroupId)
  284. );
  285. if (parentCampaign) {
  286. // 更新子节点(广告组)的信息
  287. const group = parentCampaign.campaignGroupInfo.find(group => group.adGroupId === selectedTargetedRow.value.adGroupId);
  288. if (group) {
  289. if (targetType === 'keyword') {
  290. group.keywordInfo = campaignInfo;
  291. } else if (targetType === 'target') {
  292. group.campaignTargetInfo = campaignInfo;
  293. }
  294. group.isSelected = true; // 更新子节点的选择状态
  295. group.targetLength = (group.keywordInfo?.length || 0) + (group.campaignTargetInfo?.length || 0);
  296. }
  297. // 勾选表格1中的对应行,只有在定向大于0时进行勾选
  298. if (group && group.targetLength > 0) {
  299. if (xGridOne.value) {
  300. xGridOne.value.toggleCheckboxRow(group, true); // 手动勾选复选框
  301. }
  302. }
  303. }
  304. // 更新选中的广告
  305. updateSelectedAds();
  306. }
  307. // 删除选中的广告
  308. const removeSelectedAd = async (row) => {
  309. const $grid = xGridTwo.value;
  310. if ($grid) {
  311. if (row.adGroupId) {
  312. // 删除子节点(广告组)
  313. selectedAds.value = selectedAds.value.map(ad => {
  314. if (ad.campaignGroupInfo) {
  315. return {
  316. ...ad,
  317. campaignGroupInfo: ad.campaignGroupInfo.filter(group => group.adGroupId !== row.adGroupId)
  318. };
  319. }
  320. return ad;
  321. }).filter(ad => ad.campaignGroupInfo && ad.campaignGroupInfo.length > 0);
  322. } else {
  323. // 删除父节点(广告活动)
  324. selectedAds.value = selectedAds.value.filter(ad => ad.campaignId !== row.campaignId);
  325. }
  326. await $grid.remove(row);
  327. }
  328. if (xGridOne.value) {
  329. await xGridOne.value.toggleCheckboxRow(row);
  330. }
  331. };
  332. function removeAllSelectedAds() {
  333. selectedAds.value = [];
  334. const $grid = xGridOne.value;
  335. if ($grid) {
  336. $grid.clearCheckboxRow();
  337. }
  338. }
  339. function cancel() {
  340. dialogVisible.value = false;
  341. }
  342. //TODO: 确认按钮-adGroupInfo
  343. async function confirm() {
  344. const campaignItems = selectedAds.value.map(ad => ({
  345. campaignId: ad.campaignId,
  346. campaignType: ad.campaignType
  347. }));
  348. let campaignKeywordInfo = [];
  349. let campaignTargetInfo = [];
  350. selectedAds.value.forEach(campaign => {
  351. campaign.campaignGroupInfo.forEach(group => {
  352. if (group.keywordInfo && group.keywordInfo.length > 0) {
  353. campaignKeywordInfo = campaignKeywordInfo.concat(
  354. group.keywordInfo.map(keyword => ({
  355. keywordId: keyword.keywordId,
  356. adGroup_id: group.adGroupId,
  357. bid: keyword.bid
  358. }))
  359. );
  360. }
  361. if (group.campaignTargetInfo && group.campaignTargetInfo.length > 0) {
  362. campaignTargetInfo = campaignTargetInfo.concat(
  363. group.campaignTargetInfo.map(target => ({
  364. targetId: target.targetId,
  365. adGroup_id: group.adGroupId,
  366. bid: target.bid
  367. }))
  368. );
  369. }
  370. });
  371. });
  372. const requestData = {
  373. profileId: profile.value.profile_id,
  374. templateId: templateId.value,
  375. campaignItems: campaignItems,
  376. adGroupInfo: [],
  377. campaignTargetInfo,
  378. campaignKeywordInfo
  379. };
  380. console.log('requestData', requestData);
  381. try {
  382. const response = await updateAdCampaign(requestData);
  383. if (response.code === 2000) {
  384. dialogVisible.value = false;
  385. emits('confirmSuccess');
  386. ElMessage({ message: '创建成功', type: 'success', });
  387. }
  388. } catch (error) {
  389. console.error('API error:', error);
  390. ElMessage({ message: '创建失败', type: 'error', });
  391. }
  392. }
  393. // 获取广告组下拉框
  394. async function fetchAdGroupList() {
  395. try {
  396. const resp = await getAdGroupList({
  397. profileId: profile.value.profile_id,
  398. });
  399. adGroups.value = resp.data.map((item: any) => {
  400. return {
  401. label: item.name,
  402. value: item.portfolioId
  403. };
  404. });
  405. } catch (error) {
  406. ElMessage.error('请求失败');
  407. }
  408. }
  409. const headerCellStyle = (args) => {
  410. if (args.rowIndex === 0) {
  411. return {
  412. backgroundColor: 'rgba(245, 245, 245, 0.9)',
  413. fontWeight: '500',
  414. };
  415. }
  416. };
  417. const cellStyle = () => {
  418. return {
  419. fontSize: '13px',
  420. //fontWeight: '500',
  421. };
  422. };
  423. //监控筛选条件变化
  424. watch(selectedCampaignType, () => {
  425. fetchAdCampaign();
  426. });
  427. watch(selectedAdGroup, (newVal) => {
  428. if (newVal) {
  429. selectedAdGroup.value = newVal;
  430. fetchAdCampaign();
  431. }
  432. });
  433. watch(selectedStatus, () => {
  434. fetchAdCampaign();
  435. });
  436. // watch(templateId, () => {
  437. // fetchAdCampaign();
  438. // fetchAdGroupList();
  439. // });
  440. // watch(() => props.modelValue, (newValue) => {
  441. // dialogVisible.value = newValue;
  442. // });
  443. // watch(dialogVisible, (newValue) => {
  444. // // emits('update:modelValue', newValue);
  445. // });
  446. onMounted(() => {
  447. fetchAdGroupList();
  448. fetchAdCampaign();
  449. });
  450. </script>
  451. <template>
  452. <el-dialog
  453. v-model="dialogVisible"
  454. style="border-radius: 10px;"
  455. title="关联广告活动"
  456. width="1158px"
  457. >
  458. <div class="container">
  459. <div class="container-left">
  460. <el-input v-model="searchAdCampaign" clearable placeholder="请输入广告活动" style="width: 100%;"
  461. @change="handleAdCampaignChange()"></el-input>
  462. <div class="custom-inline">
  463. <el-select v-model="selectedCampaignType" placeholder="选择广告类型">
  464. <el-option v-for="item in campaignType"
  465. :key="item.value"
  466. :label="item.label"
  467. :value="item.value"
  468. ></el-option>
  469. </el-select>
  470. <el-select v-model="selectedAdGroup" clearable placeholder="广告组合" style="margin-bottom: 10px;">
  471. <el-option
  472. v-for="item in adGroups"
  473. :key="item.value"
  474. :label="item.label"
  475. :value="item.value"
  476. ></el-option>
  477. </el-select>
  478. <el-select v-model="selectedStatus" placeholder="状态" style="margin-bottom: 10px;">
  479. <el-option
  480. v-for="item in campaignStatus"
  481. :key="item.value"
  482. :label="item.label"
  483. :value="item.value"
  484. ></el-option>
  485. </el-select>
  486. </div>
  487. <vxe-grid ref="xGridOne" :cell-style="cellStyle" :header-cell-style="headerCellStyle" v-bind="gridOptions"
  488. @checkbox-change="handleGridChange" @checkbox-all="handleGridChange">
  489. <template #campaignName_default="{ row }">
  490. <el-tag
  491. v-if="row.campaignType"
  492. :color="row.campaignType === 'sb' ? '#0163d2' : (row.campaignType === 'sp' ? '#ff7424' : '#365672')"
  493. class="campaign-type"
  494. disable-transitions
  495. round>
  496. {{ row.campaignType }}
  497. </el-tag>
  498. <span> {{ row.campaignName }}</span>
  499. <span class="flex-container">
  500. {{ row.adGroupName }}
  501. <el-button
  502. v-if="row.adGroupName && activeModel==='specified'&&!row.isSelected"
  503. class="btn-link"
  504. link
  505. @click="handleSelectTarget(row)">
  506. 选择定向
  507. </el-button>
  508. <span v-else-if="row.adGroupName && activeModel==='specified'">已选择定向</span>
  509. </span>
  510. </template>
  511. <template #checkbox_header="{ checked, indeterminate }">
  512. <span class="custom-checkbox" @click.stop="toggleAllCheckboxEvent">
  513. <i v-if="indeterminate" class="vxe-icon-square-minus-fill" style="color: #0d84ff"></i>
  514. <i v-else-if="checked" class="vxe-icon-square-checked-fill" style="color: #0d84ff"></i>
  515. <i v-else class="vxe-icon-checkbox-unchecked" style="color: #0d84ff"></i>
  516. </span>
  517. </template>
  518. <template #checkbox_cell="{ row, checked, indeterminate }">
  519. <span class="custom-checkbox" @click.stop="toggleCheckboxEvent(row)">
  520. <i v-if="indeterminate" class="vxe-icon-square-minus-fill" style="color: #0d84ff"></i>
  521. <i v-else-if="checked" class="vxe-icon-square-checked-fill" style="color: #0d84ff"></i>
  522. <el-tooltip v-else
  523. class="box-item"
  524. content="请选择定向"
  525. effect="dark"
  526. placement="top"
  527. >
  528. <i class="vxe-icon-checkbox-unchecked" style="color: #0d84ff"></i>
  529. </el-tooltip>
  530. </span>
  531. </template>
  532. </vxe-grid>
  533. <div class="pagination-container mt-4">
  534. <el-pagination
  535. v-model:current-page="currentPage"
  536. :page-size="pageSize"
  537. :page-sizes="[10, 25, 50,100,200]"
  538. :total="total"
  539. background
  540. layout="total,sizes,prev, next, jumper"
  541. small
  542. @size-change="handleSizeChange"
  543. @current-change="handleCurrentChange"
  544. />
  545. </div>
  546. </div>
  547. <div class="container-right">
  548. <h3>已选择({{ selectedAds.length }})</h3>
  549. <vxe-grid ref="xGridTwo"
  550. :cell-style="cellStyle"
  551. :columns="selectedColumns"
  552. :data="selectedAds"
  553. :header-cell-style="headerCellStyle"
  554. :tree-config="treeProps"
  555. border="inner"
  556. height="484">
  557. <template #campaignName_default="{ row }">
  558. <template v-if="!row.adGroupId">
  559. <!-- 父节点(广告活动) -->
  560. <el-tag
  561. v-if="row.campaignType"
  562. :color="row.campaignType === 'sb' ? '#0163d2' : (row.campaignType === 'sp' ? '#ff7424' : '#365672')"
  563. class="campaign-type"
  564. disable-transitions
  565. round>
  566. {{ row.campaignType }}
  567. </el-tag>
  568. <span>{{ row.campaignName }}</span>
  569. </template>
  570. <template v-else>
  571. <!-- 子节点(广告组) -->
  572. <div class="flex-container">
  573. <span>{{ row.adGroupName }}</span>
  574. <el-button
  575. v-if="row.isSelected"
  576. :icon="DocumentAdd"
  577. class="btn-link"
  578. link
  579. @click="handleSelectTarget(row)">
  580. 共{{ row.targetLength }}个定向规则
  581. </el-button>
  582. </div>
  583. </template>
  584. </template>
  585. <template #header_operation>
  586. <el-button link size="default" style="color: #2077d7" @click="removeAllSelectedAds">删除全部</el-button>
  587. </template>
  588. <template #default_operation="{row}">
  589. <el-button type="text" @click="removeSelectedAd(row)">
  590. <CircleClose style="width:16px;color:#4b5765" />
  591. </el-button>
  592. </template>
  593. </vxe-grid>
  594. </div>
  595. </div>
  596. <template #footer>
  597. <div class="dialog-footer">
  598. <el-button @click="cancel">取消</el-button>
  599. <el-button type="primary" @click="confirm">确定</el-button>
  600. </div>
  601. </template>
  602. </el-dialog>
  603. <!--选择定向弹窗-->
  604. <TargetRuleDialog v-if="activeModel === 'specified'"
  605. v-model="targetRuleDialogVisible"
  606. :selectedTargetedRow="selectedTargetedRow"
  607. @confirm:targetRule="handleConfirm"
  608. ></TargetRuleDialog>
  609. </template>
  610. <style scoped>
  611. .pagination-container {
  612. display: flex;
  613. flex-direction: row-reverse;
  614. }
  615. .custom-inline {
  616. display: flex;
  617. justify-content: space-around;
  618. margin: 12px 0;
  619. gap: 4px;
  620. }
  621. .campaign-type {
  622. /* width: 35px; */
  623. /* text-align: center; */
  624. /* height: 22px; */
  625. /* font-size: 13px; */
  626. /* font-weight: 400; */
  627. color: #fff;
  628. border-color: #fff;
  629. /* line-height: 21px; */
  630. border-radius: 12px;
  631. margin-right: 4px;
  632. }
  633. .container {
  634. width: 100%;
  635. height: 100%;
  636. border: 1px solid #d6dbe2;
  637. border-radius: 4px;
  638. display: flex;
  639. overflow: hidden;
  640. align-content: center;
  641. flex-wrap: nowrap;
  642. flex-direction: row;
  643. /* padding: 10px; */
  644. }
  645. .container-left {
  646. width: 50%;
  647. border-right: 1px solid #d6dbe2;
  648. padding: 15px
  649. }
  650. .container-right {
  651. flex: 1;
  652. padding: 15px
  653. }
  654. .btn-link {
  655. font-size: 13px;
  656. color: #0085ff;
  657. /* ling-heigt: 23px; */
  658. }
  659. .flex-container {
  660. display: flex;
  661. justify-content: space-between;
  662. }
  663. </style>