You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

483 lines
17 KiB

3 weeks ago
3 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
2 weeks ago
3 weeks ago
  1. <template>
  2. <el-card>
  3. <div class="condition">
  4. <div class="condition-item1">
  5. <el-text size="large">活动名称</el-text>
  6. <el-input v-model="searchForm.activityName" style="width: 10vw" placeholder="请输入活动名称" clearable />
  7. </div>
  8. <div class="condition-item1">
  9. <el-text size="large">业绩归属</el-text>
  10. <!-- <el-cascader v-model="searchForm.businessBelong" :options="marketOptions" placeholder="请选择所属地区" clearable
  11. style="width: 10vw" /> -->
  12. <el-select v-model="searchForm.businessBelong" placeholder="请选择业绩归属" style="width: 10vw">
  13. <el-option label="客户归属地" value="客户归属地" />
  14. <el-option label="活动归属地" value="活动归属地" />
  15. </el-select>
  16. </div>
  17. <div class="condition-item2">
  18. <el-text size="large">开始时间</el-text>
  19. <el-date-picker v-model="searchForm.startTime" type="datetime" placeholder="请选择开始时间"
  20. format="YYYY-MM-DD HH:mm:ss" :default-time="defaultStartTime" clearable />
  21. </div>
  22. <div class="condition-item2">
  23. <el-text size="large">结束时间</el-text>
  24. <el-date-picker v-model="searchForm.endTime" type="datetime" placeholder="请选择结束时间"
  25. format="YYYY-MM-DD HH:mm:ss" :default-time="defaultEndTime" clearable />
  26. </div>
  27. <el-button type="primary" @click="getActivity">查询</el-button>
  28. <el-button type="success" @click="reset">重置</el-button>
  29. </div>
  30. </el-card>
  31. <el-button type="success" @click="showAdd = true" style="margin-top: 1vh;">新增活动</el-button>
  32. <el-card style="margin-top: 1vh;height:80vh;">
  33. <el-table :data="tableData" style="width: 82vw;height:70vh;" :row-style="{ height: '50px' }">
  34. <el-table-column type="index" label="序号" width="100px" fixed="left">
  35. <template #default="scope">
  36. <span>{{ scope.$index + 1 + (pagination.pageNum - 1) * pagination.pageSize }}</span>
  37. </template>
  38. </el-table-column>
  39. <el-table-column prop="activityName" label="活动名称" width="150px" show-overflow-tooltip />
  40. <el-table-column prop="businessBelong" label="业绩归属地" width="150px" />
  41. <el-table-column prop="areaName" label="归属地" width="150px" />
  42. <el-table-column prop="startTime" label="开始时间" width="200px">
  43. <template #default="scope">
  44. {{ moment(scope.row.startTime).format('YYYY-MM-DD HH:mm:ss') }}
  45. </template>
  46. </el-table-column>
  47. <el-table-column prop="endTime" label="结束时间" width="200px">
  48. <template #default="scope">
  49. {{
  50. moment(scope.row.endTime).format('YYYY-MM-DD HH:mm:ss')
  51. }}
  52. </template>
  53. </el-table-column>
  54. <el-table-column prop="status" label="状态" width="150px">
  55. <template #default="scope">
  56. {{ scope.row.status === '0' ? '未开始' :
  57. scope.row.status === '1' ? '进行中' :
  58. scope.row.status === '2' ? '已结束' : scope.row.status
  59. }}
  60. </template>
  61. </el-table-column>
  62. <el-table-column prop="creatorName" label="添加人" width="150px" />
  63. <el-table-column prop="operation" label="操作" width="220px">
  64. <template #default="scope">
  65. <el-button type="primary" text @click="editOpen(scope.row)">编辑</el-button>
  66. <el-button type="danger" text @click="openDel(scope.row)">删除</el-button>
  67. </template>
  68. </el-table-column>
  69. </el-table>
  70. <el-pagination v-model:current-page="pagination.pageNum" v-model:page-size="pagination.pageSize"
  71. layout="total, sizes, prev, pager, next, jumper" :total="pagination.total" style="margin-top: 1vh;"
  72. @size-change="handleSizeChange" @current-change="handleCurrentChange" />
  73. </el-card>
  74. <el-dialog v-model="showAdd" width="20vw" draggable align-center style="background-color: rgb(243,250,254);">
  75. <div class="add-item">
  76. <el-text size="large">活动名称</el-text>
  77. <el-input v-model="addForm.activityName" style="width: 12vw" placeholder="请输入活动名称" maxlength="100" clearable />
  78. </div>
  79. <div class="add-item">
  80. <el-text size="large">业绩归属</el-text>
  81. <el-radio-group v-model="addForm.businessBelong" style="width: 12vw">
  82. <el-radio size="large" value="客户归属地">客户归属地</el-radio>
  83. <el-radio size="large" value="活动归属地">活动归属地</el-radio>
  84. </el-radio-group>
  85. </div>
  86. <div class="add-item" v-show="addForm.businessBelong === '活动归属地'">
  87. <el-text size="large">所属地区</el-text>
  88. <el-cascader v-model="addForm.area" :options="marketOptions" placeholder="请选择所属地区" clearable
  89. style="width: 12vw" />
  90. </div>
  91. <div class="add-item">
  92. <el-text size="large">开始时间</el-text>
  93. <el-date-picker v-model="addForm.startTime" type="datetime" placeholder="请选择开始时间"
  94. :default-time="defaultStartTime" style="width: 12vw" />
  95. </div>
  96. <div class="add-item">
  97. <el-text size="large">结束时间</el-text>
  98. <el-date-picker v-model="addForm.endTime" type="datetime" placeholder="请选择结束时间"
  99. :default-time="defaultEndTime" style="width: 12vw" />
  100. </div>
  101. <div style="display: flex; justify-content: center; margin-top: 5vh;">
  102. <el-button type="primary" @click="hideAdd">取消</el-button>
  103. <el-button type="primary" @click="handleAdd">确定</el-button>
  104. </div>
  105. </el-dialog>
  106. <el-dialog v-model="showEdit" width="20vw" draggable align-center style="background-color: rgb(243,250,254);">
  107. <div class="edit-item">
  108. <el-text size="large">活动名称</el-text>
  109. <el-input v-model="editForm.activityName" style="width: 12vw" placeholder="请输入活动名称" maxlength="100" clearable />
  110. </div>
  111. <div class="edit-item">
  112. <el-text size="large">业绩归属</el-text>
  113. <el-radio-group v-model="editForm.businessBelong" style="width: 12vw">
  114. <el-radio size="large" value="客户归属地">客户归属地</el-radio>
  115. <el-radio size="large" value="活动归属地">活动归属地</el-radio>
  116. </el-radio-group>
  117. </div>
  118. <div class="edit-item" v-show="editForm.businessBelong === '活动归属地'">
  119. <el-text size="large">所属地区</el-text>
  120. <el-cascader v-model="editForm.area" :options="marketOptions" placeholder="请选择所属地区" clearable
  121. style="width: 12vw" />
  122. </div>
  123. <div class="edit-item">
  124. <el-text size="large">开始时间</el-text>
  125. <el-date-picker v-model="editForm.startTime" type="datetime" placeholder="请选择开始时间"
  126. :default-time="defaultStartTime" style="width: 12vw" />
  127. </div>
  128. <div class="edit-item">
  129. <el-text size="large">结束时间</el-text>
  130. <el-date-picker v-model="editForm.endTime" type="datetime" placeholder="请选择结束时间"
  131. :default-time="defaultEndTime" style="width: 12vw" />
  132. </div>
  133. <div style="display: flex; justify-content: center; margin-top: 5vh;">
  134. <el-button type="primary" @click="hideEdit">取消</el-button>
  135. <el-button type="primary" @click="handleEdit">确定</el-button>
  136. </div>
  137. </el-dialog>
  138. <ConfirmDialog v-model="showDel" message="删除该活动数据" @confirm="handleDel()" @cancel="hideDel" @close="hideDel" />
  139. </template>
  140. <script setup>
  141. import { ElMessage, ElPagination } from 'element-plus';
  142. import { onMounted, ref } from 'vue'
  143. import API from "@/util/http.js"
  144. import moment from 'moment'
  145. import { useAdminStore } from "@/store/index.js"
  146. import { storeToRefs } from "pinia"
  147. import { permissionMapping, hasMenuPermission } from "@/utils/menuTreePermission.js"
  148. const adminStore = useAdminStore();
  149. const { adminData, menuTree } = storeToRefs(adminStore)
  150. import ConfirmDialog from '@/components/dialogs/ConfirmDialog.vue'
  151. import { add } from 'lodash';
  152. // 活动名称正则表达式
  153. const activityNameReg = /^[-a-zA-Z0-9\u4e00-\u9fa5,。!?、;:“”‘’()《》【】——~,.!?:;'"()\[\]_&+=]{0,100}$/;
  154. const tableData = ref([])
  155. const pagination = ref({
  156. pageNum: 1,
  157. pageSize: 10,
  158. total: 0
  159. })
  160. const searchForm = ref({
  161. activityName: ''
  162. })
  163. const showAdd = ref(false)
  164. const showEdit = ref(false)
  165. const showDel = ref(false)
  166. const currentDelRow = ref(null)
  167. const addForm = ref({
  168. activityName: '',
  169. area: []
  170. })
  171. const editForm = ref({
  172. activityName: '',
  173. businessBelong: '',
  174. area: [],
  175. startTime: null,
  176. endTime: null,
  177. id: ''
  178. })
  179. const marketOptions = ref([])
  180. const getActivity = async function () {
  181. const rechargeActivity = {
  182. activityName: searchForm.value.activityName,
  183. businessBelong: searchForm.value.businessBelong,
  184. }
  185. if (searchForm.value.startTime && moment(searchForm.value.startTime).isValid()) {
  186. rechargeActivity.startTime = moment(searchForm.value.startTime).format('YYYY-MM-DD HH:mm:ss');
  187. }
  188. if (searchForm.value.endTime && moment(searchForm.value.endTime).isValid()) {
  189. rechargeActivity.endTime = moment(searchForm.value.endTime).format('YYYY-MM-DD HH:mm:ss');
  190. }
  191. const params = {
  192. pageNum: pagination.value.pageNum,
  193. pageSize: pagination.value.pageSize,
  194. rechargeActivity
  195. }
  196. const res = await API({
  197. url: '/admin/coin/rechargeActivityCenter/queryActivity',
  198. data: params
  199. })
  200. if (res.code === 200) {
  201. tableData.value = res.data.list
  202. pagination.value.total = res.data.total
  203. }
  204. }
  205. const handleAdd = async function () {
  206. const activityName = addForm.value.activityName
  207. if (!validateActivityName(activityName)) return
  208. if (!addForm.value.businessBelong) {
  209. ElMessage.error('请选择业绩归属')
  210. return
  211. }
  212. if (addForm.value.businessBelong === '活动归属地' && addForm.value.area.length === 0) {
  213. ElMessage.error('请选择所属地区')
  214. return
  215. }
  216. if (!addForm.value.startTime) {
  217. ElMessage.error('请选择开始时间')
  218. return
  219. }
  220. if (!addForm.value.endTime) {
  221. ElMessage.error('请选择结束时间')
  222. return
  223. }
  224. if(addForm.value.businessBelong === '客户归属地'){
  225. addForm.value.area = []
  226. }
  227. const params = {
  228. activityName: addForm.value.activityName,
  229. businessBelong: addForm.value.businessBelong,
  230. area: addForm.value.area.length > 0 ? addForm.value.area.slice(-1)[0] : null,
  231. startTime: moment(addForm.value.startTime).format('YYYY-MM-DD HH:mm:ss'),
  232. endTime: moment(addForm.value.endTime).format('YYYY-MM-DD HH:mm:ss'),
  233. creator: adminData.value.id
  234. }
  235. const res = await API({
  236. url: '/admin/coin/rechargeActivityCenter/addActivity',
  237. data: params
  238. })
  239. if (res.code === 200) {
  240. ElMessage.success('添加成功')
  241. getActivity()
  242. hideAdd()
  243. addForm.value = {
  244. activityName: '',
  245. businessBelong: '',
  246. area: [],
  247. startTime: null,
  248. endTime: null,
  249. }
  250. } else {
  251. ElMessage.error(res.msg || '添加失败')
  252. return
  253. }
  254. }
  255. const handleEdit = async function () {
  256. const activityName = editForm.value.activityName
  257. if (!validateActivityName(activityName)) return
  258. if (!editForm.value.activityName) {
  259. ElMessage.error('请输入活动名称')
  260. return
  261. }
  262. if (!editForm.value.businessBelong) {
  263. ElMessage.error('请选择业绩归属')
  264. return
  265. }
  266. if (editForm.value.businessBelong === '活动归属地' && editForm.value.area.length === 0) {
  267. ElMessage.error('请选择所属地区')
  268. return
  269. }
  270. if (!editForm.value.startTime) {
  271. ElMessage.error('请选择开始时间')
  272. return
  273. }
  274. if (!editForm.value.endTime) {
  275. ElMessage.error('请选择结束时间')
  276. return
  277. }
  278. if(editForm.value.businessBelong === '客户归属地'){
  279. editForm.value.area = []
  280. }
  281. const params = {
  282. id: editForm.value.id,
  283. activityName: editForm.value.activityName,
  284. businessBelong: editForm.value.businessBelong,
  285. area: editForm.value.area.length > 0 ? editForm.value.area.slice(-1)[0] : null,
  286. startTime: moment(editForm.value.startTime).format('YYYY-MM-DD HH:mm:ss'),
  287. endTime: moment(editForm.value.endTime).format('YYYY-MM-DD HH:mm:ss'),
  288. creator: adminData.value.id
  289. }
  290. console.log('看看修改params', params)
  291. const res = await API({
  292. url: '/admin/coin/rechargeActivityCenter/updateActivity',
  293. data: params
  294. })
  295. if (res.code === 200) {
  296. ElMessage.success('修改成功')
  297. getActivity()
  298. hideEdit()
  299. }
  300. }
  301. const handleDel = async function (row) {
  302. if (!currentDelRow.value) {
  303. ElMessage.error('当前选择无数据')
  304. return
  305. }
  306. const res = await API({
  307. url: '/admin/coin/rechargeActivityCenter/deleteActivity',
  308. data: {
  309. id: currentDelRow.value.id,
  310. }
  311. })
  312. if (res.code === 200) {
  313. ElMessage.success('删除成功')
  314. getActivity()
  315. showDel.value = false
  316. }
  317. }
  318. const getmarkets = async function () {
  319. try {
  320. const result = await API({
  321. url: '/market/selectMarket',
  322. });
  323. console.log('请求成功', result)
  324. // 递归转换树形结构为级联选择器需要的格式(跳过第一级节点)
  325. const transformTree = (nodes) => {
  326. // 直接处理第一级节点的子节点
  327. const allChildren = nodes.flatMap(node => node.children || []);
  328. return allChildren.map(child => {
  329. const grandchildren = child.children && child.children.length
  330. ? transformTree([child]) // 递归处理子节点
  331. : null;
  332. return {
  333. value: child.id,
  334. label: child.name,
  335. children: grandchildren
  336. }
  337. })
  338. }
  339. marketOptions.value = transformTree(result.data)
  340. console.log('转换后的地区树', marketOptions.value)
  341. } catch (error) {
  342. console.log('请求失败', error)
  343. }
  344. }
  345. const defaultStartTime = [
  346. new Date(2000, 1, 1, 0, 0, 0)
  347. ]
  348. const defaultEndTime = [
  349. new Date(2000, 2, 1, 23, 59, 59)
  350. ]
  351. const hideEdit = () => {
  352. showEdit.value = false
  353. editForm.value = {
  354. activityName: '',
  355. businessBelong: '',
  356. area: [],
  357. startTime: null,
  358. endTime: null,
  359. id: ''
  360. }
  361. }
  362. const editOpen = (row) => {
  363. editForm.value = {
  364. id: row.id,
  365. activityName: row.activityName,
  366. businessBelong: row.businessBelong,
  367. area: row.area ? [...row.area] : []
  368. }
  369. if (row.startTime) {
  370. editForm.value.startTime = moment(row.startTime).toDate()
  371. }
  372. if (row.endTime) {
  373. editForm.value.endTime = moment(row.endTime).toDate()
  374. }
  375. console.log('看看editForm', editForm.value)
  376. showEdit.value = true
  377. }
  378. const openDel = (row) => {
  379. currentDelRow.value = row
  380. showDel.value = true
  381. }
  382. const hideDel = () => {
  383. showDel.value = false
  384. currentDelRow.value = null
  385. }
  386. const reset = () => {
  387. searchForm.value = {
  388. activityName: '',
  389. businessBelong: '',
  390. startTime: null,
  391. endTime: null
  392. }
  393. getActivity()
  394. }
  395. const hideAdd = () => {
  396. showAdd.value = false
  397. addForm.value = {
  398. activityName: '',
  399. area: [],
  400. startTime: null,
  401. endTime: null
  402. }
  403. }
  404. const validateActivityName = (name) => {
  405. // 非空校验
  406. if (!name.trim()) {
  407. ElMessage.error('活动名称不能为空');
  408. return false;
  409. }
  410. // 长度校验(限制100字符)
  411. if (name.length > 100) {
  412. ElMessage.error('活动名称长度不能超过100字符');
  413. return false;
  414. }
  415. // 字符格式校验
  416. if (!activityNameReg.test(name)) {
  417. ElMessage.error('活动名称仅支持汉字、英文字母、泰语、数字及常见标点');
  418. return false;
  419. }
  420. return true;
  421. };
  422. const handleSizeChange = function(val){
  423. pagination.pageSize = val
  424. getActivity()
  425. }
  426. const handleCurrentChange = function(val){
  427. pagination.pageNum = val
  428. getActivity()
  429. }
  430. onMounted(() => {
  431. getActivity()
  432. getmarkets()
  433. console.log('看看adminData', adminData.value)
  434. })
  435. </script>
  436. <style>
  437. .condition {
  438. display: flex;
  439. align-items: center;
  440. }
  441. .condition-item1 {
  442. display: flex;
  443. align-items: center;
  444. width: 15vw;
  445. }
  446. .condition-item2 {
  447. display: flex;
  448. align-items: center;
  449. width: 17vw;
  450. }
  451. .add-item {
  452. display: flex;
  453. align-items: center;
  454. width: 17vw;
  455. margin-bottom: 1vh;
  456. }
  457. .edit-item {
  458. display: flex;
  459. align-items: center;
  460. width: 17vw;
  461. margin-bottom: 1vh;
  462. }
  463. </style>