index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. <!-- 资费管理 -->
  2. <template>
  3. <div class="container">
  4. <div class="head-title">
  5. <span>{{ route.meta.title }} </span>
  6. <span class="head-title-right">
  7. <!-- <a-button class="m-r-10" type="primary" @click="dictShowModel(1, null)">{{ $t('form.Add') }}</a-button> -->
  8. </span>
  9. </div>
  10. <!-- 搜索条件区 -->
  11. <div class="search-section">
  12. <a-form :model="searchForm" layout="inline">
  13. <!-- 资费名称-->
  14. <a-form-item field="label" :label="$t('tariffManagement.label')">
  15. <a-input v-model="searchForm.label"
  16. :placeholder="$t('lotCard.please') + $t('tariffManagement.label')" allow-clear/>
  17. </a-form-item>
  18. <!-- 供应商-->
  19. <a-form-item field="label" :label="$t('tariffManagement.soundName')">
  20. <a-select v-model="value" :style="{width:'320px'}" :placeholder="$t('lotCard.soundName')">
  21. <a-option v-for=" item in sourceList" :key="item.id" :value="item.value">{{
  22. item.label
  23. }}
  24. </a-option>
  25. </a-select>
  26. </a-form-item>
  27. <!-- 流量类型-->
  28. <a-form-item field="label" :label="$t('tariffManagement.FlowType')">
  29. <a-select v-model="value" :style="{width:'320px'}" :placeholder="$t('lotCard.FlowTypeName')">
  30. <a-option v-for=" item in trafficList" :key="item.id" :value="item.value">{{
  31. item.label
  32. }}
  33. </a-option>
  34. </a-select>
  35. </a-form-item>
  36. <a-form-item>
  37. <a-space>
  38. <a-button type="primary" @click="handleSearch">{{ $t('form.Search') }}</a-button>
  39. <a-button @click="resetSearch">{{ $t('form.Reset') }}</a-button>
  40. </a-space>
  41. </a-form-item>
  42. </a-form>
  43. </div>
  44. <div class="audit-btn">
  45. <a-button type="text" @click="dictShowModel(1, null)" v-if="role.getRole == 1">
  46. <template #icon>
  47. <icon-plus-circle/>
  48. </template>
  49. <template #default>{{ $t('form.Add') }}</template>
  50. </a-button>
  51. </div>
  52. <a-table row-key="id" :data="dataSource" :columns="role.getRole == 1 ? columns : columnsCustomer"
  53. :pagination="pagination" :scroll="{ x: 'auto' }" @page-change="evChangePage">
  54. <template #id="{ record }">
  55. <!-- 修改 -->
  56. <a class="a-link" href="javascript:;" style="margin-right: 1rem" @click="dictShowModel(2, record)">{{
  57. $t('form.Edit')
  58. }}</a>
  59. <!-- 删除 -->
  60. <a-popconfirm :content="$t('form.Delete')" :ok-text="$t('form.Confirm')"
  61. :cancel-text="$t('form.Cancel')" @ok="handleDel(record.id)">
  62. <a class="a-link" href="javascript:;" style="margin-right: 1rem">{{
  63. $t('form.Delete')
  64. }}</a>
  65. </a-popconfirm>
  66. </template>
  67. </a-table>
  68. <!--资费 弹框 -->
  69. <a-modal :title="typeCurrent == 1 ? $t('form.Add') : $t('form.Edit')" v-model:visible="visible"
  70. @onCancel="resetForm" centered :maskClosable="false" :footer="null" width="700px">
  71. <a-form ref="formRef" :rules="rules" :model="formState" @submit="handleSubmit">
  72. <div class="formTitle">基本信息</div>
  73. <a-form-item :label="$t('tariffManagement.source')" field="source">
  74. <a-select v-model="formState.source">
  75. <a-option v-for=" item in sourceList" :key="item.id" :value="item.value">{{
  76. item.label
  77. }}
  78. </a-option>
  79. </a-select>
  80. </a-form-item>
  81. <template v-if="formState.source">
  82. <a-form-item :label="$t('tariffManagement.simDataPlanId')" field="simDataPlanId">
  83. <a-select v-model="formState.simDataPlanId">
  84. <a-option v-for=" item in planList" :key="item.superior_id" :value="item.id"> 流量包{{
  85. item.id
  86. }}
  87. </a-option>
  88. </a-select>
  89. </a-form-item>
  90. </template>
  91. <a-form-item :label="$t('tariffManagement.label')" field="label">
  92. <a-input v-model="formState.label"/>
  93. </a-form-item>
  94. <a-form-item :label="$t('tariffManagement.userId')" field="userId">
  95. <a-select v-model="formState.userId">
  96. <a-option v-for=" item in userIdList" :key="item.id" :value="item.id">{{
  97. item.name
  98. }}
  99. </a-option>
  100. </a-select>
  101. </a-form-item>
  102. <a-form-item :label="$t('tariffManagement.billingMethod')" field="billingMethod">
  103. <a-select v-model="formState.billingMethod">
  104. <a-option v-for=" item in methodList" :key="item.id" :value="item.value">{{
  105. item.label
  106. }}
  107. </a-option>
  108. </a-select>
  109. </a-form-item>
  110. <a-form-item :label="$t('tariffManagement.currency')" field="currency">
  111. <a-select v-model="formState.currency">
  112. <a-option v-for=" item in currency" :key="item.id" :value="item.value">{{
  113. item.label
  114. }}
  115. </a-option>
  116. </a-select>
  117. </a-form-item>
  118. <div class="formTitle">计费信息</div>
  119. <a-form-item field="billingCycle" :label="$t('tariffManagement.billingCycle')" required>
  120. <a-radio-group v-model="formState.billingCycle">
  121. <a-radio value="1">按天</a-radio>
  122. <a-radio value="2">按月</a-radio>
  123. </a-radio-group>
  124. </a-form-item>
  125. <a-form-item field="" :label="$t('tariffManagement.pricing')" required>
  126. <a-input v-model="formState.pricing" v-if="formState.billingMethod==2">
  127. <template #append>
  128. {{ formState.currency === '0' ? '元' : '美金' }}
  129. </template>
  130. </a-input>
  131. <a-input v-model="formState.trafficBilling" v-if="formState.billingMethod==1"></a-input>
  132. <a-select v-model="formState.trafficBillingType" style="width: 80px; margin:0 8px;"
  133. v-if="formState.billingMethod==1">
  134. <a-option value="KB">KB</a-option>
  135. <a-option value="MB">MB</a-option>
  136. <a-option value="GB">GB</a-option>
  137. </a-select>
  138. <a-input v-model="formState.trafficBillingAmount" v-if="formState.billingMethod==1">
  139. <template #append>
  140. {{ formState.currency === '0' ? '元' : '美金' }}
  141. </template>
  142. </a-input>
  143. </a-form-item>
  144. <a-form-item field="settlementCycle" :label="$t('tariffManagement.cycleBuy')">
  145. <a-input v-model="formState.settlementCycleMap.starTime">
  146. <template #prepend>
  147. 最短
  148. </template>
  149. <template #append>
  150. 个月,最长
  151. </template>
  152. </a-input>
  153. <a-input v-model="formState.settlementCycleMap.endTime" style="width: 50%;">
  154. <template #append>
  155. 个月
  156. </template>
  157. </a-input>
  158. </a-form-item>
  159. <a-form-item :label="$t('tariffManagement.MRCName')" field="mrcAmount">
  160. <a-input v-model="formState.mrcAmount">
  161. <template #append>
  162. {{ formState.currency === '0' ? '元' : '美金' }}
  163. </template>
  164. </a-input>
  165. </a-form-item>
  166. <a-form-item :label="$t('tariffManagement.networkName')" field="networkAccessFee">
  167. <a-input v-model="formState.networkAccessFee">
  168. <template #append>
  169. {{ formState.currency === '0' ? '元' : '美金' }}
  170. </template>
  171. </a-input>
  172. </a-form-item>
  173. <a-form-item>
  174. <a-button type="primary" html-type="submit" style="margin-right: 10px;">{{
  175. $t('form.Confirm')
  176. }}
  177. </a-button>
  178. <a-button @click="resetForm">{{ $t('form.Cancel') }}</a-button>
  179. </a-form-item>
  180. </a-form>
  181. </a-modal>
  182. <a-modal width="70%" :visible="planVisible" title="选择流量包" @ok="handleSubmitPlan" @cancel="handleCancel">
  183. <!-- 搜索条件区 -->
  184. <div class="search-section">
  185. <a-form :model="formData" layout="inline">
  186. <a-form-item field="label" :label="$t('tariffManagement.label')">
  187. <a-input v-model="formData.label"
  188. :placeholder="$t('lotCard.please') + $t('tariffManagement.label')" allow-clear/>
  189. </a-form-item>
  190. <a-form-item>
  191. <a-space>
  192. <a-button type="primary" @click="handleSearchPlan">{{ $t('form.Search') }}</a-button>
  193. <a-button @click="resetSearchPlan">{{ $t('form.Reset') }}</a-button>
  194. </a-space>
  195. </a-form-item>
  196. </a-form>
  197. </div>
  198. <a-table row-key="id" :data="planList" :columns="planColumns" :scroll="{ x: 'auto' }"
  199. :row-selection="rowSelectionPlan" v-model:selectedKeys="selectedKeysPlan">
  200. </a-table>
  201. </a-modal>
  202. </div>
  203. </template>
  204. <script setup>
  205. import {onMounted, ref, reactive, getCurrentInstance, nextTick, watch} from "vue";
  206. import {useRoute} from "vue-router";
  207. import {columns, columnsCustomer, planColumns} from "./config";
  208. import {Message} from '@arco-design/web-vue'
  209. import {deleteTariff, updateTariff, addTariff, tariffList} from "@/api/path/tariffManagement.api"
  210. import {getDataPlanList} from "@/api/path/lotCard.api"
  211. import {getSTSInfoList} from '@/api/path/system.api'
  212. import {Getdictionary} from '@/mixins/index.js'
  213. import {useSystemStore} from '@/store/modules/systemStore'
  214. const role = useSystemStore()
  215. const {proxy} = getCurrentInstance()
  216. const formRef = ref()
  217. const searchForm = ref({
  218. "label": "",
  219. });
  220. const currency = ref([])
  221. const dataSource = ref([]);
  222. const route = useRoute();
  223. const pagination = ref({
  224. total: 0,
  225. pageSize: 10,
  226. current: 1,
  227. })
  228. const intData = async () => {
  229. const param = {
  230. current: pagination.value.current,
  231. size: pagination.value.pageSize,
  232. ...searchForm.value,
  233. }
  234. const {data} = await tariffList(param)
  235. dataSource.value = (data.records || []).map((item, index) => {
  236. const sourceName = sourceList.value.find(val => val.value == item.source)?.label
  237. const billingCycleName = cycleist.value.find(val => val.value == item.billingCycle)?.label
  238. const pricingCurrty = currency.value.find(val => val.value == item.currency)?.label
  239. const Activated = item.trafficBilling+'/'+item.trafficBillingType
  240. return {
  241. ...item,
  242. sourceName,
  243. pricingName: item.pricing !== '' ? item.pricing + '/' + pricingCurrty : '',
  244. billingCycleName,
  245. Activated:Activated,
  246. status: "正常"
  247. }
  248. })
  249. pagination.value.total = data.total
  250. }
  251. // 删除
  252. const handleDel = async (id) => {
  253. const {code} = await deleteTariff({id})
  254. if (code == 200) {
  255. Message.success({
  256. content: "删除成功!",
  257. duration: 2000,
  258. })
  259. intData()
  260. }
  261. };
  262. const evChangePage = (page) => {
  263. pagination.value.current = page
  264. intData()
  265. }
  266. const handleSearch = () => {
  267. intData()
  268. }
  269. const resetSearch = () => {
  270. searchForm.value.label = ""
  271. intData()
  272. }
  273. // -------------------弹窗数据------------------------------------
  274. const planList = ref([])
  275. const userIdList = ref([])
  276. const visible = ref(false);
  277. const typeCurrent = ref(null);
  278. const sourceList = ref([])
  279. const trafficList = ref([])
  280. const cycleist = ref([])
  281. const typeList = ref([])
  282. const methodList = ref([])
  283. const settlementCycleMap = ref([])
  284. const formState = ref({
  285. id: "",
  286. // 资费名称(必填)
  287. "label": "",
  288. // 流量包ID(必填)
  289. "simDataPlanId": null,
  290. // 用户ID(必填)
  291. "userId": null,
  292. // 来源(必填)
  293. "source": "",
  294. // 计费周期(必填)
  295. "billingCycle": "",
  296. // 计费方式(必填)
  297. "billingMethod": "1",
  298. // 结算周期(必填)
  299. "settlementCycle": "",
  300. // 价格(必填)
  301. "pricing": "",
  302. // 币种(必填)
  303. "currency": "0",
  304. // 流量资费计费
  305. "trafficBilling": '',
  306. // 流量资费计费类型
  307. "trafficBillingType": '',
  308. // 流量资费计费金
  309. "trafficBillingAmount": '',
  310. // MRC金额
  311. "mrcAmount": '',
  312. // 网络接入费
  313. "networkAccessFee": '',
  314. "settlementCycleMap": {
  315. "starTime": '',
  316. "endTime": ''
  317. }
  318. });
  319. const rules = {
  320. label: [{required: true, trigger: 'change',}],
  321. simDataPlanId: [{required: true, trigger: 'change',}],
  322. userId: [{required: true, trigger: 'change',}],
  323. source: [{required: true, trigger: 'change',}],
  324. billingCycle: [{required: true, trigger: 'change',}],
  325. billingMethod: [{required: true, trigger: 'change',}],
  326. currency: [{required: true, trigger: 'change',}],
  327. trafficBilling: [{required: true, trigger: 'change',}],
  328. trafficBillingType: [{required: true, trigger: 'change',}],
  329. trafficBillingAmount: [{required: true, trigger: 'change',}],
  330. mrcAmount: [{required: true, trigger: 'change',}],
  331. networkAccessFee: [{required: true, trigger: 'change',}],
  332. };
  333. // 提交
  334. const handleSubmit = ({values, errors}) => {
  335. formRef.value.validate(async (errors) => {
  336. if (!errors) {
  337. const formVal = JSON.parse(JSON.stringify(values))
  338. delete formVal.settlementCycleMap
  339. formVal.userId = Number(values.userId)
  340. formVal.simDataPlanId = String(values.simDataPlanId)
  341. if (values.settlementCycleMap.starTime && values.settlementCycleMap.starTime) {
  342. formVal.settlementCycle = values.settlementCycleMap.starTime + '~' + values.settlementCycleMap.endTime
  343. } else {
  344. Message.warning({
  345. content: "请选择订购周期!",
  346. duration: 2000,
  347. })
  348. }
  349. if (formState.value.id!=='') {
  350. const {code, data} = await updateTariff(formVal)
  351. if (code == 200) {
  352. Message.success({
  353. content: "修改成功!",
  354. duration: 2000,
  355. })
  356. visible.value = false;
  357. intData()
  358. }
  359. } else {
  360. const {code, data} = await addTariff(formVal)
  361. if (code == 200) {
  362. Message.success({
  363. content: "添加成功!",
  364. duration: 2000,
  365. })
  366. visible.value = false;
  367. intData()
  368. }
  369. }
  370. }
  371. });
  372. }
  373. // 弹框
  374. const dictShowModel = (type, data) => {
  375. handleModelId()
  376. formRef.value.resetFields();
  377. if (formState.value.settlementCycleMap) {
  378. formState.value.settlementCycleMap.starTime = ''
  379. formState.value.settlementCycleMap.endTime = ''
  380. }
  381. typeCurrent.value = type;
  382. // 编辑
  383. if (type == 2) {
  384. Object.keys(formState.value).forEach(key => {
  385. if (data[key]) {
  386. formState.value[key] = data[key]
  387. }
  388. })
  389. formState.value.simDataPlanId = Number(formState.value.simDataPlanId)
  390. formState.value.userId = Number(formState.value.userId)
  391. if (data.pricing !== '') {
  392. formState.value.pricing = data.pricing.match(/\d+/)[0] || ''
  393. }
  394. if (data.settlementCycle) {
  395. formState.value.settlementCycleMap.starTime = data.settlementCycle.split('~')[0] || ''
  396. formState.value.settlementCycleMap.endTime = data.settlementCycle.split('~')[1] || ''
  397. }
  398. }
  399. nextTick(() => {
  400. visible.value = true;
  401. })
  402. }
  403. // 获取id数组
  404. const handleModelId = async () => {
  405. const param = {
  406. current: 1,
  407. size: 999,
  408. }
  409. getSTSInfoList(param).then(res => {
  410. userIdList.value = (res.data.records || [])
  411. })
  412. }
  413. const handleDataPlan = async () => {
  414. const param = {
  415. current: 1,
  416. size: 999,
  417. source: formState.value.source
  418. }
  419. getDataPlanList(param).then(res => {
  420. planList.value = res.data.records || []
  421. })
  422. }
  423. // 取消
  424. const resetForm = () => {
  425. visible.value = false;
  426. Object.keys(formState.value).forEach(key => {
  427. formState.value[key] = ''
  428. })
  429. formState.value.settlementCycleMap = {
  430. starTime:'',
  431. endTime:''
  432. }
  433. }
  434. // --------------------------------------------------------
  435. // 资费弹窗------------------------------------------------
  436. const planVisible = ref(false)
  437. const formData = ref({})
  438. const selectedKeysPlan = ref([])
  439. const rowSelectionPlan = reactive({
  440. type: 'radio',
  441. showCheckedAll: true,
  442. onlyCurrent: false,
  443. });
  444. const resetSearchPlan = () => {
  445. }
  446. const handleSearchPlan = () => {
  447. }
  448. const handleCancel = () => {
  449. planVisible.value = false
  450. }
  451. const handleSubmitPlan = () => {
  452. if (selectedKeysPlan.value.length > 0) {
  453. formState.value.simDataPlanId = String(selectedKeysPlan.value[0])
  454. planVisible.value = false
  455. }
  456. }
  457. watch(
  458. () => formState.value.source,
  459. (newValue, oldValue) => {
  460. if (newValue != oldValue) {
  461. handleDataPlan()
  462. }
  463. },
  464. {immediate: true}
  465. );
  466. watch(()=>formState.value.billingMethod,val=>{
  467. if(val==2){
  468. formState.value.trafficBillingType = ''
  469. formState.value.trafficBilling = ''
  470. formState.value.trafficBillingAmount = ''
  471. }
  472. })
  473. // -------------------------------------------------------
  474. // 获取字典
  475. const handleDictValue = async () => {
  476. sourceList.value = await Getdictionary('source')
  477. cycleist.value = await Getdictionary('Billingcycle')
  478. typeList.value = await Getdictionary('Billingcycle')
  479. methodList.value = await Getdictionary('billingMethod')
  480. currency.value = await Getdictionary('currencyType')
  481. }
  482. onMounted(async () => {
  483. await handleDictValue()
  484. await intData()
  485. })
  486. </script>
  487. <style scoped lang="less">
  488. .head-title-right {
  489. .m-r-10 {
  490. margin-right: 10px;
  491. }
  492. }
  493. .search-section {
  494. margin-top: 20px;
  495. margin-bottom: 20px;
  496. }
  497. .container {
  498. .head-title {
  499. display: flex;
  500. justify-content: space-between;
  501. }
  502. .form-row {
  503. display: flex;
  504. .form-row-col {
  505. width: 25%;
  506. display: flex;
  507. align-items: center;
  508. .form-row-label {
  509. width: 120px;
  510. text-align: right;
  511. }
  512. }
  513. }
  514. }
  515. .audit-btn {
  516. margin-bottom: 10px;
  517. }
  518. .formTitle {
  519. font-size: 18px;
  520. margin-bottom: 20px;
  521. display: flex;
  522. align-items: center
  523. }
  524. .formTitle::before {
  525. content: "";
  526. display: inline-block;
  527. width: 4px;
  528. height: 20px;
  529. background-color: green;
  530. margin-right: 10px;
  531. }
  532. </style>