friendCoupon.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. <template>
  2. <div class="table-box button-table friend-coupon-container">
  3. <ProTable
  4. ref="proTable"
  5. :columns="columns"
  6. :request-api="getTableList"
  7. :init-param="initParam"
  8. :data-callback="dataCallback"
  9. :key="activeName"
  10. >
  11. <!-- 表格 header 按钮 -->
  12. <template #tableHeader="scope">
  13. <div class="table-header-content">
  14. <!-- <div class="header-button">
  15. <el-button type="primary" @click="openGiftDialog"> 赠送好友优惠券 </el-button>
  16. </div> -->
  17. <el-tabs v-model="activeName" class="header-tabs" @tab-click="handleTabClick">
  18. <el-tab-pane label="好友赠我" name="friendMessage" />
  19. <el-tab-pane label="我赠好友" name="myGift" />
  20. </el-tabs>
  21. </div>
  22. </template>
  23. <!-- 表格操作 -->
  24. <template #operation="scope">
  25. <el-button link type="primary" @click="viewDetail(scope.row)"> 查看详情 </el-button>
  26. <el-button v-if="activeName === 'myGift'" link type="primary" @click="deleteRow(scope.row)"> 删除 </el-button>
  27. </template>
  28. </ProTable>
  29. <!-- 赠送好友优惠券对话框 -->
  30. <el-dialog v-model="giftDialogVisible" title="赠送好友优惠券" width="600px" @close="closeGiftDialog">
  31. <el-form ref="giftFormRef" :model="giftFormData" :rules="giftRules" label-width="120px">
  32. <el-form-item label="选择好友" prop="friendId">
  33. <el-select v-model="giftFormData.friendId" placeholder="请选择好友" style="width: 100%" :loading="friendListLoading">
  34. <el-option v-for="friend in friendList" :key="friend.id" :label="friend.name" :value="friend.id" />
  35. </el-select>
  36. </el-form-item>
  37. <el-form-item label="选择优惠券" prop="couponId">
  38. <el-select
  39. v-model="giftFormData.couponId"
  40. placeholder="请选择优惠券"
  41. style="width: 100%"
  42. :loading="couponListLoading"
  43. @focus="loadCouponList"
  44. @change="handleCouponChange"
  45. >
  46. <el-option v-for="coupon in couponList" :key="coupon.id" :label="coupon.name" :value="coupon.id" />
  47. </el-select>
  48. <div v-if="giftFormData.couponId" class="coupon-info">
  49. <span>请输入赠送数量</span>
  50. </div>
  51. </el-form-item>
  52. <el-form-item v-if="giftFormData.couponId" label="赠送数量" prop="quantity">
  53. <el-input-number v-model="giftFormData.quantity" :min="1" :max="100" placeholder="请输入数量" style="width: 100%" />
  54. </el-form-item>
  55. </el-form>
  56. <template #footer>
  57. <div class="dialog-footer">
  58. <el-button @click="closeGiftDialog"> 取消 </el-button>
  59. <el-button type="primary" @click="handleGiftSubmit"> 确定 </el-button>
  60. </div>
  61. </template>
  62. </el-dialog>
  63. </div>
  64. </template>
  65. <script setup lang="tsx" name="friendCoupon">
  66. import { computed, onMounted, reactive, ref } from "vue";
  67. import { useRouter } from "vue-router";
  68. import type { FormInstance, FormRules } from "element-plus";
  69. import { ElMessage, ElMessageBox } from "element-plus";
  70. import ProTable from "@/components/ProTable/index.vue";
  71. import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
  72. import { localGet } from "@/utils";
  73. import { getFriendCouponList, getMutualAttention, getCouponList, setFriendCoupon } from "@/api/modules/newLoginApi";
  74. const router = useRouter();
  75. // 当前激活的标签页
  76. const activeName = ref("friendMessage");
  77. // ProTable 实例
  78. const proTable = ref<ProTableInstance>();
  79. // 赠送对话框
  80. const giftDialogVisible = ref(false);
  81. const giftFormRef = ref<FormInstance>();
  82. // 好友列表
  83. const friendList = ref<any[]>([]);
  84. const friendListLoading = ref(false);
  85. const friendListLoaded = ref(false); // 标记是否已加载
  86. // 优惠券列表
  87. const couponList = ref<any[]>([]);
  88. const couponListLoading = ref(false);
  89. const couponListLoaded = ref(false); // 标记是否已加载
  90. // 加载好友列表
  91. const loadFriendList = async () => {
  92. // 如果已经加载过,则不重复加载
  93. if (friendListLoaded.value || friendListLoading.value) {
  94. return;
  95. }
  96. friendListLoading.value = true;
  97. try {
  98. const res: any = await getMutualAttention({
  99. page: 1,
  100. size: 999, // 获取所有好友
  101. fansId: "store_" + localGet("geeker-user")?.userInfo?.phone
  102. });
  103. if (res.code === 200) {
  104. friendList.value = res.data.records.map((item: any) => ({
  105. id: item.id,
  106. name: item.username
  107. }));
  108. friendListLoaded.value = true;
  109. } else {
  110. // 如果接口失败,使用模拟数据
  111. friendList.value = [];
  112. friendListLoaded.value = true;
  113. }
  114. } catch (error) {
  115. console.error("加载好友列表失败:", error);
  116. // 使用模拟数据作为备用
  117. friendList.value = [];
  118. friendListLoaded.value = true;
  119. } finally {
  120. friendListLoading.value = false;
  121. }
  122. };
  123. // 加载优惠券列表
  124. const loadCouponList = async () => {
  125. // 如果已经加载过,则不重复加载
  126. if (couponListLoaded.value || couponListLoading.value) {
  127. return;
  128. }
  129. couponListLoading.value = true;
  130. try {
  131. const res: any = await getCouponList({
  132. storeId: localGet("createdId"),
  133. status: 0
  134. });
  135. if (res.code === 200) {
  136. couponList.value = res.data.map((item: any) => ({
  137. id: item.id,
  138. name: item.name
  139. }));
  140. couponListLoaded.value = true;
  141. } else {
  142. // 如果接口失败,使用模拟数据
  143. couponList.value = [];
  144. couponListLoaded.value = true;
  145. }
  146. } catch (error) {
  147. console.error("加载优惠券列表失败:", error);
  148. // 使用模拟数据作为备用
  149. couponList.value = [];
  150. couponListLoaded.value = true;
  151. } finally {
  152. couponListLoading.value = false;
  153. }
  154. };
  155. // 赠送表单数据
  156. const giftFormData = reactive({
  157. friendId: "",
  158. couponId: "",
  159. quantity: 1
  160. });
  161. // 表单验证规则
  162. const giftRules = reactive<FormRules>({
  163. friendId: [{ required: true, message: "请选择好友", trigger: "change" }],
  164. couponId: [{ required: true, message: "请选择优惠券", trigger: "change" }],
  165. quantity: [{ required: true, message: "请输入赠送数量", trigger: "blur" }]
  166. });
  167. // 好友留言表格列配置
  168. const friendMessageColumns = reactive<ColumnProps<any>[]>([
  169. {
  170. prop: "storeName",
  171. label: "店铺名称",
  172. search: {
  173. el: "input"
  174. }
  175. },
  176. {
  177. prop: "couponName",
  178. label: "优惠券名称"
  179. },
  180. {
  181. prop: "nominalValue",
  182. label: "优惠券额",
  183. render: (scope: any) => {
  184. return `¥${scope.row.nominalValue || 0}`;
  185. }
  186. },
  187. {
  188. prop: "endDate",
  189. label: "有效期至",
  190. render: (scope: any) => {
  191. return scope.row.endDate?.replace(/-/g, "/") || "--";
  192. }
  193. },
  194. {
  195. prop: "couponNum",
  196. label: "优惠券数量"
  197. },
  198. { prop: "operation", label: "操作", fixed: "right", width: 200 }
  199. ]);
  200. // 我赠好友表格列配置
  201. const myGiftColumns = reactive<ColumnProps<any>[]>([
  202. {
  203. prop: "storeName",
  204. label: "店铺名称",
  205. search: {
  206. el: "input"
  207. }
  208. },
  209. {
  210. prop: "couponName",
  211. label: "优惠券名称"
  212. },
  213. {
  214. prop: "nominalValue",
  215. label: "优惠券额",
  216. render: (scope: any) => {
  217. return `¥${scope.row.nominalValue || 0}`;
  218. }
  219. },
  220. {
  221. prop: "endDate",
  222. label: "有效期至",
  223. render: (scope: any) => {
  224. return scope.row.endDate?.replace(/-/g, "/") || "--";
  225. }
  226. },
  227. {
  228. prop: "couponNum",
  229. label: "优惠券数量"
  230. },
  231. { prop: "operation", label: "操作", fixed: "right", width: 200 }
  232. ]);
  233. // 根据当前选中的tab动态返回列配置
  234. const columns = computed(() => {
  235. return activeName.value === "friendMessage" ? friendMessageColumns : myGiftColumns;
  236. });
  237. // 初始化请求参数 - 好友赠我传 storeUserId
  238. const initParam = reactive({
  239. storeUserId: localGet("createdId"), // 好友赠我:当前店铺ID(接收方)
  240. friendStoreUserId: undefined as number | undefined, // 我赠好友:当前用户ID(赠送方)
  241. type: activeName.value
  242. });
  243. // Tab切换处理
  244. const handleTabClick = () => {
  245. initParam.type = activeName.value;
  246. // 根据当前 tab 设置正确的参数
  247. if (activeName.value === "myGift") {
  248. // 好友赠我:传 storeUserId
  249. initParam.storeUserId = localGet("createdId");
  250. initParam.friendStoreUserId = undefined;
  251. } else {
  252. // 我赠好友:传 friendStoreUserId
  253. initParam.storeUserId = undefined;
  254. initParam.friendStoreUserId = localGet("geeker-user").userInfo.id;
  255. }
  256. proTable.value?.getTableList();
  257. };
  258. // dataCallback 是对于返回的表格数据做处理
  259. const dataCallback = (data: any) => {
  260. return {
  261. list: data || [],
  262. total: data?.length || 0
  263. };
  264. };
  265. // 获取表格列表
  266. const getTableList = (params: any) => {
  267. const newParams = {
  268. ...params,
  269. type: activeName.value === "friendMessage" ? 0 : 1 // 0-好友赠我,1-我赠好友
  270. };
  271. return getFriendCouponList(newParams);
  272. };
  273. // 打开赠送对话框
  274. const openGiftDialog = () => {
  275. giftDialogVisible.value = true;
  276. loadFriendList();
  277. loadCouponList();
  278. // 点击下拉框时才会加载数据(通过 @focus 事件触发)
  279. };
  280. // 关闭赠送对话框
  281. const closeGiftDialog = () => {
  282. giftDialogVisible.value = false;
  283. giftFormRef.value?.resetFields();
  284. Object.assign(giftFormData, {
  285. friendId: "",
  286. couponId: "",
  287. quantity: 1
  288. });
  289. // 重置加载状态,下次打开时重新加载
  290. friendListLoaded.value = false;
  291. couponListLoaded.value = false;
  292. };
  293. // 优惠券改变时
  294. const handleCouponChange = (val: string) => {
  295. giftFormData.quantity = 1;
  296. };
  297. // 提交赠送
  298. const handleGiftSubmit = async () => {
  299. if (!giftFormRef.value) return;
  300. await giftFormRef.value.validate(async (valid: boolean) => {
  301. if (valid) {
  302. try {
  303. // 调用赠送接口
  304. const params = {
  305. couponIds: [
  306. {
  307. couponId: giftFormData.couponId,
  308. singleQty: giftFormData.quantity
  309. }
  310. ],
  311. friendStoreUserId: String(giftFormData.friendId)
  312. };
  313. const res: any = await setFriendCoupon(params);
  314. if (res && res.code === 200) {
  315. ElMessage.success("赠送成功");
  316. closeGiftDialog();
  317. proTable.value?.getTableList();
  318. } else {
  319. ElMessage.error(res?.msg || "赠送失败");
  320. }
  321. } catch (error: any) {
  322. console.error("赠送失败:", error);
  323. ElMessage.error(error?.message || "赠送失败");
  324. }
  325. }
  326. });
  327. };
  328. // 查看详情
  329. const viewDetail = (row: any) => {
  330. router.push({
  331. path: "/dynamicManagement/friendCouponDetail",
  332. query: {
  333. couponId: row.couponId,
  334. type: activeName.value
  335. }
  336. });
  337. };
  338. // 删除行数据
  339. const deleteRow = (row: any) => {
  340. ElMessageBox.confirm("确定要删除这条赠送记录吗?", "提示", {
  341. confirmButtonText: "确定",
  342. cancelButtonText: "取消",
  343. type: "warning"
  344. })
  345. .then(async () => {
  346. try {
  347. // TODO: 集成真实接口时,取消下面的注释
  348. // await deleteFriendCoupon({ id: row.id });
  349. ElMessage.success("删除成功");
  350. proTable.value?.getTableList();
  351. } catch (error) {
  352. ElMessage.error("删除失败");
  353. }
  354. })
  355. .catch(() => {
  356. // 用户取消删除
  357. });
  358. };
  359. // 页面加载时触发查询
  360. onMounted(() => {
  361. proTable.value?.getTableList();
  362. });
  363. </script>
  364. <style lang="scss" scoped>
  365. .friend-coupon-container {
  366. .table-header-content {
  367. display: flex;
  368. flex-direction: column;
  369. gap: 16px;
  370. .header-tabs {
  371. :deep(.el-tabs__nav-wrap::after) {
  372. height: 0;
  373. }
  374. }
  375. .header-button {
  376. display: flex;
  377. justify-content: flex-start;
  378. }
  379. }
  380. .coupon-info {
  381. margin-top: 8px;
  382. font-size: 12px;
  383. color: #909399;
  384. }
  385. .dialog-footer {
  386. display: flex;
  387. gap: 10px;
  388. justify-content: flex-end;
  389. }
  390. }
  391. </style>