adActivityDialog.vue 21 KB

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