account-config.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. <template>
  2. <div class="account-config-content">
  3. <div class="control-con-header">
  4. <a-form
  5. class="grid-form"
  6. layout="inline"
  7. :form="form"
  8. hide-required-mark
  9. @submit="handleQueryList"
  10. >
  11. <a-row class="grid-form-options">
  12. <a-form-item
  13. class="grid-form-item"
  14. label="账户"
  15. :colon="false"
  16. >
  17. <acount-search class="acount-search-class" :appId.sync="acountId" :multiple="false" request="1,3"></acount-search>
  18. </a-form-item>
  19. <a-form-item label="状态">
  20. <a-select v-model="searchStatus" style="width: 100px">
  21. <a-select-option :value="0">开启</a-select-option>
  22. <a-select-option :value="1">关闭</a-select-option>
  23. </a-select>
  24. </a-form-item>
  25. <a-form-item class="form-handle-btn">
  26. <a-button type="default" class="reset-class" @click="handleResetList">重置</a-button>
  27. <a-button type="primary" html-type="submit">查询</a-button>
  28. </a-form-item>
  29. </a-row>
  30. </a-form>
  31. <a-button type="primary" class="upload-person" @click="handleAddAccountConfig">新建账户配置</a-button>
  32. </div>
  33. <div class="control-con-table">
  34. <a-table
  35. ref="table"
  36. size="middle"
  37. bordered
  38. :loading="controlLoading"
  39. :columns="columns"
  40. :dataSource="dataSource"
  41. :pagination="false"
  42. >
  43. <span slot="customTitle">
  44. 花费(元)
  45. <a-tooltip placement="top">
  46. <template slot="title">
  47. <span>当日花费</span>
  48. </template>
  49. <a-icon type="question-circle"/>
  50. </a-tooltip>
  51. </span>
  52. <span slot="acountRelax" slot-scope="text, record">
  53. <a-switch :checked="text === 0" @change="handleSwitchChang($event, record)"/>
  54. </span>
  55. <span solt="accountBudget" slot-scope="text, record">
  56. {{ record.accountBudgetMode === '1' ? '不限' : text }}
  57. </span>
  58. <span slot="action" slot-scope="text, record">
  59. <a @click="handleEdit(record)">编辑</a>
  60. <a-divider type="vertical"/>
  61. <a @click="handleListDelete(record)">删除</a>
  62. <a-divider type="vertical"/>
  63. <a @click="handleUpdateMod(record)">修改出价</a>
  64. <a-divider type="vertical"/>
  65. <a @click="handleUpdateBudget(record)">修改预算</a>
  66. </span>
  67. </a-table>
  68. <a-pagination
  69. class="pagin-table-class"
  70. :total="totalAll"
  71. :show-total="total => `共 ${totalAll} 条`"
  72. size="small"
  73. show-size-changer
  74. show-quick-jumper
  75. @change="onShowSizeChange"
  76. @showSizeChange="onShowSizeChange"
  77. />
  78. </div>
  79. <a-modal
  80. title="修改预算"
  81. v-if="budgetVisible"
  82. :visible="budgetVisible"
  83. dialog-class="mode-modal-class"
  84. @ok="handleBudgetSure"
  85. @cancel="handleBudgetCancel"
  86. >
  87. <div>
  88. <a-form-model
  89. ref="budgetForm"
  90. :model="budgetForm"
  91. :rules="budgetRules"
  92. :label-col="labelCol"
  93. :wrapper-col="wrapperCol"
  94. >
  95. <a-form-model-item label="预算方式">
  96. <a-radio-group
  97. v-model="budgetForm.budgetType"
  98. button-style="solid"
  99. @change="handleAccountMode"
  100. >
  101. <a-radio-button value="1">不限预算</a-radio-button>
  102. <a-radio-button value="2">指定预算</a-radio-button>
  103. </a-radio-group>
  104. </a-form-model-item>
  105. <a-form-model-item v-if="budgetForm.budgetType === '2'" label="账户日预算" prop="budget">
  106. <a-input-number
  107. v-model="budgetForm.budget"
  108. :min="1000"
  109. :max="9999999.99"
  110. :step="0.01"
  111. @blur="handleAccountBudget"
  112. /> 元
  113. </a-form-model-item>
  114. <!-- <div v-if="adBudgetShowTitle" style="width: 500px;color: #f00;margin-left: 140px;">单次修改预算幅度, 不能低于100.0元</div> -->
  115. </a-form-model>
  116. </div>
  117. </a-modal>
  118. <a-modal
  119. title="修改出价"
  120. v-if="modeVisible"
  121. :visible="modeVisible"
  122. dialog-class="mode-modal-class"
  123. @ok="handleModeSure"
  124. @cancel="handleModeCancel"
  125. >
  126. <div>
  127. <a-form-model
  128. ref="ruleForm"
  129. :model="configForm"
  130. :rules="rules"
  131. :label-col="labelCol"
  132. :wrapper-col="wrapperCol"
  133. >
  134. <a-form-model-item v-if="updateModTxt.adBidCreateType === 'FIX'" label="目标转化出价" prop="adCpaBid">
  135. <a-input-number
  136. class="common-input"
  137. v-model="configForm.adCpaBid"
  138. :min="0.1"
  139. :step="0.01"
  140. placeholder="请输入"
  141. />
  142. </a-form-model-item>
  143. <div v-if="updateModTxt.adBidCreateType === 'RAND'">
  144. <a-form-model-item label="目标转化出价范围"
  145. class="dp-link-start" prop="adMinBid">
  146. <a-input-number
  147. class="common-input"
  148. v-model="configForm.adMinBid"
  149. :min="0.1"
  150. :max="10000"
  151. :step="0.01"
  152. placeholder="请输入最小值"
  153. />
  154. </a-form-model-item>
  155. <span class="icon-span">~</span>
  156. <a-form-model-item class="dp-link-end" prop="adMaxBid">
  157. <a-input-number
  158. class="common-input"
  159. v-model="configForm.adMaxBid"
  160. :min="0.1"
  161. :max="10000"
  162. :step="0.01"
  163. placeholder="请输入最大值"
  164. />
  165. </a-form-model-item>
  166. </div>
  167. <div v-if="updateModTxt.adBidCreateType === 'STEP'">
  168. <a-form-model-item label="目标转化出价范围" class="dp-link-start" prop="adMinBid">
  169. <a-input-number
  170. class="common-input"
  171. v-model="configForm.adMinBid"
  172. :min="0.1"
  173. :max="10000"
  174. :step="0.01"
  175. placeholder="请输入最小值"
  176. />
  177. </a-form-model-item>
  178. <span class="icon-span">~</span>
  179. <a-form-model-item class="dp-link-end" prop="adMaxBid">
  180. <a-input-number
  181. class="common-input"
  182. v-model="configForm.adMaxBid"
  183. :min="0.1"
  184. :max="10000"
  185. :step="0.01"
  186. placeholder="请输入最大值"
  187. />
  188. </a-form-model-item>
  189. <a-form-model-item label="浮动间隔" prop="adStepBid">
  190. <a-input-number
  191. class="common-input"
  192. :min="0"
  193. :step="0.01"
  194. v-model="configForm.adStepBid"
  195. placeholder="请输入浮动间隔"
  196. />
  197. </a-form-model-item>
  198. </div>
  199. </a-form-model>
  200. </div>
  201. </a-modal>
  202. </div>
  203. </template>
  204. <script>
  205. import AcountSearch from '@/views/modules/Statistics/components/Treeselect.vue';
  206. import {getAction, putAction, deleteAction} from '@/api/manage';
  207. import {mapGetters} from 'vuex';
  208. import {urlAcount} from './account-config-server.js';
  209. export default {
  210. name: 'account-config',
  211. components: {
  212. AcountSearch
  213. },
  214. data() {
  215. let adMinBidValidator = (rule, value, callback) => {
  216. const finallyResult = Number(this.configForm.adMaxBid);
  217. if (finallyResult !== '' && value && Number(value) <= finallyResult) {
  218. callback();
  219. }
  220. else {
  221. callback('最低出价不能高于最高出价');
  222. }
  223. };
  224. let adCpaBidValidator = (rule, value, callback) => {
  225. if (Number(this.updateModTxt.adBudget) < Number(value)) {
  226. callback('出价不能大于预算');
  227. }
  228. else {
  229. callback();
  230. }
  231. };
  232. let adMaxBidValidator = (rule, value, callback) => {
  233. const finallyResult = Number(this.configForm.adMinBid);
  234. if (finallyResult && value && Number(value) <= finallyResult) {
  235. callback('最高出价不能低于最低出价');
  236. }
  237. else if (Number(this.updateModTxt.adBudget) < Number(value)) {
  238. callback('出价不能大于预算');
  239. }
  240. else if (Number(this.configForm.adMaxBid) > Number(this.configForm.adMinBid) + Number(this.configForm.adStepBid)) {
  241. this.$refs['ruleForm'].clearValidate(['adStepBid']);
  242. callback();
  243. }
  244. else {
  245. this.$refs['ruleForm'].clearValidate(['adMinBid']);
  246. callback();
  247. }
  248. };
  249. let floatingIntervalValidator = (rule, value, callback) => {
  250. const finallyResult = Number(this.configForm.adMinBid) + Number(value);
  251. if (finallyResult < Number(this.configForm.adMaxBid)) {
  252. callback();
  253. }
  254. else {
  255. callback('最低出价+浮动间隔<最高出价');
  256. }
  257. };
  258. let budgetValidator = (rule, value, callback) => {
  259. const changeBudget = this.updateModTxt.accountBudget;
  260. if (Number(value) > Number(changeBudget) && Number(value) < (Number(changeBudget) + 100)) {
  261. callback('单次修改预算幅度, 不能低于100.0元');
  262. }
  263. else if (Number(value) < Number(changeBudget) && Number(value) > (Number(changeBudget) - 100)) {
  264. callback('单次修改预算幅度, 不能低于100.0元');
  265. }
  266. else {
  267. callback();
  268. }
  269. };
  270. return {
  271. searchStatus: 0,
  272. controlLoading: true,
  273. adBudgetShowTitle: false,
  274. budgetVisible: false,
  275. budgetForm: {
  276. budgetType: '1',
  277. budget: 0
  278. },
  279. budgetRules: {
  280. budget: [
  281. {required: true, message: '请输入', trigger: 'blur'},
  282. {validator: budgetValidator, trigger: 'blur'}
  283. ]
  284. },
  285. labelCol: {span: 4},
  286. wrapperCol: {span: 14},
  287. configForm: {
  288. adMinBid: undefined,
  289. adMaxBid: undefined,
  290. adStepBid: undefined,
  291. adCpaBid: undefined
  292. },
  293. rules: {
  294. adCpaBid: [
  295. {required: true, message: '请输入', trigger: 'blur'},
  296. {validator: adCpaBidValidator, trigger: 'blur'}
  297. ],
  298. adStepBid: [
  299. {required: true, message: '请输入', trigger: 'blur'},
  300. {validator: floatingIntervalValidator, trigger: 'blur'}
  301. ],
  302. adMinBid: [
  303. {required: true, message: '请输入最低出价', trigger: 'blur'},
  304. {validator: adMinBidValidator, trigger: 'blur'}
  305. ],
  306. adMaxBid: [
  307. {required: true, message: '请输入最高出价', trigger: 'blur'},
  308. {validator: adMaxBidValidator, trigger: 'blur'}
  309. ]
  310. },
  311. modeVisible: false,
  312. updateModTxt: {},
  313. modContent: '',
  314. budgetContent: '',
  315. acountId: undefined, // 搜索的账户ID
  316. totalAll: 0,
  317. tablePag: {
  318. page: 1,
  319. size: 10
  320. },
  321. dataSource: [],
  322. columns: [
  323. {
  324. title: '开关',
  325. align: 'center',
  326. dataIndex: 'status',
  327. scopedSlots: {customRender: 'acountRelax'}
  328. },
  329. {
  330. title: '广告账户名称',
  331. align: 'center',
  332. dataIndex: 'accountId_dictText'
  333. },
  334. {
  335. title: '账户ID',
  336. align: 'center',
  337. dataIndex: 'accountId'
  338. },
  339. {
  340. title: '创建时间',
  341. dataIndex: 'createTime',
  342. align: 'center'
  343. },
  344. {
  345. title: '账户余额',
  346. dataIndex: 'validBalance',
  347. align: 'center'
  348. },
  349. {
  350. title: '账户日预算(元)',
  351. dataIndex: 'accountBudget',
  352. width: 180,
  353. align: 'center'
  354. },
  355. {
  356. title: '出价(元)',
  357. dataIndex: 'adCpaBidStr',
  358. align: 'center'
  359. },
  360. {
  361. align: 'center',
  362. dataIndex: 'cost',
  363. width: 150,
  364. slots: {title: 'customTitle'}
  365. },
  366. {
  367. title: '操作',
  368. dataIndex: 'action',
  369. align: 'center',
  370. width: '20%',
  371. scopedSlots: {customRender: 'action'}
  372. }
  373. ]
  374. };
  375. },
  376. created() {
  377. this.form = this.$form.createForm(this);
  378. },
  379. mounted() {
  380. this.handleInitTable();
  381. },
  382. methods: {
  383. ...mapGetters(['nickname', 'avatar', 'userInfo']),
  384. handleAccountMode(e) {
  385. this.budgetForm.budget = 1000;
  386. this.adBudgetShowTitle = false;
  387. },
  388. handleAccountBudget(e) {
  389. const adBudgetInput = e.target.value;
  390. this.budgetForm.budget = Number(Number(adBudgetInput).toFixed(2));
  391. },
  392. handleModeSure() {
  393. let paramsData = new FormData();
  394. if (this.updateModTxt.adBidCreateType === 'FIX') {
  395. paramsData.append('type', 1);
  396. paramsData.append('id', this.updateModTxt.id);
  397. paramsData.append('adCpaBid', this.configForm.adCpaBid);
  398. }
  399. else if (this.updateModTxt.adBidCreateType === 'RAND') {
  400. paramsData.append('type', 1);
  401. paramsData.append('id', this.updateModTxt.id);
  402. paramsData.append('adMinBid', this.configForm.adMinBid);
  403. paramsData.append('adMaxBid', this.configForm.adMaxBid);
  404. }
  405. else if (this.updateModTxt.adBidCreateType === 'STEP') {
  406. paramsData.append('type', 1);
  407. paramsData.append('id', this.updateModTxt.id);
  408. paramsData.append('adMinBid', this.configForm.adMinBid);
  409. paramsData.append('adMaxBid', this.configForm.adMaxBid);
  410. paramsData.append('adStepBid', this.configForm.adStepBid);
  411. }
  412. this.$refs.ruleForm.validate(valid => {
  413. if (valid) {
  414. this.controlLoading = true;
  415. this.handlePopoverChange(paramsData);
  416. }
  417. else {
  418. console.log('error submit!!');
  419. return false;
  420. }
  421. });
  422. },
  423. handleModeCancel() {
  424. this.adMinBid = undefined;
  425. this.adMaxBid = undefined;
  426. this.adStepBid = undefined;
  427. this.adCpaBid = undefined;
  428. this.modeVisible = false;
  429. },
  430. handleUpdateMod(record) {
  431. this.updateModTxt = record;
  432. this.configForm.adCpaBid = record.adCpaBid;
  433. this.configForm.adMinBid = record.adMinBid;
  434. this.configForm.adMaxBid = record.adMaxBid;
  435. this.configForm.adStepBid = record.adStepBid;
  436. this.modeVisible = true;
  437. },
  438. handleUpdateBudget(record) {
  439. this.updateModTxt = record;
  440. this.budgetForm.budgetType = record.accountBudgetMode;
  441. this.budgetForm.budget = record.accountBudget;
  442. this.budgetVisible = true;
  443. },
  444. handleBudgetSure() {
  445. let paramsData = new FormData();
  446. paramsData.append('accountId', this.updateModTxt.accountId);
  447. paramsData.append('adId', this.updateModTxt.adId);
  448. paramsData.append('type', 2);
  449. paramsData.append('budget', this.budgetForm.budget);
  450. paramsData.append('budgetType', this.budgetForm.budgetType);
  451. paramsData.append('id', this.updateModTxt.id);
  452. paramsData.append('cost', this.updateModTxt.cost);
  453. if (this.adBudgetShowTitle) {
  454. return;
  455. }
  456. this.$refs.budgetForm.validate(valid => {
  457. if (valid) {
  458. this.controlLoading = true;
  459. this.handlePopoverChange(paramsData);
  460. }
  461. else {
  462. console.log('error submit!!');
  463. return false;
  464. }
  465. });
  466. },
  467. handleBudgetCancel() {
  468. this.budgetVisible = false;
  469. this.budgetForm.budgetType = '1';
  470. },
  471. handlePopoverChange(data) {
  472. putAction(urlAcount + '/bytedance-api/advertiser/aiBytedanceAdvertiserStrategy/updStaOrCpaOrBudgetById', data).then(result => {
  473. if (result.code === 0) {
  474. this.$message.success(result.message);
  475. this.adMinBid = undefined;
  476. this.adMaxBid = undefined;
  477. this.adStepBid = undefined;
  478. this.adCpaBid = undefined;
  479. this.modeVisible = false;
  480. this.budgetVisible = false;
  481. this.budgetForm.budgetType = '1';
  482. this.handleInitTable();
  483. }
  484. else {
  485. this.$message.error(result.message);
  486. }
  487. }).catch(error => {
  488. console.log(error, 'eeee');
  489. });
  490. },
  491. handleResetList() {
  492. this.acountId = '';
  493. this.searchStatus = 0;
  494. this.controlLoading = true;
  495. this.handleInitTable();
  496. },
  497. handleInitTable() {
  498. const paramsData = {
  499. accountId: this.acountId,
  500. status: this.searchStatus,
  501. loginUserId: this.userInfo().id,
  502. pageNo: this.tablePag.page,
  503. pageSize: this.tablePag.size
  504. };
  505. getAction(urlAcount + '/bytedance-api/advertiser/aiBytedanceAdvertiserStrategy/list', paramsData).then(result => {
  506. if (result.code === 0) {
  507. result.result.records.forEach(item => {
  508. if (item.accountBudgetMode === '1') {
  509. item.accountBudget = '不限';
  510. }
  511. });
  512. this.controlLoading = false;
  513. this.dataSource = result.result.records;
  514. this.totalAll = result.result.total;
  515. }
  516. else {
  517. this.$message.error(result.message);
  518. }
  519. }).catch(error => {
  520. console.log(error, 'eeee');
  521. });
  522. },
  523. handleListDelete(data) {
  524. let that = this;
  525. this.$confirm({
  526. title: '删除提示',
  527. content: '是否删除该条数据',
  528. onOk() {
  529. that.controlLoading = true;
  530. deleteAction(urlAcount + '/bytedance-api/advertiser/aiBytedanceAdvertiserStrategy/delete', {id: data.id}).then(result => {
  531. if (result.code === 0) {
  532. that.handleInitTable();
  533. that.$message.success('删除成功');
  534. }
  535. else {
  536. that.$message.error(result.message);
  537. }
  538. }).catch(error => {
  539. console.log(error, 'eeee');
  540. });
  541. }
  542. });
  543. },
  544. handleQueryList(event) {
  545. event.preventDefault();
  546. this.controlLoading = true;
  547. this.handleInitTable();
  548. },
  549. onShowSizeChange(current, pageSize) {
  550. this.tablePag = {
  551. page: current,
  552. size: pageSize
  553. };
  554. this.controlLoading = true;
  555. this.handleInitTable();
  556. },
  557. handleSwitchChang(checked, data) {
  558. this.controlLoading = true;
  559. const paramsData = {
  560. id: data.id,
  561. state: checked ? 0 : 1,
  562. accountId: data.accountId
  563. };
  564. const forDate = new FormData();
  565. forDate.append('id', paramsData.id);
  566. forDate.append('state', paramsData.state);
  567. forDate.append('accountId', paramsData.accountId);
  568. putAction(urlAcount + '/bytedance-api/advertiser/aiBytedanceAdvertiserStrategy/updStaById', forDate).then(result => {
  569. if (result.code === 0) {
  570. this.$message.success(result.message);
  571. this.handleInitTable();
  572. }
  573. else {
  574. this.$message.error(result.message);
  575. }
  576. }).catch(error => {
  577. console.log(error, 'eeee');
  578. });
  579. },
  580. handleEdit(data) {
  581. // TODO 切换路由时候,及时删除上一次相同路由
  582. let params = {
  583. accountModal: 'edit',
  584. id: data.id
  585. };
  586. localStorage.setItem('queryList', JSON.stringify(params));
  587. this.$router.push('/account-config/components/configuration-modal');
  588. },
  589. handleAddAccountConfig() {
  590. let params = {
  591. accountModal: 'add'
  592. };
  593. localStorage.setItem('queryList', JSON.stringify(params));
  594. this.$router.push('/account-config/components/configuration-modal');
  595. }
  596. }
  597. };
  598. </script>
  599. <style lang="less" scoped>
  600. @import "account-config";
  601. </style>