index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. <template>
  2. <div class="table-box">
  3. <ProTable
  4. ref="proTable"
  5. :columns="columns"
  6. :request-api="getTableList"
  7. :init-param="initParam"
  8. :data-callback="dataCallback"
  9. @drag-sort="sortTable"
  10. >
  11. <!-- 表格 header 按钮 -->
  12. <template #tableHeader="scope">
  13. <!-- <el-button type="primary" :icon="CirclePlus" @click="openDrawer('新增')">新增商铺及商铺管理员</el-button> -->
  14. <el-button type="primary" :icon="CirclePlus" @click="handleToDetail('add', '')"> 新增 </el-button>
  15. <el-button type="primary" :icon="Download" @click="exportInfoExcel()"> 导出 </el-button>
  16. </template>
  17. <!-- Expand -->
  18. <template #expand="scope">
  19. {{ scope.row }}
  20. </template>
  21. <!-- usernameHeader -->
  22. <template #usernameHeader="scope">
  23. <el-button type="primary" @click="ElMessage.success('我是通过作用域插槽渲染的表头')">
  24. {{ scope.column.label }}
  25. </el-button>
  26. </template>
  27. <!-- createTime -->
  28. <template #createTime="scope">
  29. <el-button type="primary" link @click="ElMessage.success('我是通过作用域插槽渲染的内容')">
  30. {{ scope.row.createTime }}
  31. </el-button>
  32. </template>
  33. <!-- 表格操作 -->
  34. <template #operation="scope">
  35. <el-button type="primary" v-if="scope.row.storeApplicationStatus == 0" link :icon="Check" @click="approve(1, scope.row)">
  36. 通过
  37. </el-button>
  38. <!-- <el-button type="primary" v-if="scope.row.storeApplicationStatus == 0" link :icon="Close"
  39. @click="approve(2, scope.row)">拒绝</el-button> -->
  40. <el-button type="primary" v-if="scope.row.storeApplicationStatus == 0" link :icon="Close" @click="jj(scope.row)">
  41. 拒绝
  42. </el-button>
  43. <el-button type="primary" link :icon="Search" @click="handleToDetail('show', scope.row.id)"> 查看详情 </el-button>
  44. <el-button
  45. v-if="scope.row.storeStatus != 2"
  46. type="primary"
  47. link
  48. :icon="EditPen"
  49. @click="handleToDetail('edit', scope.row.id)"
  50. >
  51. 编辑
  52. </el-button>
  53. <el-button
  54. v-if="scope.row.storeApplicationStatus != 0"
  55. type="primary"
  56. link
  57. :icon="Delete"
  58. @click="deleteAccount(scope.row)"
  59. >
  60. 删除
  61. </el-button>
  62. <el-button type="primary" link :icon="PieChart" @click="handleCC(scope.row)" v-if="scope.row.storeStatus !== 2">
  63. 设置抽成比例
  64. </el-button>
  65. </template>
  66. </ProTable>
  67. <StoreUserDrawer ref="drawerRef" />
  68. <ImportExcel ref="dialogRef" />
  69. <!-- 设置抽成百分比弹出框-->
  70. <el-drawer v-model="drawer" :direction="direction" size="89%">
  71. <template #header>
  72. <h4>商家管理/店铺管理</h4>
  73. </template>
  74. <template #default>
  75. <div class="topTitle">当前店铺订单抽成比例:{{ ccValuefix || 0 }}%</div>
  76. <div class="inputcc">
  77. <span>设置抽成比例</span>
  78. <div>
  79. <el-input
  80. style="width: 100%"
  81. placeholder="请输入0~100的抽成比例"
  82. type="number"
  83. size="large"
  84. v-model="ccValue"
  85. :min="0"
  86. :max="100"
  87. @change="changeCCValue"
  88. >
  89. <template #append>
  90. <span>% / 每单</span>
  91. </template>
  92. </el-input>
  93. </div>
  94. </div>
  95. <div class="topTitle zysx">
  96. <span>计算说明</span>
  97. <div>
  98. <span>订单金额x抽成比例=平台抽成金额</span>
  99. <br />
  100. <span>例如:订单金额100元,抽成比例3%,则平台抽成为3元</span>
  101. </div>
  102. </div>
  103. <div class="topTitle zysx zysx2">
  104. <span>注意</span>
  105. <div>
  106. <span>1.修改抽成比例将影响所有新生产的订单</span>
  107. <br />
  108. <span>2.已完成订单的抽成比例不受影响</span>
  109. <br />
  110. <span>3.建议根据市场情况合理设置抽成比例</span>
  111. </div>
  112. </div>
  113. </template>
  114. <template #footer>
  115. <div style="flex: auto">
  116. <el-button @click="cancelClick"> 取消 </el-button>
  117. <el-button type="primary" @click="confirmClick"> 确定 </el-button>
  118. </div>
  119. </template>
  120. </el-drawer>
  121. <!-- 拒接弹窗 -->
  122. <el-dialog v-model="dialogFormVisible" title="温馨提示" width="500">
  123. <div style="padding-bottom: 2vh; font-size: 15px; font-weight: 700">是否拒绝【{{ jjValue?.storeName }}】商铺申请?</div>
  124. <el-form :model="form">
  125. <el-form-item label="拒绝原因:" :label-width="formLabelWidth">
  126. <el-input v-model="form.reason" autocomplete="off" :rows="2" type="textarea" />
  127. </el-form-item>
  128. </el-form>
  129. <template #footer>
  130. <div class="dialog-footer">
  131. <el-button @click="dialogFormVisible = false"> 取消 </el-button>
  132. <el-button type="primary" @click="jjQd"> 确定 </el-button>
  133. </div>
  134. </template>
  135. </el-dialog>
  136. </div>
  137. </template>
  138. <script setup lang="tsx" name="useProTable">
  139. import { useRouter, useRoute } from "vue-router";
  140. import { ref, reactive, computed, onMounted, watch, onUnmounted, onActivated } from "vue";
  141. import { StoreUser } from "@/api/interface";
  142. import { ElMessage } from "element-plus";
  143. import ProTable from "@/components/ProTable/index.vue";
  144. import ImportExcel from "@/components/ImportExcel/index.vue";
  145. import StoreUserDrawer from "@/views/proTable/components/StoreUserDrawer.vue";
  146. import { ProTableInstance, ColumnProps } from "@/components/ProTable/interface";
  147. import { CirclePlus, Delete, EditPen, Download, Upload, Refresh, Check, Close, Search, PieChart } from "@element-plus/icons-vue";
  148. import {
  149. getStoreUserList,
  150. addStoreUser,
  151. editStoreUser,
  152. deleteStoreUser,
  153. resetStoreUserPassWord,
  154. getStoreInfoList,
  155. getBusinessSection,
  156. deleteStoreInfo,
  157. approveStoreInfo,
  158. exportExcel,
  159. updateStoreCommissionRate
  160. } from "@/api/modules/storeUser";
  161. import { useHandleData } from "@/hooks/useHandleData";
  162. import { number } from "echarts";
  163. import type { DrawerProps } from "element-plus";
  164. const dialogFormVisible = ref(false);
  165. const formLabelWidth = "140px";
  166. const form = reactive({
  167. reason: ""
  168. });
  169. const router = useRouter();
  170. const route = useRoute();
  171. watch(
  172. () => route.fullPath,
  173. (newVal, oldVal) => {
  174. if (newVal.startsWith("/store/storeUser") && newVal !== oldVal) {
  175. proTable.value?.getTableList();
  176. }
  177. },
  178. { immediate: true }
  179. );
  180. //导出信息
  181. const exportInfoExcel = async () => {
  182. const params = (proTable.value?.searchParam as Record<string, any>) ?? {};
  183. let res = await exportExcel(params);
  184. console.log("导出res", res);
  185. // link.href = "https://file.ailien.shop/excel/generate/storeCashOutRecord4.xlsx";
  186. if (res.code == "200") {
  187. if (!res.data) {
  188. ElMessage.error("暂无可下载数据");
  189. return;
  190. }
  191. const exportFile = document.createElement("a");
  192. exportFile.style.display = "none";
  193. exportFile.download = `商铺信息.xlsx`;
  194. // return;
  195. exportFile.href = `${res.data}?timestamp=${new Date().getTime()}`; // 添加时间戳防止缓存
  196. // exportFile.href = ` https://file.ailien.shop/excel/generate/storeCashOutRecord4.xlsx?timestamp=${new Date().getTime()}`; // 添加时间戳防止缓存
  197. https: document.body.appendChild(exportFile);
  198. exportFile.click();
  199. // 去除下载对 url 的影响
  200. document.body.removeChild(exportFile);
  201. ElMessage.success("下载成功");
  202. }
  203. };
  204. //审批状态
  205. const approve = async (approvalStatus: number, row: StoreUser.ResStoreUserList) => {
  206. if (!row.expirationTime) {
  207. ElMessage.error("请先选择商铺的到期时间");
  208. return;
  209. }
  210. let approvalStatusStr = approvalStatus == 1 ? "通过" : "拒绝";
  211. approvalStatusStr += "【" + row.storeName + "】商铺申请?";
  212. await useHandleData(approveStoreInfo, { id: row.id, approvalStatus: approvalStatus }, approvalStatusStr);
  213. proTable.value?.getTableList();
  214. };
  215. // 表格拖拽排序
  216. const sortTable = ({ newIndex, oldIndex }: { newIndex?: number; oldIndex?: number }) => {
  217. console.log(newIndex, oldIndex);
  218. console.log(proTable.value?.tableData);
  219. ElMessage.success("修改列表排序成功");
  220. };
  221. // ProTable 实例
  222. const proTable = ref<ProTableInstance>();
  223. // 如果表格需要初始化请求参数,直接定义传给 ProTable (之后每次请求都会自动带上该参数,此参数更改之后也会一直带上,改变此参数会自动刷新表格数据)
  224. const initParam = reactive({ type: 1 });
  225. // dataCallback 是对于返回的表格数据做处理,如果你后台返回的数据不是 list && total 这些字段,可以在这里进行处理成这些字段
  226. // 或者直接去 hooks/useTable.ts 文件中把字段改为你后端对应的就行
  227. const dataCallback = (data: any) => {
  228. return {
  229. list: data.records,
  230. total: data.total
  231. };
  232. };
  233. // 如果你想在请求之前对当前请求参数做一些操作,可以自定义如下函数:params 为当前所有的请求参数(包括分页),最后返回请求列表接口
  234. // 默认不做操作就直接在 ProTable 组件上绑定 :requestApi="getUserList"
  235. const getTableList = (params: any) => {
  236. let newParams = JSON.parse(JSON.stringify(params));
  237. // newParams.createTime && (newParams.startTime = newParams.createTime[0]);
  238. // newParams.createTime && (newParams.endTime = newParams.createTime[1]);
  239. // delete newParams.createTime;
  240. return getStoreInfoList(newParams);
  241. };
  242. // 门店审核状态列表
  243. const storeApplicationStatus = ref<any[]>([
  244. { value: 0, label: "待审核" },
  245. { value: 1, label: "审核通过" },
  246. { value: 2, label: "审核拒绝" }
  247. ]);
  248. // 门店状态列表
  249. const storeStatuss = ref<any[]>([
  250. { value: 1, label: "正常" },
  251. { value: 0, label: "禁用" },
  252. { value: 2, label: "已注销" }
  253. ]);
  254. //获取审批状态列表
  255. const getAuditStatus = computed((params: any) => {
  256. const list: any = [];
  257. list.push({ auditLabel: "待审核", auditValue: "0" });
  258. list.push({ auditLabel: "审核通过", auditValue: "1" });
  259. list.push({ auditLabel: "审核拒绝", auditValue: "2" });
  260. return list;
  261. });
  262. // 经营板块列表
  263. const businessSectionList = ref<any[]>([]);
  264. const getBusinessSectionList = async () => {
  265. const res = await getBusinessSection();
  266. const addData: any[] = [];
  267. const data = (res as any)?.data ?? [];
  268. data.forEach((element: any) => {
  269. addData.push({
  270. value: Number(element.dictId),
  271. label: element.dictDetail,
  272. parentId: element.parentId
  273. });
  274. });
  275. businessSectionList.value = addData;
  276. };
  277. // 表格配置项
  278. const columns = reactive<ColumnProps<StoreUser.ResStoreUserList>[]>([
  279. { type: "selection", fixed: "left" },
  280. { prop: "id", label: "商铺ID", search: { el: "input", tooltip: "请输入商铺id" } },
  281. { prop: "storeContact", label: "联系人" },
  282. { prop: "storePhone", label: "联系电话", search: { el: "input", tooltip: "请输入联系人电话" } },
  283. { prop: "storeName", label: "店铺名称" },
  284. {
  285. prop: "businessSection",
  286. label: "经营板块",
  287. enum: businessSectionList,
  288. search: { el: "select" },
  289. fieldNames: { label: "label", value: "value" }
  290. },
  291. {
  292. prop: "createdTime",
  293. label: "创建时间",
  294. width: 180,
  295. search: {
  296. span: 2,
  297. props: { type: "datetimerange", valueFormat: "YYYY-MM-DD HH:mm:ss" },
  298. defaultValue: ["2022-11-12 11:35:00", "2022-12-12 11:35:00"]
  299. }
  300. },
  301. {
  302. prop: "storeApplicationStatus",
  303. label: "审核状态 ",
  304. search: { el: "select" },
  305. enum: storeApplicationStatus,
  306. fieldNames: { label: "label", value: "value" }
  307. },
  308. {
  309. prop: "storeStatus",
  310. label: "状态 ",
  311. enum: storeStatuss,
  312. fieldNames: { label: "label", value: "value" }
  313. },
  314. // { prop: "storeTypeStr", label: "经营类型" },
  315. // { prop: "businessStatusStr", label: "状态" },
  316. { prop: "operation", label: "操作", fixed: "right", width: 330 }
  317. ]);
  318. // 打开 drawer(新增、查看、编辑)
  319. const drawerRef = ref<InstanceType<typeof StoreUserDrawer> | null>(null);
  320. const openDrawer = (title: string, row: Partial<StoreUser.ResStoreUserList> = {}) => {
  321. const params = {
  322. title,
  323. isView: title === "查看",
  324. row: { ...row },
  325. api: title === "新增" ? addStoreUser : title === "编辑" ? editStoreUser : undefined,
  326. getTableList: proTable.value?.getTableList
  327. };
  328. drawerRef.value?.acceptParams(params);
  329. };
  330. // 删除商户信息
  331. const deleteAccount = async (params: StoreUser.ResStoreUserList) => {
  332. await useHandleData(deleteStoreInfo, { id: params.id }, `删除【${params.storeName}】商铺与管理账户`);
  333. proTable.value?.getTableList();
  334. };
  335. // 重置用户密码
  336. const resetPass = async (params: StoreUser.ResStoreUserList) => {
  337. await useHandleData(resetStoreUserPassWord, { id: params.id }, `重置【${params.storeName}】】商铺与管理账户密码`);
  338. proTable.value?.getTableList();
  339. };
  340. //跳转至新增页面
  341. const handleToDetail = (type: string, id?: string) => {
  342. router.push({
  343. path: `/store/storeInfo/storeInfoDetail`,
  344. query: {
  345. id: id,
  346. type: type
  347. }
  348. });
  349. // router.push(`/store/storeInfo/storeInfoDetail`);
  350. };
  351. onMounted(async () => {
  352. //获取商铺经营板块
  353. await getBusinessSectionList();
  354. await getTableList({});
  355. });
  356. onActivated(() => {
  357. proTable.value?.getTableList();
  358. });
  359. //抽成比例部分
  360. const ccValue = ref(30);
  361. const ccValuefix = ref(30);
  362. const drawer = ref(false);
  363. const direction = ref<DrawerProps["direction"]>("rtl");
  364. function cancelClick() {
  365. drawer.value = false;
  366. }
  367. const storeId = ref("");
  368. const confirmClick = async () => {
  369. let params = {
  370. id: storeId.value,
  371. commissionRate: ccValue.value
  372. };
  373. let res = await updateStoreCommissionRate(params);
  374. if (res.code == "200") {
  375. ElMessage.success("设置抽成比例成功!");
  376. ccValuefix.value = ccValue.value;
  377. drawer.value = false;
  378. proTable.value?.getTableList();
  379. } else {
  380. ElMessage.error("设置抽成比例失败!");
  381. }
  382. };
  383. //这个是为了不让输入框输入超过100%
  384. function changeCCValue() {
  385. if (ccValue.value < 0) {
  386. ccValue.value = 0;
  387. } else if (ccValue.value > 100) {
  388. ccValue.value = 100;
  389. }
  390. }
  391. //点击抽成百分比
  392. const handleCC = (item: any) => {
  393. console.log(item, "点击抽成百分比");
  394. storeId.value = item.id;
  395. ccValue.value = item.commissionRate;
  396. ccValuefix.value = item.commissionRate;
  397. drawer.value = true;
  398. };
  399. const jjValue = ref<any>({});
  400. // 点击拒接
  401. const jj = (item: any) => {
  402. dialogFormVisible.value = true;
  403. form.reason = "";
  404. jjValue.value = item;
  405. };
  406. // 点击拒绝确定
  407. const jjQd = async () => {
  408. let res = await approveStoreInfo({
  409. id: jjValue.value.id,
  410. approvalStatus: 2,
  411. reason: form.reason
  412. });
  413. if (res.code == "200") {
  414. dialogFormVisible.value = false;
  415. proTable.value?.getTableList();
  416. ElMessage.success("审核拒绝成功!");
  417. } else {
  418. ElMessage.error("审核拒绝失败!");
  419. }
  420. };
  421. </script>
  422. <style scoped lang="scss">
  423. .topTitle {
  424. width: 100%;
  425. padding: 14px;
  426. margin-bottom: 4vh;
  427. font-weight: 600;
  428. color: white;
  429. background-color: rgb(64 149 229);
  430. border-radius: 6px;
  431. }
  432. .inputcc {
  433. margin-bottom: 4vh;
  434. > span {
  435. display: block;
  436. margin-bottom: 8px;
  437. }
  438. }
  439. .zysx {
  440. padding: 16px;
  441. font-family: serif;
  442. font-weight: 400;
  443. color: black;
  444. background-color: rgb(212 212 212);
  445. border-radius: 6px;
  446. > span {
  447. display: block;
  448. margin-bottom: 8px;
  449. }
  450. }
  451. .zysx2 {
  452. font-family: serif;
  453. background-color: rgb(240 187 125);
  454. > div {
  455. margin-left: 1.5%;
  456. }
  457. }
  458. ::v-deep .el-drawer__footer {
  459. > div {
  460. display: flex;
  461. justify-content: space-around;
  462. button {
  463. width: 6vw;
  464. }
  465. }
  466. }
  467. </style>