猎羽广告

modifyDailyBudget.vue 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. <template>
  2. <Dialog :dialogVisible="dialogShow" @confirm="confirmEvent" @close="closeEvent" :cancleText="pageInfo.cancleText"
  3. :closeOnModal="false" :hasBtn="pageInfo.hasBtn" :destroyOnCloseFlag="true" width="800px" dialog-title="批量修改日预算">
  4. <template v-slot:content>
  5. <div class="dialogBox" v-if="pageInfo.schedule == 1">
  6. <div class="batch-title">已选{{ pageInfo.multipleSelection.length }}个可操作媒体账户</div>
  7. <div class="flex bMar15">
  8. <span class="form-block-item-title">修改规则</span>
  9. <el-radio-group v-model="pageInfo.modifyRuleValue" size="default">
  10. <template v-for="item in modifyRule">
  11. <el-radio-button :label="item.value">{{ item.label }}</el-radio-button>
  12. </template>
  13. </el-radio-group>
  14. </div>
  15. <div class="flex_start bMar15">
  16. <span class="form-block-item-title">预算</span>
  17. <div class="flex_start">
  18. <el-select v-model="pageInfo.selectValue" style="width: 115px" @change="selectChange">
  19. <el-option :label="item.label" :value="item.value" v-for="item in selectList" />
  20. </el-select>
  21. <div>
  22. <el-input v-model="pageInfo.inputValue" :class="pageInfo.mainInputError ? 'inputError' : ''"
  23. v-if="pageInfo.selectValue != 6" style="width:260px" @input="onChangeInput('mainInput')">
  24. <template #suffix>
  25. <span>{{ selectList.filter((v) => v.value == pageInfo.selectValue)[0]?.unit }}</span>
  26. </template>
  27. </el-input>
  28. <div class="error" v-if="pageInfo.mainInputError">{{ pageInfo.mainInputErrHint }}</div>
  29. </div>
  30. <el-tooltip placement="top" content="选中广告主账户预算包含不限,不可以设置此内容"
  31. :disabled="!(pageInfo.selectValue == 1 || pageInfo.selectValue == 6 ? false : pageInfo.isNoLimit)"
  32. effect="light">
  33. <span>
  34. <el-button type="primary" class="lMar10"
  35. :disabled="pageInfo.selectValue == 1 || pageInfo.selectValue == 6 ? false : pageInfo.isNoLimit"
  36. @click="application">应 用</el-button>
  37. </span>
  38. </el-tooltip>
  39. </div>
  40. </div>
  41. <!-- 更改预算 table -->
  42. <el-table :data="pageInfo.multipleSelection" :header-cell-style="tableHeaderStyle" border style="width: 100%">
  43. <el-table-column prop="advertiser_id" label="广告主账户" width="180" />
  44. <el-table-column label="日预算" width="180" align="right">
  45. <template #default="scope">
  46. {{ scope.row.daily_budget || '不限' }}
  47. </template>
  48. </el-table-column>
  49. <el-table-column label="分别修改日预算">
  50. <template #default="scope">
  51. <el-input v-model="scope.row.modifyDailyBudget"
  52. :class="scope.row.inputError != '' && scope.row.inputError ? 'inputError' : ''" placeholder="请输入日预算"
  53. style="width:260px" @input="onChangeInput('tableInput', scope.$index)"></el-input>
  54. <div class="error" v-if="scope.row.inputError">{{ scope.row.inputError }}</div>
  55. </template>
  56. </el-table-column>
  57. </el-table>
  58. </div>
  59. <!-- 确定修改操作 -->
  60. <div class="dialogBox" v-if="pageInfo.schedule == 2 || pageInfo.schedule == 3">
  61. <div class="flex bMar15" v-if="pageInfo.schedule == 2">
  62. <el-icon color="#ff9b48">
  63. <WarningFilled />
  64. </el-icon>
  65. <p class="f13 c-555 lMar5">确定要执行以下修改操作吗?此操作不可逆!</p>
  66. </div>
  67. <div class="flex bMar15" v-if="pageInfo.schedule == 3">
  68. <el-icon color="#00b697">
  69. <CircleCheckFilled />
  70. </el-icon>
  71. <p class="f13 c-555 lMar5">修改完成,共{{ pageInfo.successLength }}项修改成功</p>
  72. </div>
  73. <el-table :data="pageInfo.multipleSelection" :header-cell-style="tableHeaderStyle" border style="width: 100%">
  74. <el-table-column prop="advertiser_id" label="广告主账户" />
  75. <el-table-column label="日预算">
  76. <template #default="scope">
  77. <div class="preview-modified">
  78. <div class="budget">{{ scope.row.daily_budget || '不限' }}</div>
  79. <div class="modified-info">
  80. <div class="status">
  81. <div class="text">{{ scope.row.modifyDailyBudget && scope.row.modifyDailyBudget != '' ? '修改为' :
  82. '(未修改)' }}</div>
  83. </div>
  84. <div class="modified-budget">{{ scope.row.modifyDailyBudget }}</div>
  85. </div>
  86. </div>
  87. </template>
  88. </el-table-column>
  89. <el-table-column label="修改结果" v-if="pageInfo.schedule == 3" width="180px">
  90. <template #default="scope">
  91. <div class="flex" v-if="scope.row.state != 2 && (scope.row.modifyDailyBudget && scope.row.modifyDailyBudget != '')">
  92. <el-icon color="#00b697" class="rMar5">
  93. <CircleCheckFilled />
  94. </el-icon>
  95. <span>修改成功</span>
  96. </div>
  97. <div class="flex" v-if="scope.row.state == 2">
  98. <el-icon color="#fb1919" class="rMar5">
  99. <CircleCloseFilled />
  100. </el-icon>
  101. <span>失败:{{ scope.row.err_msg }}</span>
  102. </div>
  103. </template>
  104. </el-table-column>
  105. </el-table>
  106. </div>
  107. </template>
  108. </Dialog>
  109. </template>
  110. <script setup lang="ts">
  111. import Dialog from '@/components/capsulationMoudle/_dialog.vue'
  112. import { nextTick, onMounted, reactive, ref } from "vue";
  113. import { ElLoading, ElMessage } from "element-plus";
  114. import _ from 'lodash';
  115. import http from '@/http/http'
  116. import { getDay } from '@/common/common';
  117. const emit = defineEmits<{
  118. (event: "confirm", val: string): void;
  119. }>();
  120. const props = withDefaults(defineProps<{
  121. title?: string,
  122. }>(), {
  123. title: '提示',
  124. })
  125. const modifyRule = [
  126. { label: '立即生效', value: 1 },
  127. { label: '次日0时生效', value: 2 }
  128. ]
  129. const selectList = [
  130. { label: '修改为', value: 1, unit: '元' },
  131. { label: '提高', value: 2, unit: '元' },
  132. { label: '降低', value: 3, unit: '元' },
  133. { label: '按 % 提高', value: 4, unit: '%' },
  134. { label: '按 % 降低', value: 5, unit: '%' },
  135. { label: '不限', value: 6, unit: '' },
  136. ]
  137. const pageInfo: any = reactive({})
  138. const nameRef = ref<{ value: any }>()
  139. const confirmEvent = async () => {
  140. if (pageInfo.schedule == 1) {
  141. let isErrItem = false;
  142. let isEmpty = false
  143. pageInfo.multipleSelection.forEach((item) => {
  144. if (item.inputError && item.inputError != '') {
  145. isErrItem = true
  146. }
  147. if (item.modifyDailyBudget && item.modifyDailyBudget != '') {
  148. isEmpty = true;
  149. }
  150. })
  151. if (isErrItem) {
  152. ElMessage.error('存在不合法日预算,请重新填写不合法的日预算')
  153. return
  154. }
  155. if (!isEmpty) {
  156. ElMessage.error(' 请修改至少一个广告主账户的日预算!')
  157. return
  158. }
  159. pageInfo.schedule = 2;
  160. pageInfo.cancleText = '返回编辑'
  161. return;
  162. }
  163. if (pageInfo.schedule == 2) {
  164. const loading = ElLoading.service({
  165. lock: true,
  166. text: '修改操作进行中...',
  167. background: 'rgba(255, 255, 255, 0.7)',
  168. })
  169. let str_val: any[] = []
  170. pageInfo.multipleSelection.forEach((item) => {
  171. if (item.modifyDailyBudget && item.modifyDailyBudget != '') {
  172. str_val.push({
  173. "account_id": item.advertiser_id,
  174. "daily_budget": item.modifyDailyBudget == '不限' ? 0 : item.modifyDailyBudget
  175. })
  176. }
  177. })
  178. let params = {
  179. 'str_val': JSON.stringify(str_val)
  180. }
  181. if (pageInfo.modifyRuleValue == 1) {
  182. params['start_time'] = getDay(0, true).now
  183. }
  184. if (pageInfo.modifyRuleValue == 2) {
  185. params['start_time'] = getDay(1, false) + ' 00:00:00'
  186. }
  187. const res: any = await http.post('/api/ad/multiUpDailyBudget', params)
  188. loading.close()
  189. if (res.errNo == 0) {
  190. ElMessage.success('修改成功')
  191. if (res.rst.record_id) {
  192. getMultiUpDailyBudgetRes(res.rst.record_id, str_val)
  193. }
  194. } else {
  195. ElMessage.error(res.errMsg)
  196. }
  197. return
  198. }
  199. }
  200. /**获取批量修改日预算结果 */
  201. const getMultiUpDailyBudgetRes = async (record_id, str_val) => {
  202. const loading = ElLoading.service({
  203. lock: true,
  204. text: '结果获取中...',
  205. background: 'rgba(255, 255, 255, 0.7)',
  206. })
  207. const res: any = await http.get('/api/ad/multiUpDailyBudgetRes', { record_id })
  208. loading.close()
  209. if (res.errNo == 0) {
  210. pageInfo.schedule = 3;
  211. pageInfo.cancleText = '关闭'
  212. pageInfo.hasBtn = true;
  213. if (Array.isArray(res.rst.result)) {
  214. pageInfo.multipleSelection.forEach((item) => {
  215. let arr = str_val.filter((v) => v.account_id == item.advertiser_id)
  216. if (arr.length > 0) {
  217. let brr = res.rst.result.filter((v) => { v.account_id == arr[0].account_id })
  218. if (brr.length > 0) {
  219. item['state'] = brr[0].state
  220. item['err_msg'] = brr[0].err_msg
  221. }
  222. }
  223. })
  224. pageInfo.successLength = str_val.length - res.rst.result?.length
  225. } else {
  226. pageInfo.successLength = str_val.length
  227. }
  228. } else {
  229. ElMessage.error(res.errMsg)
  230. }
  231. }
  232. const closeEvent = () => {
  233. if (pageInfo.schedule == 1) {
  234. dialogShow.value = false
  235. }
  236. if (pageInfo.schedule == 2) {
  237. pageInfo.schedule = 1;
  238. pageInfo.cancleText = '取消'
  239. }
  240. if (pageInfo.schedule == 3) {
  241. dialogShow.value = false
  242. emit('confirm', '')
  243. }
  244. }
  245. /**点击应用 */
  246. const application = () => {
  247. if ((pageInfo.selectValue != 1 && pageInfo.selectValue != 6 && pageInfo.isNoLimit) || pageInfo.mainInputError) {
  248. ElMessage.error('预算批量规则设置有误')
  249. return
  250. }
  251. if (pageInfo.selectValue != 6 && pageInfo.inputValue == '') {
  252. pageInfo.mainInputErrHint = '请输入账户日预算,仅支持正整数'
  253. pageInfo.mainInputError = true;
  254. ElMessage.error('预算批量规则设置有误')
  255. return
  256. }
  257. if (pageInfo.selectValue == 1) {//修改为
  258. pageInfo.multipleSelection.forEach((item) => {
  259. item.modifyDailyBudget = pageInfo.inputValue
  260. })
  261. }
  262. if (pageInfo.selectValue == 2) {//提高
  263. pageInfo.multipleSelection.forEach((item) => {
  264. item.modifyDailyBudget = parseFloat((Number(item.daily_budget) + Number(pageInfo.inputValue)).toFixed(2).toString())
  265. })
  266. }
  267. if (pageInfo.selectValue == 3) {//降低
  268. pageInfo.multipleSelection.forEach((item) => {
  269. item.modifyDailyBudget = parseFloat((Number(item.daily_budget) - Number(pageInfo.inputValue)).toFixed(2).toString())
  270. })
  271. }
  272. if (pageInfo.selectValue == 4) {//按 % 提高
  273. pageInfo.multipleSelection.forEach((item) => {
  274. item.modifyDailyBudget = parseFloat((Number(item.daily_budget) * (Number(pageInfo.inputValue) / 100 + 1)).toFixed(2).toString())
  275. })
  276. }
  277. if (pageInfo.selectValue == 5) {//按 % 降低
  278. pageInfo.multipleSelection.forEach((item) => {
  279. item.modifyDailyBudget = parseFloat((Number(item.daily_budget) * (1 - Number(pageInfo.inputValue) / 100)).toFixed(2).toString())
  280. })
  281. }
  282. if (pageInfo.selectValue == 6) {//不限
  283. pageInfo.multipleSelection.forEach((item) => {
  284. item.modifyDailyBudget = '不限'
  285. })
  286. }
  287. pageInfo.multipleSelection.forEach((item) => {
  288. item.inputError = ''
  289. if (item.modifyDailyBudget == '不限') return
  290. if (!isPositiveInteger(item.modifyDailyBudget)) {
  291. item.inputError = '请输入账户日预算,仅支持正整数'
  292. return
  293. }
  294. let isDetermine = isLimit(50, 40000000, item.modifyDailyBudget)
  295. if (!isDetermine.flag) {
  296. item.inputError = isDetermine.err
  297. return
  298. }
  299. })
  300. }
  301. // 切换显隐
  302. const dialogShow = ref<boolean>(false)
  303. const switchShow = (val: boolean, multipleSelection_c: any[]) => {
  304. dialogShow.value = val
  305. if (val) {
  306. const initObj = {
  307. hasBtn: false,
  308. cancleText: '取消',
  309. schedule: 1,
  310. successLength: 0,//修改成功条数
  311. multipleSelection: [],
  312. oldMultipleSelection: [],
  313. isNoLimit: false,//所选账户是否包含不限
  314. modifyRuleValue: 1,//规则
  315. inputValue: '',
  316. mainInputError: false,
  317. mainInputErrHint: '',
  318. selectValue: 1,
  319. }
  320. for (let key in initObj) {//所有字段 清空重来
  321. pageInfo[key] = _.cloneDeep(initObj[key])
  322. }
  323. pageInfo.oldMultipleSelection = multipleSelection_c;
  324. pageInfo.multipleSelection = _.cloneDeep(multipleSelection_c)
  325. pageInfo.multipleSelection.forEach((item) => {
  326. item['modifyDailyBudget'] = ''
  327. if (item.daily_budget == 0) {
  328. pageInfo.isNoLimit = true
  329. }
  330. });
  331. }
  332. }
  333. const selectChange = () => {
  334. pageInfo.inputValue = ''
  335. pageInfo.mainInputError = false;
  336. pageInfo.mainInputErrHint = ''
  337. }
  338. /**input change */
  339. const onChangeInput = (type, index?) => {
  340. if (type == 'mainInput') {
  341. pageInfo.mainInputError = false;
  342. if (pageInfo.selectValue == 1 || pageInfo.selectValue == 2 || pageInfo.selectValue == 3) {
  343. if (!isPositiveInteger(pageInfo.inputValue)) {
  344. pageInfo.mainInputError = true;
  345. pageInfo.mainInputErrHint = '请输入账户日预算,仅支持正整数'
  346. return
  347. }
  348. let isDetermine = isLimit(1, 40000000, pageInfo.inputValue)
  349. if (!isDetermine.flag) {
  350. pageInfo.mainInputError = true;
  351. pageInfo.mainInputErrHint = isDetermine.err
  352. return
  353. }
  354. } else {
  355. if (!isPositiveNumberWithTwoDecimalPlaces(pageInfo.inputValue)) {
  356. pageInfo.mainInputError = true;
  357. pageInfo.mainInputErrHint = '请输入预算调整比例,最多支持小数点后两位'
  358. return
  359. }
  360. }
  361. }
  362. if (type == 'tableInput') {
  363. let item = pageInfo.multipleSelection[index]
  364. item.inputError = ''
  365. if (item.modifyDailyBudget == '') return;
  366. if (item.modifyDailyBudget != '不限') {
  367. if (!isPositiveInteger(item.modifyDailyBudget)) {
  368. item.inputError = '请输入账户日预算,仅支持正整数'
  369. return
  370. }
  371. let isDetermine = isLimit(50, 40000000, item.modifyDailyBudget)
  372. if (!isDetermine.flag) {
  373. item.inputError = isDetermine.err
  374. return
  375. }
  376. }
  377. }
  378. }
  379. /**使用正则表达式检查是否为正数且最多两位小数 */
  380. const isPositiveNumberWithTwoDecimalPlaces = (value) => {
  381. const regex = /^[1-9]\d*(\.\d{1,2})?$|^0\.\d{1,2}$/;
  382. return regex.test(value.toString());
  383. }
  384. /**判断是否是正整数 */
  385. const isPositiveInteger = (value) => {
  386. return /^[1-9]\d*$/.test(value.toString());
  387. }
  388. /**判断限额 */
  389. const isLimit = (min: number, max: number, value: number) => {
  390. if (value < min || value > max) {
  391. return {
  392. flag: false,
  393. err: `日预算范围限制:${min}-${max}`
  394. }
  395. } else {
  396. return {
  397. flag: true
  398. }
  399. }
  400. }
  401. const tableHeaderStyle = ({ row, column, rowIndex, columnIndex }: never) => {
  402. return {
  403. backgroundColor: '#FAFAFA',
  404. color: '#161E46',
  405. height: '44px'
  406. }
  407. }
  408. // 父组件共享值
  409. defineExpose({
  410. switchShow,
  411. });
  412. onMounted(() => {
  413. nextTick(() => {
  414. })
  415. })
  416. </script>
  417. <style lang="scss" scoped>
  418. @import "@/assets/style/batchDialogGdt.scss";
  419. .batch-title {
  420. position: relative;
  421. margin-bottom: 25px;
  422. font-size: 14px;
  423. color: #333330;
  424. }
  425. .error {
  426. color: #f56c6c;
  427. line-height: 20px;
  428. font-size: 12px;
  429. }
  430. .inputError {
  431. --el-input-hover-border-color: #f56c6c;
  432. --el-input-focus-border-color: #f56c6c;
  433. --el-input-border-color: #f56c6c;
  434. }
  435. .preview-modified {
  436. display: flex;
  437. align-items: center;
  438. .budget {
  439. width: 100px;
  440. margin-right: 20px;
  441. }
  442. .modified-info {
  443. display: flex;
  444. align-items: center;
  445. }
  446. .status {
  447. width: 70px;
  448. }
  449. .text {
  450. color: #888;
  451. }
  452. .modified-budget {
  453. margin-left: 20px;
  454. }
  455. }
  456. </style>