feat:退款,支付返回
This commit is contained in:
1 parent
41d3b01c24
commit
68349eb8c0
17 files changed
+1092
-491
No files matched your search
@@ -25,17 +25,17 @@ VITE_OAUTH2_APP_CLIENT='mini:mini'
|
||||
# VITE_ZZD_CORP_ID=
|
||||
|
||||
# --------------------------- 开发环境 api地址 ----------------------------------
|
||||
VITE_APP_DEV_SERVICE = https://stgl.pj.gov.cn/api # 域名线上
|
||||
# VITE_APP_DEV_SERVICE = https://stgl.pj.gov.cn/api # 域名线上
|
||||
#VITE_APP_DEV_SERVICE = http://59.202.170.152:81/api # 信创线上
|
||||
# VITE_APP_DEV_SERVICE = https://dzc-test-1.fy.takin.cc # 邓-本地
|
||||
VITE_APP_DEV_SERVICE = https://dzc-test-1.fy.takin.cc # 邓-本地
|
||||
# VITE_APP_DEV_SERVICE = http://127.0.0.1:9999 # 邓-本地
|
||||
# VITE_APP_DEV_SERVICE = http://123.157.250.162:8089/api # 测试线上
|
||||
|
||||
# --------------------------- 开发环境 图片访问基础地址 ---------------------------
|
||||
# VITE_IMAGE_DEV_PATH = https://stgl.pj.gov.cn/api # 域名线上
|
||||
#VITE_IMAGE_DEV_PATH = http://59.202.170.152:81/api # 信创线上
|
||||
#VITE_IMAGE_DEV_PATH = https://dzc-test-1.fy.takin.cc # 邓-本地
|
||||
VITE_IMAGE_DEV_PATH = http://127.0.0.1:9999
|
||||
VITE_IMAGE_DEV_PATH = https://dzc-test-1.fy.takin.cc # 邓-本地
|
||||
# VITE_IMAGE_DEV_PATH = http://127.0.0.1:9999
|
||||
# VITE_IMAGE_DEV_PATH = http://123.157.250.162:8089/api # 测试线上
|
||||
|
||||
# --------------------------- 生产环境 api地址 ----------------------------------
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref, watch } from "vue"
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
|
||||
import { individualOrderApi } from "@@/api/index"
|
||||
|
||||
|
||||
const emit = defineEmits(["confirm"])
|
||||
|
||||
const rejectFormRef = ref<any>()
|
||||
const state = reactive<any>({
|
||||
show: false,
|
||||
apptList: [],
|
||||
refundDetail: [],
|
||||
})
|
||||
|
||||
const rejectForm = reactive<any>({
|
||||
id: '',
|
||||
auditReason: "",
|
||||
})
|
||||
const rejectFormRules = reactive<any>({
|
||||
auditReason: [{ required: true, message: "请输入拒绝原因" }],
|
||||
})
|
||||
|
||||
const open = (refundDetail: any) => {
|
||||
state.show = true
|
||||
state.refundDetail = refundDetail
|
||||
}
|
||||
|
||||
// 同意退款
|
||||
const doAgreeRefund = async () => {
|
||||
if (!state.refundDetail.id) {
|
||||
return uni.showToast({ title: "订单不存在", icon: "none" })
|
||||
}
|
||||
rejectFormRef.value.submit()
|
||||
const { isPass } = rejectFormRef.value.validate()
|
||||
if (!isPass) return
|
||||
state.show = false
|
||||
uni.showLoading({ title: "操作中...", mask: true })
|
||||
try {
|
||||
const res: any = await individualOrderApi.refuseRefund({ id: state.refundDetail.id, auditReason: rejectForm.auditReason })
|
||||
if (res.code == 0) {
|
||||
uni.showToast({ title: "操作成功", icon: "success" })
|
||||
state.show = false
|
||||
emit("confirm")
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || "退款失败", icon: "none" })
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({ title: "错误", icon: "none" })
|
||||
} finally {
|
||||
uni.hideLoading()
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<tm-drawer v-model:show="state.show" showClose :showCancel="false" showFooter bgColor="#EAF2FE" title="确认预约"
|
||||
size="50%" position="bottom" confirmText="拒绝退款">
|
||||
<view class="h-20rpx" />
|
||||
<tm-form ref="rejectFormRef" v-model="rejectForm" :rules="rejectFormRules" direction="vertical">
|
||||
<tm-form-item name="auditReason" label="拒绝原因" :showBottom="false">
|
||||
<tm-input v-model="rejectForm.auditReason" type="textarea" :showClear="false" placeholder="请输入拒绝原因.." />
|
||||
</tm-form-item>
|
||||
</tm-form>
|
||||
<template #footer>
|
||||
<view class="bg-red p-y-20rpx text-center rounded-20rpx mx-30rpx m-y-10rpx sub-text-30 color-white!"
|
||||
@tap="doAgreeRefund">
|
||||
拒绝退款
|
||||
</view>
|
||||
</template>
|
||||
</tm-drawer>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
+87
-14
@@ -1,18 +1,40 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive } from "vue"
|
||||
import { computed, reactive, ref } from "vue"
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
import { isEmpty } from "radash"
|
||||
|
||||
import { hooks, router } from "@@/index"
|
||||
import { orderApi, refundApi } from "@@/api"
|
||||
import { hooks, router, constant } from "@@/index"
|
||||
import { orderApi, refundApi, individualOrderApi } from "@@/api"
|
||||
|
||||
import { filePath } from "@@/utils/file"
|
||||
import { hasRoleCode, MCH_USER } from "@@/utils/user-role"
|
||||
|
||||
import RejectChechk from "./components/reject-chechk.vue"
|
||||
|
||||
const rejectChechkRef = ref<any>()
|
||||
const state = reactive<any>({
|
||||
detailId: null,
|
||||
detail: {},
|
||||
refundDetail: {},
|
||||
shopCarList: [],
|
||||
currentUser: {}
|
||||
})
|
||||
|
||||
const applyPicUrlList = computed(() => {
|
||||
return state.refundDetail?.applyPicUrls?.split(',') ?? []
|
||||
})
|
||||
|
||||
const isCheckRefund = computed(() => {
|
||||
const orderUserId = state.detail?.userId
|
||||
const currentUserId = state.currentUser?.sysUser?.userId
|
||||
return hasRoleCode(MCH_USER) && orderUserId != currentUserId && state.refundDetail.status == '10'
|
||||
})
|
||||
|
||||
|
||||
const isUserOperation = computed(() => {
|
||||
const orderUserId = state.detail?.userId
|
||||
const currentUserId = state.currentUser?.sysUser?.userId
|
||||
return orderUserId == currentUserId
|
||||
})
|
||||
|
||||
onLoad((options: any) => {
|
||||
@@ -21,9 +43,14 @@ onLoad((options: any) => {
|
||||
}
|
||||
})
|
||||
onShow(() => {
|
||||
refresh()
|
||||
})
|
||||
|
||||
const refresh = () => {
|
||||
getCurrentUserDetail()
|
||||
getDetail()
|
||||
getShopCarList()
|
||||
})
|
||||
}
|
||||
|
||||
const getDetail = async () => {
|
||||
if (isEmpty(state.detailId)) return
|
||||
@@ -35,6 +62,13 @@ const getDetail = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const getCurrentUserDetail = () => {
|
||||
const userInfo: any = uni.getStorageSync(constant.storageConstant.USERINFO) || {}
|
||||
if (userInfo) {
|
||||
state.currentUser = userInfo
|
||||
}
|
||||
}
|
||||
|
||||
const getShopCarList = async () => {
|
||||
if (isEmpty(state.detailId)) return
|
||||
const _pa = { orderId: state.detailId }
|
||||
@@ -65,6 +99,23 @@ const doCancelRefund = async () => {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const doAgreeRefund = async () => {
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "是否确定同意退款",
|
||||
confirmColor: "#0094ff",
|
||||
success: async (res) => {
|
||||
if (!res.confirm) return
|
||||
uni.showLoading({ title: "操作中...", mask: false })
|
||||
const _pa = { id: state.refundDetail.id }
|
||||
await individualOrderApi.agreeRefund(_pa)
|
||||
refresh()
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: "同意成功", icon: "none" })
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -170,6 +221,13 @@ const doCancelRefund = async () => {
|
||||
<view>售后类型:</view>
|
||||
<view>{{ state.refundDetail.applyReason }}</view>
|
||||
</view>
|
||||
<view v-if="applyPicUrlList && applyPicUrlList.length" class="flex-row items-center">
|
||||
<view>补充图片:</view>
|
||||
<view class="flex items-center gap-10rpx">
|
||||
<image v-for="(v, i) in applyPicUrlList" :key="i" class="size-100rpx rounded-8rpx"
|
||||
:src="filePath(v)" mode="scaleToFill" @tap="hooks.usePreviewImage(filePath(v))" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row items-center">
|
||||
<view>相关描述:</view>
|
||||
<view>{{ state.refundDetail.applyDescription }}</view>
|
||||
@@ -194,18 +252,33 @@ const doCancelRefund = async () => {
|
||||
<!-- end 退款相关 end -->
|
||||
<view class="h-30rpx" />
|
||||
<template #main-bottom>
|
||||
<view v-if="state.detail.orderStatus == 10 && state.refundDetail.status == 10"
|
||||
class="bg-#999 p-y-20rpx text-center rounded-40rpx m-x-30rpx m-y-30rpx sub-text-30 color-white!"
|
||||
@tap="doCancelRefund">
|
||||
取消申请
|
||||
</view>
|
||||
<view v-else-if="state.refundDetail.status == 62 || state.refundDetail.status == 61"
|
||||
class="bg-#999 p-y-20rpx text-center rounded-40rpx m-x-30rpx m-y-30rpx sub-text-30 color-white!"
|
||||
@tap="router.jump('/pages/refund/apply', { id: state.detailId }, 2)">
|
||||
重新申请
|
||||
</view>
|
||||
<slot v-if="isCheckRefund">
|
||||
<view class="flex items-center mx-30rpx gap-30rpx">
|
||||
<view class="w-40% bg-red p-y-20rpx text-center rounded-40rpx m-y-30rpx sub-text-30 color-white!"
|
||||
@tap="rejectChechkRef.open(state.refundDetail)">
|
||||
拒绝退款
|
||||
</view>
|
||||
<view class="flex-1 bg-blue p-y-20rpx text-center rounded-40rpx m-y-30rpx sub-text-30 color-white!"
|
||||
@tap="doAgreeRefund">
|
||||
同意退款
|
||||
</view>
|
||||
</view>
|
||||
</slot>
|
||||
<slot v-else-if="isUserOperation">
|
||||
<view v-if="state.detail.orderStatus == 10 && state.refundDetail.status == 10"
|
||||
class="bg-#999 p-y-20rpx text-center rounded-40rpx m-x-30rpx m-y-30rpx sub-text-30 color-white!"
|
||||
@tap="doCancelRefund">
|
||||
取消申请
|
||||
</view>
|
||||
<view v-else-if="state.refundDetail.status == 62 || state.refundDetail.status == 61"
|
||||
class="bg-#999 p-y-20rpx text-center rounded-40rpx m-x-30rpx m-y-30rpx sub-text-30 color-white!"
|
||||
@tap="router.jump('/pages/refund/apply', { id: state.detailId }, 2)">
|
||||
重新申请
|
||||
</view>
|
||||
</slot>
|
||||
</template>
|
||||
</crud-layout>
|
||||
<reject-chechk ref="rejectChechkRef" @confirm="refresh" />
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -2,23 +2,12 @@
|
||||
<view class="w-full h-full">
|
||||
<view class="flex-col-center p-30rpx">
|
||||
<view class="flex-col-center m-y-50rpx">
|
||||
<svg
|
||||
t="1742978804614"
|
||||
class="icon"
|
||||
viewBox="0 0 1024 1024"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
p-id="1708"
|
||||
width="64"
|
||||
height="64"
|
||||
>
|
||||
<svg t="1742978804614" class="icon" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="1708" width="64" height="64">
|
||||
<path
|
||||
d="M512 0C230.4 0 0 230.4 0 512s230.4 512 512 512 512-230.4 512-512S793.6 0 512 0z m288 371.2L460.8 710.4c-6.4 6.4-19.2 12.8-25.6 12.8-12.8 0-19.2-6.4-25.6-12.8L224 531.2c-12.8-12.8-12.8-38.4 0-57.6 12.8-12.8 38.4-12.8 57.6 0l147.2 147.2L736 313.6c12.8-12.8 38.4-12.8 57.6 0 19.2 19.2 19.2 44.8 6.4 57.6z"
|
||||
fill="#2BCDA3"
|
||||
p-id="1709"
|
||||
data-spm-anchor-id="a313x.search_index.0.i2.beb13a81SVstw0"
|
||||
class="selected"
|
||||
></path>
|
||||
fill="#2BCDA3" p-id="1709" data-spm-anchor-id="a313x.search_index.0.i2.beb13a81SVstw0"
|
||||
class="selected"></path>
|
||||
</svg>
|
||||
<text class="text-36 mt-3 font-bold c-#333333!">支付成功</text>
|
||||
</view>
|
||||
@@ -46,19 +35,54 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue"
|
||||
import { reactive, ref } from "vue"
|
||||
import { onShow } from "@dcloudio/uni-app"
|
||||
import { usePayStore } from "@/sheep/stores/pay"
|
||||
import { merchantApi } from "@/sheep/api"
|
||||
|
||||
const scanPayData = ref<any>({})
|
||||
|
||||
onShow(() => {
|
||||
if (!usePayStore().scanPayData.mchId) return uni.showToast({ title: "支付信息不存在", icon: "none" })
|
||||
scanPayData.value = usePayStore().scanPayData
|
||||
const state = reactive<any>({
|
||||
mchDetail: {}
|
||||
})
|
||||
|
||||
onShow(async () => {
|
||||
if (!usePayStore().scanPayData.mchId) return uni.showToast({ title: "支付信息不存在", icon: "none" })
|
||||
scanPayData.value = usePayStore().scanPayData
|
||||
await getMchDetail(usePayStore().scanPayData.mchId)
|
||||
})
|
||||
|
||||
// 获取商户详情
|
||||
const getMchDetail = async (mchId: string) => {
|
||||
try {
|
||||
uni.showLoading({ title: "加载中" })
|
||||
const { data } = await merchantApi.detail({ id: mchId })
|
||||
console.log("获取商户详情成功:", data)
|
||||
state.mchDetail = data ?? {}
|
||||
} catch (error) {
|
||||
console.log("获取商户详情意外的错误error:", error);
|
||||
} finally {
|
||||
uni.hideLoading()
|
||||
}
|
||||
}
|
||||
|
||||
const goBack = () => {
|
||||
const url: string = window.location.href.split("h5")[0] + "h5/?launchParam=coopMerchant#/pages/tabbar/order"
|
||||
let launchParam = "coopMerchant"
|
||||
if (state.mchDetail?.types) {
|
||||
// 自营食堂
|
||||
if (state.mchDetail.types == "1") {
|
||||
launchParam = "canteen"
|
||||
}
|
||||
// 合作商家
|
||||
else if (state.mchDetail.types == "2") {
|
||||
launchParam = "coopMerchant"
|
||||
}
|
||||
// 自营商家
|
||||
else if (state.mchDetail.types == "2") {
|
||||
launchParam = "selfMerchant"
|
||||
}
|
||||
}
|
||||
const url: string = window.location.href.split("h5")[0] + `h5/?launchParam=${launchParam}#/pages/tabbar/order`
|
||||
window.location.replace(url)
|
||||
}
|
||||
</script>
|
||||
@@ -33,7 +33,8 @@
|
||||
</view>
|
||||
<!-- 金额限制提示 -->
|
||||
<view class="h-30rpx">
|
||||
<view v-if="storePrice(amount) > payStore.sourceWalletData?.balance" class="text-xs c-red px-4">注:转账金额不能超过钱包余额</view>
|
||||
<view v-if="storePrice(amount) > payStore.sourceWalletData?.balance" class="text-xs c-red px-4">
|
||||
注:转账金额不能超过钱包余额</view>
|
||||
</view>
|
||||
|
||||
<view class="font-bold mt-6">
|
||||
@@ -45,13 +46,10 @@
|
||||
|
||||
<!-- 选择转入方式 -->
|
||||
<tm-drawer v-model:show="show" title="选择钱包" size="auto" bg-color="#efefef" :show-footer="false" :showClose="true">
|
||||
<view
|
||||
v-for="(v, index) in wallet.walletList"
|
||||
:key="index"
|
||||
<view v-for="(v, index) in wallet.walletList" :key="index"
|
||||
class="card m-2 overflow-hidden relative border-4 border-solid border-white duration-200 flex justify-between items-center p-4"
|
||||
:class="{ 'border-4 border-solid border-blue!': targetWalletType.id == v.walletTypeId }"
|
||||
@click="selectTargetWalletType(v)"
|
||||
>
|
||||
@click="selectTargetWalletType(v)">
|
||||
<view class="flex items-center">
|
||||
<image class="w-70 h-70 mr-2" :src="filePath(v.walletTypeIcon)" />
|
||||
<view class="flex flex-col">
|
||||
|
||||
+14
-26
@@ -54,6 +54,8 @@ const getSetting = async () => {
|
||||
title: v,
|
||||
}
|
||||
})
|
||||
applyForm.reason = state.selectList[0].id
|
||||
applyForm.reasonStr = state.selectList[0].title
|
||||
}
|
||||
const getDetail = async () => {
|
||||
if (isEmpty(state.detailId)) return
|
||||
@@ -120,12 +122,8 @@ const doSubmit = async () => {
|
||||
<view class="h-30rpx" />
|
||||
<view class="flex-col justify-center card p-x-20rpx p-y-30rpx m-b-20rpx">
|
||||
<!-- <view class="m-t-15rpx"> -->
|
||||
<view
|
||||
class="flex-row items-start justify-between"
|
||||
v-for="(v, i) in state.shopCarList"
|
||||
:key="i"
|
||||
@tap.stop="router.jump('/pages/canteen/product-detail', { id: v.productId })"
|
||||
>
|
||||
<view class="flex-row items-start justify-between" v-for="(v, i) in state.shopCarList" :key="i"
|
||||
@tap.stop="router.jump('/pages/canteen/product-detail', { id: v.productId })">
|
||||
<view class="flex-row items-center">
|
||||
<image class="w-160rpx h-160rpx rounded-8rpx" :src="filePath(v.productPic)" mode="aspectFill" />
|
||||
<view class="flex-col m-l-15rpx second-text-26">
|
||||
@@ -152,7 +150,8 @@ const doSubmit = async () => {
|
||||
<view class="sub-text-28">售后类型</view>
|
||||
<view class="m-t-20rpx">
|
||||
<tm-radio-group @change="radioChange" direction="column" gap="20" v-model="applyForm.way">
|
||||
<tm-radio :disabled="v.disabled" v-for="(v, i) in data.payType" :key="i" v-show="v.visible" :value="v.type" :label="v.text" />
|
||||
<tm-radio :disabled="v.disabled" v-for="(v, i) in data.payType" :key="i" v-show="v.visible"
|
||||
:value="v.type" :label="v.text" />
|
||||
</tm-radio-group>
|
||||
</view>
|
||||
</view>
|
||||
@@ -161,13 +160,8 @@ const doSubmit = async () => {
|
||||
<view class="sub-text-28 color-red!">¥{{ hooks.useMoney(state.detail.payPrice) }}</view>
|
||||
</view>
|
||||
<view class="card p-x-20rpx p-y-30rpx m-b-20rpx">
|
||||
<tm-picker
|
||||
rang-key="title"
|
||||
rang-text="title"
|
||||
v-model="applyForm.reason"
|
||||
v-model:model-str="applyForm.reasonStr"
|
||||
:list="state.selectList"
|
||||
>
|
||||
<tm-picker rang-key="title" rang-text="title" v-model="applyForm.reason"
|
||||
v-model:model-str="applyForm.reasonStr" :list="state.selectList">
|
||||
<view class="flex-row items-center justify-between">
|
||||
<view class="sub-text-28">申请原因</view>
|
||||
<view class="flex-row items-center second-text-24">
|
||||
@@ -180,29 +174,23 @@ const doSubmit = async () => {
|
||||
<view class="flex-col justify-center card p-x-20rpx p-y-30rpx m-b-20rpx">
|
||||
<view class="sub-text-28">补充凭证图片</view>
|
||||
<view class="m-t-20rpx">
|
||||
<tm-upload-photo
|
||||
v-model="uploadApplyPicUrls"
|
||||
:maxFileSize="1024 * 1024 * 5"
|
||||
:url="'/api/admin/sys-file/upload'"
|
||||
:header="state.header"
|
||||
:maxCount="6"
|
||||
/>
|
||||
<tm-upload-photo v-model="uploadApplyPicUrls" :maxFileSize="1024 * 1024 * 5"
|
||||
:url="'/api/admin/sys-file/upload'" :header="state.header" :maxCount="6" />
|
||||
</view>
|
||||
<view class="sub-text-20 c-red!">注:图片大小不超过5M,最多上传6张</view>
|
||||
</view>
|
||||
<view class="flex-col justify-center card p-x-20rpx p-y-30rpx m-b-20rpx">
|
||||
<view class="sub-text-28">相关描述</view>
|
||||
<view class="m-t-20rpx">
|
||||
<tm-input v-model="applyForm.remark" type="textarea" :showClear="false" placeholder="客官~请描述您遇到的问题"></tm-input>
|
||||
<tm-input v-model="applyForm.remark" type="textarea" :showClear="false"
|
||||
placeholder="客官~请描述您遇到的问题"></tm-input>
|
||||
</view>
|
||||
</view>
|
||||
<view class="h-30rpx" />
|
||||
<template #main-bottom>
|
||||
<view
|
||||
v-if="state.detailType != 'view'"
|
||||
<view v-if="state.detailType != 'view'"
|
||||
class="bg-#0094ff p-y-20rpx text-center rounded-40rpx m-x-30rpx m-y-30rpx sub-text-30 color-white!"
|
||||
@tap="doSubmit"
|
||||
>
|
||||
@tap="doSubmit">
|
||||
提交申请
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -5,233 +5,67 @@
|
||||
:auto-scroll-to-top-when-reload="false" @scroll="pageHook.scroll">
|
||||
<template #top>
|
||||
<view class="h-30rpx" />
|
||||
<view class="flex justify-between items-center bg-white rounded-16rpx px-20rpx">
|
||||
<z-tabs :list="tabs" @change="tabChange" />
|
||||
<tm-between-time start="2020-1-1" end="2050-1-1" v-model="state.date"
|
||||
v-model:model-str="state.formatVal" @confirm="datePickerConfirm" format="YYYY-MM-DD"
|
||||
:quickDate="[]" drawerSize="900">
|
||||
<view class="mb-6rpx flex items-center gap-1">
|
||||
<image class="w-[30rpx] h-[30rpx]" src="@/static/page/filter.svg" />
|
||||
<view class="text-center second-text-28 text-30 whitespace-nowrap">筛选</view>
|
||||
<view class="bg-white rounded-16rpx px-20rpx my-20rpx">
|
||||
<view class="flex justify-between items-center">
|
||||
<z-tabs :list="tabs" @change="tabChange" />
|
||||
<tm-between-time start="2020-1-1" end="2050-1-1" v-model="state.date"
|
||||
v-model:model-str="state.formatVal" @confirm="datePickerConfirm" format="YYYY-MM-DD"
|
||||
:quickDate="[]" drawerSize="900">
|
||||
<view class="mb-6rpx flex items-center gap-1">
|
||||
<image class="w-[30rpx] h-[30rpx]" src="@/static/page/filter.svg" />
|
||||
<view class="text-center second-text-28 text-30 whitespace-nowrap">筛选</view>
|
||||
</view>
|
||||
</tm-between-time>
|
||||
</view>
|
||||
<view v-if="state.pa?.orderStatusCodes?.includes(10)"
|
||||
class="flex flex-items-center justify-between py-10rpx second-text-24 font-400!">
|
||||
<text>可筛选售后状态</text>
|
||||
<view class="flex-row-center flex-wrap-center">
|
||||
<view class="flex-row-center" v-for="(v, i) in refundStatusList" :key="v.id"
|
||||
@tap.stop="toggleRefundStatus(v.id)">
|
||||
<text :style="{ color: isRefundStatusActive(v.id) ? '#1677ff' : '' }">
|
||||
{{ v.name }}
|
||||
</text>
|
||||
<text class="w-1rpx h-22rpx bg-[#999] mx-8rpx" v-if="i < refundStatusList.length - 1" />
|
||||
</view>
|
||||
</view>
|
||||
</tm-between-time>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view class="h-20rpx" />
|
||||
|
||||
<view class="flex-col justify-center card p-3 m-b-20rpx" v-for="(v, i) in pageHook.list" :key="i">
|
||||
<view class="flex-row items-center">
|
||||
<image class="w-110rpx h-110rpx rounded-8rpx" :src="filePath(v.logoPic)" mode="aspectFill" />
|
||||
<view class="flex-1 m-l-20rpx">
|
||||
<view class="flex-row items-center justify-between">
|
||||
<view class="flex-row items-center">
|
||||
<view class="main-text-28">{{ v.merchantName }}</view>
|
||||
<view v-if="false"
|
||||
class="m-l-15rpx color-#999 font-size-26rpx! iconfont icon-youjiantou" />
|
||||
</view>
|
||||
<tm-tag v-if="v.orderStatus == 1" color="info" size="xs">未支付</tm-tag>
|
||||
<tm-tag v-if="v.orderStatus == 5" color="success" size="xs">已支付</tm-tag>
|
||||
<tm-tag v-if="v.orderStatus == 10" color="error" size="xs">售后</tm-tag>
|
||||
<tm-tag v-if="v.orderStatus == 20" size="xs">已核销</tm-tag>
|
||||
<tm-tag v-if="v.orderStatus == 30" color="info" size="xs">已取消(智能柜)</tm-tag>
|
||||
</view>
|
||||
<view class="flex justify-between items-center m-t-5rpx">
|
||||
<view class="second-text-22">
|
||||
<text>{{ v.username }}</text>
|
||||
<text class="m-l-10rpx">{{ v.userMobile }}</text>
|
||||
</view>
|
||||
<view class="second-text-22 h-30rpx">{{ hooks.useEnum("hardwareRefundStatusEnum",
|
||||
v.refundStatus) }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between items-center">
|
||||
<view class="second-text-22">
|
||||
<text>下单时间</text>
|
||||
<text class="m-l-10rpx">{{ hooks.useTime(v.createTime, "{y}-{m}-{d} {h}:{i}:{s}")
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="main-text-30 color-red! min-w-140rpx text-right">¥ {{
|
||||
hooks.useMoney(v.totalPrice) }}
|
||||
</view>
|
||||
<!-- <view class="second-text-24">共 {{ v.carList.length }} 件</view> -->
|
||||
</view>
|
||||
<view v-if="v.payType == '9'" class="sub-text-24">{{ v.productDesc }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-end items-center mt-1">
|
||||
<view v-if="v.orderType == '1' && v.refundStatus" class="ml-1 botder_btn"
|
||||
@tap.stop="refundDetail(v)">售后详情
|
||||
</view>
|
||||
<view v-if="v.orderStatus == '5' && v.orderType == '1' && v.payType != '9'" class="ml-1 botder_btn"
|
||||
@tap.stop="doIndividualRefund(v)">
|
||||
申请退款
|
||||
</view>
|
||||
</view>
|
||||
<view class="card rounded-24rpx bg-white p-20rpx pb-0rpx mb-20rpx" v-for="(v, index) in pageHook.list"
|
||||
:key="v.id">
|
||||
<order-car visibleUser :visibleMch="false" :cardetail="v" :footerOperate="['refund', 'qrCodeDetail']" />
|
||||
</view>
|
||||
</z-paging>
|
||||
|
||||
<tm-drawer title="退款" :showClose="true" size="90%" bgColor="#EBF6FF" v-model:show="state.showDrawer"
|
||||
zIndex="999">
|
||||
<view class="bg-white rounded-16rpx px-10rpx m-b-10rpx animate-both">
|
||||
<z-tabs :list="['同意退款', '拒绝退款']" bar-width="300" bar-height="0" :active-style="{
|
||||
width: '300rpx',
|
||||
height: '70rpx',
|
||||
backgroundColor: '#0779FDdd',
|
||||
color: '#000000',
|
||||
textAlign: 'center',
|
||||
lineHeight: '70rpx',
|
||||
fontWeight: 'bold',
|
||||
fontSize: '30rpx',
|
||||
borderRadius: '10rpx',
|
||||
marginTop: '10rpx',
|
||||
}" :inactive-style="{
|
||||
width: '300rpx',
|
||||
height: '70rpx',
|
||||
color: '#000000',
|
||||
textAlign: 'center',
|
||||
lineHeight: '70rpx',
|
||||
fontWeight: 'bold',
|
||||
fontSize: '30rpx',
|
||||
borderRadius: '10rpx',
|
||||
marginTop: '10rpx',
|
||||
}" @change="refundTabChange" />
|
||||
</view>
|
||||
|
||||
<view class="flex-col justify-center card p-x-15rpx p-y-25rpx m-b-10rpx">
|
||||
<view class="flex-row items-center">
|
||||
<image class="w-100rpx h-100rpx rounded-8rpx" :src="filePath(state.curOrder.logoPic)"
|
||||
mode="aspectFill" />
|
||||
<view class="flex-1 flex-col m-l-20rpx">
|
||||
<view class="flex-row items-center justify-between">
|
||||
<view class="flex-row items-center">
|
||||
<view class="main-text-28">{{ state.curOrder.merchantName }}</view>
|
||||
<view v-if="false"
|
||||
class="m-l-15rpx color-#999 font-size-26rpx! iconfont icon-youjiantou" />
|
||||
</view>
|
||||
<tm-tag v-if="state.curOrder.orderStatus == 1" color="info" size="xs">未支付</tm-tag>
|
||||
<tm-tag v-if="state.curOrder.orderStatus == 5" color="success" size="xs">已支付</tm-tag>
|
||||
<tm-tag v-if="state.curOrder.orderStatus == 10" color="error" size="xs">售后</tm-tag>
|
||||
<tm-tag v-if="state.curOrder.orderStatus == 20" size="xs">已核销</tm-tag>
|
||||
</view>
|
||||
<view class="flex justify-between items-center">
|
||||
<view class="flex flex-col">
|
||||
<view class="second-text-20">
|
||||
<text>{{ state.curOrder.username }}</text>
|
||||
<text class="m-l-10rpx">{{ state.curOrder.userMobile }}</text>
|
||||
</view>
|
||||
<view class="second-text-20">
|
||||
<text>下单时间</text>
|
||||
<text class="m-l-10rpx">
|
||||
{{ hooks.useTime(state.curOrder.createTime, "{y}-{m}-{d} {h}:{i}:{s}") }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex flex-col items-end justify-center m-t-5rpx">
|
||||
<view class="second-text-22">{{ hooks.useEnum("hardwareRefundStatusEnum",
|
||||
state.curOrder.refundStatus) }}</view>
|
||||
<view class="flex">
|
||||
<view v-if="state.curOrder.carList?.length"
|
||||
class="m-t-4rpx m-r-10rpx second-text-26">
|
||||
共 {{ state.curOrder.carList.length }} 件
|
||||
</view>
|
||||
<view class="main-text-30 color-red!">¥ {{ hooks.useMoney(state.curOrder.totalPrice)
|
||||
}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="flex-col justify-center card p-x-20rpx p-y-30rpx m-b-10rpx">
|
||||
<view class="flex-row items-center justify-between">
|
||||
<view class="sub-text-28">实付款</view>
|
||||
<view class="flex-row items-end">
|
||||
<view class="sub-text-28">¥</view>
|
||||
<view class="m-l-5rpx sub-text-28">{{ hooks.useMoney(state.curOrder.payPrice) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row items-center justify-between card p-x-20rpx p-y-30rpx m-b-10rpx">
|
||||
<view class="sub-text-28">退款金额</view>
|
||||
<view class="sub-text-28 color-red!">¥{{ hooks.useMoney(state.curOrder.payPrice) }}</view>
|
||||
</view>
|
||||
<view class="card p-x-20rpx p-y-30rpx space-y-10rpx m-b-10rpx second-text-24">
|
||||
<view class="flex-row items-center">
|
||||
<view>服务单号:</view>
|
||||
<view>{{ state.refundDetail.no }}</view>
|
||||
</view>
|
||||
<view class="flex-row items-center">
|
||||
<view>申请时间:</view>
|
||||
<view>{{ hooks.useTime(state.refundDetail.createTime, "") }}</view>
|
||||
</view>
|
||||
<view class="flex-row items-center">
|
||||
<view>售后类型:</view>
|
||||
<view>{{ state.refundDetail.applyReason }}</view>
|
||||
</view>
|
||||
<view class="flex-row items-center">
|
||||
<view>相关描述:</view>
|
||||
<view>{{ state.refundDetail.applyDescription }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="state.refundDetail.status == 62"
|
||||
class="card p-x-20rpx p-y-30rpx space-y-10rpx m-b-10rpx second-text-24">
|
||||
<view class="flex-row items-center">
|
||||
<view>审核人:</view>
|
||||
<view>{{ state.refundDetail.auditUsername }}</view>
|
||||
</view>
|
||||
<view class="flex-row items-center">
|
||||
<view>审核时间:</view>
|
||||
<view>{{ hooks.useTime(state.refundDetail.auditTime, "") }}</view>
|
||||
</view>
|
||||
<view class="flex-row items-center">
|
||||
<view>拒绝原因:</view>
|
||||
<view>{{ state.refundDetail.auditReason }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="state.refundScene === 1" class="flex-col justify-center card p-x-20rpx p-y-30rpx m-b-10rpx">
|
||||
<view class="sub-text-28">拒绝原因</view>
|
||||
<view class="m-t-20rpx">
|
||||
<tm-input v-model="state.remark" type="textarea" :showClear="false" placeholder="请描述拒绝原因" />
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="h-270rpx" />
|
||||
<view class="flex">
|
||||
<tm-modal v-if="state.refundScene === 0" style="flex: 1" height="250" title="确定同意退款吗?"
|
||||
:show-footer="true" @confirm="doAgreeRefund()">
|
||||
<template v-slot:trigger><tm-button block>同意退款</tm-button></template>
|
||||
</tm-modal>
|
||||
<tm-modal v-if="state.refundScene === 1" style="flex: 1" height="250" title="确定拒绝退款吗?"
|
||||
:show-footer="true" @confirm="doRefuseRefund()">
|
||||
<template v-slot:trigger><tm-button block color="danger">拒绝退款</tm-button></template>
|
||||
</tm-modal>
|
||||
</view>
|
||||
</tm-drawer>
|
||||
</crud-layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed } from "vue"
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
import { hooks, router } from "@@/index"
|
||||
import { hooks, router, constant } from "@@/index"
|
||||
import { filePath } from "@@/utils/file"
|
||||
import zTabs from "@@/components/other/z-tabs/z-tabs.vue"
|
||||
import { individualOrderApi, refundApi } from "@@/api"
|
||||
|
||||
import zTabs from "@@/components/other/z-tabs/z-tabs.vue"
|
||||
import OrderCar from "@/sheep/components/order/order-car.vue"
|
||||
|
||||
const pageRef = ref<any>(null)
|
||||
// 选项卡
|
||||
const tabs = [
|
||||
{ id: null, name: "全部", disabled: false },
|
||||
{ id: 5, name: "已支付", disabled: false },
|
||||
{ id: 10, name: "售后", disabled: false },
|
||||
{ pa: { orderStatusCodes: null }, name: "全部", disabled: false },
|
||||
{ pa: { orderStatusCodes: [5, 20, 200, 210, 220] }, name: "已支付", disabled: false },
|
||||
{ pa: { orderStatusCodes: [10] }, name: "售后", disabled: false },
|
||||
]
|
||||
const state = reactive<any>({
|
||||
pa: {
|
||||
orderStatus: tabs[0].id,
|
||||
...tabs[0].pa,
|
||||
// 售后状态筛选使用逗号拼接后的字符串,便于直接透传给分页接口。
|
||||
refundStatusCodes: [],
|
||||
createTimeList: [],
|
||||
},
|
||||
activeRefundStatusList: [],
|
||||
showDrawer: false,
|
||||
refundScene: 0,
|
||||
curOrder: {},
|
||||
@@ -240,6 +74,13 @@ const state = reactive<any>({
|
||||
date: [],
|
||||
formatVal: "",
|
||||
})
|
||||
const refundStatusList = computed(() => {
|
||||
const list = Object.keys(constant.serviceEnum.hardwareRefundStatusEnum).map((k) => ({
|
||||
id: k,
|
||||
name: constant.serviceEnum.hardwareRefundStatusEnum[k],
|
||||
})).filter((item) => item.id !== '0')
|
||||
return list
|
||||
})
|
||||
const formatVal = computed(() => (state.date.length === 2 ? state.formatVal : ""))
|
||||
|
||||
const pageHook = hooks.usePage(pageRef, individualOrderApi.page, null, "data.records")
|
||||
@@ -258,13 +99,17 @@ onShow(() => {
|
||||
|
||||
// 切换选项卡
|
||||
const tabChange = (e: number) => {
|
||||
state.pa.orderStatus = tabs[e].id
|
||||
const target = tabs[e]
|
||||
state.pa = target.pa
|
||||
// 只有“售后”tab 才需要售后状态筛选,切走时清空,避免影响其它状态查询。
|
||||
if (!target.pa?.orderStatusCodes?.includes(10)) {
|
||||
state.activeRefundStatusList = []
|
||||
state.pa.refundStatusCodes = []
|
||||
}
|
||||
pageRef.value.reload(true)
|
||||
}
|
||||
|
||||
const query = (page: number, pagesize: number) => {
|
||||
// const isLogin = hooks.useStaticCheckLogin()
|
||||
// if (!isLogin) return
|
||||
pageHook.startPage(page, pagesize, false, state.pa)
|
||||
}
|
||||
|
||||
@@ -278,92 +123,22 @@ const datePickerConfirm = (date: any) => {
|
||||
pageRef.value.reload(false)
|
||||
}
|
||||
|
||||
// 重置状态
|
||||
const resetState = () => {
|
||||
state.refundScene = 0
|
||||
state.curOrder = {}
|
||||
state.refundDetail = {}
|
||||
state.remark = ""
|
||||
// 售后状态支持多选:
|
||||
// - 已选中时再次点击可取消;
|
||||
// - 未选中时点击加入筛选;
|
||||
// - 最终同步成逗号分隔字符串给订单列表接口使用。
|
||||
const toggleRefundStatus = (statusId: string) => {
|
||||
const targetId = String(statusId)
|
||||
if (isRefundStatusActive(targetId)) {
|
||||
state.activeRefundStatusList = state.activeRefundStatusList.filter((id: string) => id !== targetId)
|
||||
} else {
|
||||
state.activeRefundStatusList = [...state.activeRefundStatusList, targetId]
|
||||
}
|
||||
state.pa.refundStatusCodes = state.activeRefundStatusList
|
||||
pageRef.value?.reload(true)
|
||||
}
|
||||
|
||||
// 点击售后详情
|
||||
const refundDetail = (v: any) => {
|
||||
router.jump("/pages/order/detail", { id: v.id })
|
||||
}
|
||||
|
||||
// 点击退款
|
||||
const doIndividualRefund = async (v: any) => {
|
||||
return router.jump("/pages/refund/apply", { id: v.id })
|
||||
|
||||
if (!v.id) return uni.showToast({ title: "订单id不存在", icon: "none" })
|
||||
|
||||
resetState()
|
||||
|
||||
state.curOrder = v
|
||||
state.showDrawer = true
|
||||
uni.showLoading({ title: "加载中...", mask: true })
|
||||
try {
|
||||
const res: any = await refundApi.get({ id: v.id })
|
||||
if (res.code == 0) {
|
||||
state.refundDetail = res.data
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || "加载退款详情失败", icon: "none" })
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({ title: "错误", icon: "none" })
|
||||
} finally {
|
||||
uni.hideLoading()
|
||||
}
|
||||
}
|
||||
|
||||
// 退款切换选项卡
|
||||
const refundTabChange = (e: number) => {
|
||||
state.refundScene = e
|
||||
}
|
||||
|
||||
// 同意退款
|
||||
const doAgreeRefund = async () => {
|
||||
if (!state.refundDetail.id) {
|
||||
return uni.showToast({ title: "订单不存在", icon: "none" })
|
||||
}
|
||||
|
||||
uni.showLoading({ title: "操作中...", mask: true })
|
||||
try {
|
||||
const res: any = await individualOrderApi.agreeRefund({ id: state.refundDetail.id })
|
||||
if (res.code == 0) {
|
||||
uni.showToast({ title: "操作成功", icon: "success" })
|
||||
state.showDrawer = false
|
||||
pageRef.value.reload(true)
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || "退款失败", icon: "none" })
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({ title: "错误", icon: "none" })
|
||||
} finally {
|
||||
uni.hideLoading()
|
||||
}
|
||||
}
|
||||
|
||||
// 拒绝退款
|
||||
const doRefuseRefund = async () => {
|
||||
if (!state.refundDetail.id) {
|
||||
return uni.showToast({ title: "订单不存在", icon: "none" })
|
||||
}
|
||||
|
||||
uni.showLoading({ title: "操作中...", mask: true })
|
||||
try {
|
||||
const res: any = await individualOrderApi.refuseRefund({ id: state.refundDetail.id, auditReason: state.remark })
|
||||
if (res.code == 0) {
|
||||
uni.showToast({ title: "操作成功", icon: "success" })
|
||||
state.showDrawer = false
|
||||
pageRef.value.reload(true)
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || "拒绝退款失败", icon: "none" })
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({ title: "错误", icon: "none" })
|
||||
} finally {
|
||||
uni.hideLoading()
|
||||
}
|
||||
const isRefundStatusActive = (statusId: string) => {
|
||||
return state.activeRefundStatusList?.includes(String(statusId))
|
||||
}
|
||||
</script>
|
||||
+63
-96
@@ -1,28 +1,41 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from "vue"
|
||||
import { ref, reactive, computed } from "vue"
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
|
||||
import { hooks, router } from "@@/index"
|
||||
import { hooks, router, constant } from "@@/index"
|
||||
import { orderApi } from "@@/api"
|
||||
|
||||
import { filePath } from "@@/utils/file"
|
||||
|
||||
import zTabs from "@@/components/other/z-tabs/z-tabs.vue"
|
||||
import OrderCar from "@/sheep/components/order/order-car.vue"
|
||||
import { getLaunchParam } from "@/sheep/utils/app"
|
||||
|
||||
const data = {
|
||||
tabs: [
|
||||
{ id: null, name: "全部", disabled: false },
|
||||
{ id: 1, name: "未支付", disabled: false },
|
||||
{ id: 5, name: "已支付", disabled: false },
|
||||
{ id: 10, name: "售后", disabled: false },
|
||||
{ id: 20, name: "已核销", disabled: false },
|
||||
{ pa: { orderStatusCodes: null }, name: "全部", disabled: false },
|
||||
{ pa: { orderStatusCodes: [200] }, name: "待发货", disabled: false },
|
||||
{ pa: { orderStatusCodes: [5, 210] }, name: "待使用", disabled: false },
|
||||
{ pa: { orderStatusCodes: [20, 220] }, name: "已核销", disabled: false },
|
||||
{ pa: { orderStatusCodes: [10] }, name: "售后", disabled: false },
|
||||
{ pa: { orderStatusCodes: [1] }, name: "待支付", disabled: false },
|
||||
{ pa: { orderStatusCodes: [30] }, name: "已关闭", disabled: false },
|
||||
],
|
||||
}
|
||||
const state = reactive<any>({
|
||||
pa: {
|
||||
orderStatus: data.tabs[0].id,
|
||||
...data.tabs[0].pa,
|
||||
// 售后状态筛选使用逗号拼接后的字符串,便于直接透传给分页接口。
|
||||
refundStatusCodes: [],
|
||||
},
|
||||
// 维护当前多选的售后状态,用于文字高亮和切换。
|
||||
activeRefundStatusList: [] as string[],
|
||||
})
|
||||
|
||||
const refundStatusList = computed(() => {
|
||||
const list = Object.keys(constant.serviceEnum.hardwareRefundStatusEnum).map((k) => ({
|
||||
id: k,
|
||||
name: constant.serviceEnum.hardwareRefundStatusEnum[k],
|
||||
})).filter((item) => item.id !== '0')
|
||||
return list
|
||||
})
|
||||
|
||||
onLoad(() => {
|
||||
@@ -36,9 +49,15 @@ onShow(async () => {
|
||||
pageRef.value.reload(false)
|
||||
}
|
||||
})
|
||||
|
||||
const doTab = (e: any) => {
|
||||
const target = data.tabs[e]
|
||||
state.pa.orderStatus = target.id
|
||||
state.pa = target.pa
|
||||
// 只有“售后”tab 才需要售后状态筛选,切走时清空,避免影响其它状态查询。
|
||||
if (!target.pa.orderStatusCodes?.includes(10)) {
|
||||
state.activeRefundStatusList = []
|
||||
state.pa.refundStatusCodes = []
|
||||
}
|
||||
pageRef.value.reload(true)
|
||||
}
|
||||
|
||||
@@ -47,9 +66,9 @@ const pageHook = hooks.usePage(
|
||||
pageRef,
|
||||
getLaunchParam() == "canteen" // 食堂
|
||||
? orderApi.caneenPage
|
||||
: getLaunchParam() == "selfMerchant"
|
||||
: getLaunchParam() == "selfMerchant" // 自营商户
|
||||
? orderApi.supPage
|
||||
: getLaunchParam() == "coopMerchant"
|
||||
: getLaunchParam() == "coopMerchant" // 合作商户
|
||||
? orderApi.supPage
|
||||
: getLaunchParam() == "onlineShop"
|
||||
? orderApi.supPage
|
||||
@@ -61,20 +80,27 @@ const pageHook = hooks.usePage(
|
||||
)
|
||||
const query = (page: number, pagesize: number) => {
|
||||
const isLogin = hooks.useStaticCheckLogin()
|
||||
|
||||
if (!isLogin) return
|
||||
pageHook.startPage(page, pagesize, false, state.pa)
|
||||
}
|
||||
|
||||
// 查看订单和核销码
|
||||
const doToDetail = (v: any) => {
|
||||
router.jump("/pages/order/detail", { id: v.id })
|
||||
// 售后状态支持多选:
|
||||
// - 已选中时再次点击可取消;
|
||||
// - 未选中时点击加入筛选;
|
||||
// - 最终同步成逗号分隔字符串给订单列表接口使用。
|
||||
const toggleRefundStatus = (statusId: string) => {
|
||||
const targetId = String(statusId)
|
||||
if (isRefundStatusActive(targetId)) {
|
||||
state.activeRefundStatusList = state.activeRefundStatusList.filter((id: string) => id !== targetId)
|
||||
} else {
|
||||
state.activeRefundStatusList = [...state.activeRefundStatusList, targetId]
|
||||
}
|
||||
state.pa.refundStatusCodes = state.activeRefundStatusList
|
||||
pageRef.value?.reload(true)
|
||||
}
|
||||
|
||||
const doAppraise = () => { }
|
||||
|
||||
const doRefund = (v: any) => {
|
||||
router.jump("/pages/refund/apply", { id: v.id })
|
||||
const isRefundStatusActive = (statusId: string) => {
|
||||
return state.activeRefundStatusList.includes(String(statusId))
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -86,83 +112,24 @@ const doRefund = (v: any) => {
|
||||
<template #top>
|
||||
<view class="bg-white rounded-16rpx px-20rpx my-20rpx">
|
||||
<z-tabs :list="data.tabs" @change="doTab" />
|
||||
<view v-if="state.pa.orderStatusCodes?.includes(10)"
|
||||
class="flex flex-items-center justify-between py-10rpx second-text-24 font-400!">
|
||||
<text>可筛选售后状态</text>
|
||||
<view class="flex-row-center flex-wrap-center">
|
||||
<view class="flex-row-center" v-for="(v, i) in refundStatusList" :key="v.id"
|
||||
@tap.stop="toggleRefundStatus(v.id)">
|
||||
<text :style="{ color: isRefundStatusActive(v.id) ? '#1677ff' : '' }">
|
||||
{{ v.name }}
|
||||
</text>
|
||||
<text class="w-1rpx h-22rpx bg-[#999] mx-8rpx" v-if="i < refundStatusList.length - 1" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view class="flex-col justify-center card p-3 m-b-20rpx" v-for="(v, i) in pageHook.list" :key="i">
|
||||
<view class="flex-row">
|
||||
<image class="size-130rpx rounded-8rpx" :src="filePath(v.logoPic)" mode="aspectFill" />
|
||||
<view class="flex-1 ml-20rpx">
|
||||
<view class="flex-row items-center justify-between">
|
||||
<view class="sub-text-30">{{ v.merchantName }}</view>
|
||||
<!-- <view class="m-l-15rpx color-#999 font-size-26rpx! iconfont icon-youjiantou" /> -->
|
||||
<tm-tag v-if="v.orderStatus == 1" color="info" size="s">未支付</tm-tag>
|
||||
<tm-tag v-if="v.orderStatus == 5" color="success" size="s">已支付</tm-tag>
|
||||
<tm-tag v-if="v.orderStatus == 10" color="error" size="s">售后</tm-tag>
|
||||
<tm-tag v-if="v.orderStatus == 20" size="s">已核销</tm-tag>
|
||||
<tm-tag v-if="v.orderStatus == 30" color="info" size="s">已取消(智能柜)</tm-tag>
|
||||
</view>
|
||||
<view class="flex-row items-center justify-between mt-5rpx second-text-24">
|
||||
<view>
|
||||
<text>下单时间</text>
|
||||
<text class="ml-10rpx">{{ hooks.useTime(v.createTime, "{y}-{m}-{d} {h}:{i}:{s}")
|
||||
}}</text>
|
||||
</view>
|
||||
<view>{{ hooks.useEnum("hardwareRefundStatusEnum", v.refundStatus) }}</view>
|
||||
</view>
|
||||
<view class="flex-row items-center justify-end mt-1">
|
||||
<text
|
||||
v-if="v.carList?.length && ['5', '20'].includes(v.orderStatus) && ['1', '2'].includes(v.orderType)"
|
||||
class="second-text-30 mr-2">
|
||||
共 {{ v.carList.length }} 件
|
||||
</text>
|
||||
<view class="flex-col items-center">
|
||||
<text v-if="v.couponPrice || v.extraPrice" class="main-text-26 mr-10rpx line-through">
|
||||
¥{{ hooks.useMoney(v.totalPrice) }}
|
||||
</text>
|
||||
<text class="main-text-30 color-red!">
|
||||
¥{{ hooks.useMoney(v.payPrice) }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="['5', '20'].includes(v.orderStatus) && ['1', '2'].includes(v.orderType)">
|
||||
<view class="border-b-2rpx border-dashed border-#eeeeee mt-2"></view>
|
||||
<tm-collapse>
|
||||
<tm-collapse-item :name="i" title="详细购买" titleFontSize="28" activeColor="#000" titleHeight="80"
|
||||
:showBottomLine="false">
|
||||
<view v-if="v.carList.length" class="flex justify-between items-center mb-2 px-3"
|
||||
v-for="(pV, pI) in v.carList" :key="pI">
|
||||
<view class="flex items-center w-6/10">
|
||||
<view class="size-100rpx">
|
||||
<image v-if="v.payType == '9'" class="size-100rpx rounded-8rpx"
|
||||
:src="pV.productPic" mode="aspectFill" />
|
||||
<image v-else class="size-100rpx rounded-8rpx" :src="filePath(pV.productPic)"
|
||||
mode="aspectFill" />
|
||||
</view>
|
||||
<view class="ml-2 overflow-hidden">
|
||||
<view class="sub-text-26 truncate">{{ pV.productName }}</view>
|
||||
<view class="sub-text-26">¥ {{ hooks.useMoney(pV.productPrice) }}</view>
|
||||
<view class="sub-text-26">x {{ pV.productCount }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="sub-text-30 w-3/10">¥ {{ hooks.useMoney(pV.totalPrice) }}</view>
|
||||
</view>
|
||||
<view v-else class="second-text-26 text-center">无数据</view>
|
||||
<view class="border-b-2rpx border-dashed border-#eeeeee mt-2"></view>
|
||||
</tm-collapse-item>
|
||||
</tm-collapse>
|
||||
</view>
|
||||
|
||||
<view v-if="['5', '10'].includes(v.orderStatus)" class="w-full flex-row items-center justify-end my-1">
|
||||
<!-- <view v-if="v.orderStatus == 5 && v.orderType == 2" class="botder_btn" @tap.stop="doRefund(v)">退款</view> -->
|
||||
<view v-if="v.orderStatus === '5' && ['2', '7'].includes(v.orderType)" class="m-l-20rpx botder_btn"
|
||||
@tap.stop="doToDetail(v)">
|
||||
核销码
|
||||
</view>
|
||||
</view>
|
||||
<view class="card rounded-24rpx bg-white p-20rpx pb-0rpx mb-20rpx" v-for="(v, index) in pageHook.list"
|
||||
:key="v.id">
|
||||
<order-car :cardetail="v" :footerOperate="['refund', 'qrCodeDetail']" />
|
||||
</view>
|
||||
</z-paging>
|
||||
</crud-layout>
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from "vue"
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
|
||||
import { hooks, router } from "@@/index"
|
||||
import { orderApi } from "@@/api"
|
||||
|
||||
import { filePath } from "@@/utils/file"
|
||||
|
||||
import zTabs from "@@/components/other/z-tabs/z-tabs.vue"
|
||||
import { getLaunchParam } from "@/sheep/utils/app"
|
||||
|
||||
const data = {
|
||||
tabs: [
|
||||
{ id: null, name: "全部", disabled: false },
|
||||
{ id: 1, name: "未支付", disabled: false },
|
||||
{ id: 5, name: "已支付", disabled: false },
|
||||
{ id: 10, name: "售后", disabled: false },
|
||||
{ id: 20, name: "已核销", disabled: false },
|
||||
],
|
||||
}
|
||||
const state = reactive<any>({
|
||||
pa: {
|
||||
orderStatus: data.tabs[0].id,
|
||||
},
|
||||
})
|
||||
|
||||
onLoad(() => {
|
||||
const app = getApp()
|
||||
app._initTabbar()
|
||||
})
|
||||
onShow(async () => {
|
||||
const isLogin = await hooks.useCheckLogin()
|
||||
if (!isLogin) return
|
||||
if (pageRef.value) {
|
||||
pageRef.value.reload(false)
|
||||
}
|
||||
})
|
||||
const doTab = (e: any) => {
|
||||
const target = data.tabs[e]
|
||||
state.pa.orderStatus = target.id
|
||||
pageRef.value.reload(true)
|
||||
}
|
||||
|
||||
const pageRef = ref<any>(null)
|
||||
const pageHook = hooks.usePage(
|
||||
pageRef,
|
||||
getLaunchParam() == "canteen" // 食堂
|
||||
? orderApi.caneenPage
|
||||
: getLaunchParam() == "selfMerchant" // 自营商户
|
||||
? orderApi.supPage
|
||||
: getLaunchParam() == "coopMerchant" // 合作商户
|
||||
? orderApi.supPage
|
||||
: getLaunchParam() == "onlineShop"
|
||||
? orderApi.supPage
|
||||
: getLaunchParam() == "prosperityShop"
|
||||
? orderApi.farmerSpuPage
|
||||
: async () => [],
|
||||
null,
|
||||
"data.records",
|
||||
)
|
||||
const query = (page: number, pagesize: number) => {
|
||||
const isLogin = hooks.useStaticCheckLogin()
|
||||
|
||||
if (!isLogin) return
|
||||
pageHook.startPage(page, pagesize, false, state.pa)
|
||||
}
|
||||
|
||||
// 查看订单和核销码
|
||||
const doToDetail = (v: any) => {
|
||||
router.jump("/pages/order/detail", { id: v.id })
|
||||
}
|
||||
|
||||
const doAppraise = () => { }
|
||||
|
||||
const doRefund = (v: any) => {
|
||||
router.jump("/pages/refund/apply", { id: v.id })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<crud-layout bg="/static/page/blue-bg.png">
|
||||
<z-paging ref="pageRef" height="100%" :fixed="false" v-model="pageHook.list" :default-page-size="10"
|
||||
safe-area-inset-bottom :loading-more-enabled="true" :show-scrollbar="false" @query="query"
|
||||
:auto-clean-list-when-reload="false" :auto-scroll-to-top-when-reload="false" @scroll="pageHook.scroll">
|
||||
<template #top>
|
||||
<view class="bg-white rounded-16rpx px-20rpx my-20rpx">
|
||||
<z-tabs :list="data.tabs" @change="doTab" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view class="flex-col justify-center card p-3 m-b-20rpx" v-for="(v, i) in pageHook.list" :key="i">
|
||||
<view class="flex-row">
|
||||
<image class="size-130rpx rounded-8rpx" :src="filePath(v.logoPic)" mode="aspectFill" />
|
||||
<view class="flex-1 ml-20rpx">
|
||||
<view class="flex-row items-center justify-between">
|
||||
<view class="sub-text-30">{{ v.merchantName }}</view>
|
||||
<!-- <view class="m-l-15rpx color-#999 font-size-26rpx! iconfont icon-youjiantou" /> -->
|
||||
<tm-tag v-if="v.orderStatus == 1" color="info" size="s">未支付</tm-tag>
|
||||
<tm-tag v-if="v.orderStatus == 5" color="success" size="s">已支付</tm-tag>
|
||||
<tm-tag v-if="v.orderStatus == 10" color="error" size="s">售后</tm-tag>
|
||||
<tm-tag v-if="v.orderStatus == 20" size="s">已核销</tm-tag>
|
||||
<tm-tag v-if="v.orderStatus == 30" color="info" size="s">已取消(智能柜)</tm-tag>
|
||||
</view>
|
||||
<view class="flex-row items-center justify-between mt-5rpx second-text-24">
|
||||
<view>
|
||||
<text>下单时间</text>
|
||||
<text class="ml-10rpx">{{ hooks.useTime(v.createTime, "{y}-{m}-{d} {h}:{i}:{s}")
|
||||
}}</text>
|
||||
</view>
|
||||
<view>{{ hooks.useEnum("hardwareRefundStatusEnum", v.refundStatus) }}</view>
|
||||
</view>
|
||||
<view class="flex-row items-center justify-end mt-1">
|
||||
<text
|
||||
v-if="v.carList?.length && ['5', '20'].includes(v.orderStatus) && ['1', '2'].includes(v.orderType)"
|
||||
class="second-text-30 mr-2">
|
||||
共 {{ v.carList.length }} 件
|
||||
</text>
|
||||
<view class="flex-col items-center">
|
||||
<text v-if="v.couponPrice || v.extraPrice" class="main-text-26 mr-10rpx line-through">
|
||||
¥{{ hooks.useMoney(v.totalPrice) }}
|
||||
</text>
|
||||
<text class="main-text-30 color-red!">
|
||||
¥{{ hooks.useMoney(v.payPrice) }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="['5', '20'].includes(v.orderStatus) && ['1', '2'].includes(v.orderType)">
|
||||
<view class="border-b-2rpx border-dashed border-#eeeeee mt-2"></view>
|
||||
<tm-collapse>
|
||||
<tm-collapse-item :name="i" title="详细购买" titleFontSize="28" activeColor="#000" titleHeight="80"
|
||||
:showBottomLine="false">
|
||||
<view v-if="v.carList.length" class="flex justify-between items-center mb-2 px-3"
|
||||
v-for="(pV, pI) in v.carList" :key="pI">
|
||||
<view class="flex items-center w-6/10">
|
||||
<view class="size-100rpx">
|
||||
<image v-if="v.payType == '9'" class="size-100rpx rounded-8rpx"
|
||||
:src="pV.productPic" mode="aspectFill" />
|
||||
<image v-else class="size-100rpx rounded-8rpx" :src="filePath(pV.productPic)"
|
||||
mode="aspectFill" />
|
||||
</view>
|
||||
<view class="ml-2 overflow-hidden">
|
||||
<view class="sub-text-26 truncate">{{ pV.productName }}</view>
|
||||
<view class="sub-text-26">¥ {{ hooks.useMoney(pV.productPrice) }}</view>
|
||||
<view class="sub-text-26">x {{ pV.productCount }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="sub-text-30 w-3/10">¥ {{ hooks.useMoney(pV.totalPrice) }}</view>
|
||||
</view>
|
||||
<view v-else class="second-text-26 text-center">无数据</view>
|
||||
<view class="border-b-2rpx border-dashed border-#eeeeee mt-2"></view>
|
||||
</tm-collapse-item>
|
||||
</tm-collapse>
|
||||
</view>
|
||||
|
||||
<view v-if="['5', '10'].includes(v.orderStatus)" class="w-full flex-row items-center justify-end my-1">
|
||||
<!-- <view v-if="v.orderStatus == 5 && v.orderType == 2" class="botder_btn" @tap.stop="doRefund(v)">退款</view> -->
|
||||
<view v-if="v.orderStatus === '5' && ['2', '7'].includes(v.orderType)" class="m-l-20rpx botder_btn"
|
||||
@tap.stop="doToDetail(v)">
|
||||
核销码
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</crud-layout>
|
||||
</template>
|
||||
@@ -83,7 +83,7 @@
|
||||
<view class="second-text-22">
|
||||
<text>下单时间</text>
|
||||
<text class="m-l-10rpx">{{ hooks.useTime(v.createTime, "{y}-{m}-{d} {h}:{i}:{s}")
|
||||
}}</text>
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="main-text-30 color-red! min-w-140rpx text-right">¥ {{
|
||||
hooks.useMoney(v.totalPrice) }}
|
||||
@@ -135,16 +135,16 @@
|
||||
borderRadius: '10rpx',
|
||||
marginTop: '10rpx',
|
||||
}" :inactive-style="{
|
||||
width: '300rpx',
|
||||
height: '70rpx',
|
||||
color: '#000000',
|
||||
textAlign: 'center',
|
||||
lineHeight: '70rpx',
|
||||
fontWeight: 'bold',
|
||||
fontSize: '30rpx',
|
||||
borderRadius: '10rpx',
|
||||
marginTop: '10rpx',
|
||||
}" @change="refundTabChange" />
|
||||
width: '300rpx',
|
||||
height: '70rpx',
|
||||
color: '#000000',
|
||||
textAlign: 'center',
|
||||
lineHeight: '70rpx',
|
||||
fontWeight: 'bold',
|
||||
fontSize: '30rpx',
|
||||
borderRadius: '10rpx',
|
||||
marginTop: '10rpx',
|
||||
}" @change="refundTabChange" />
|
||||
</view>
|
||||
|
||||
<view class="flex-col justify-center card p-x-15rpx p-y-25rpx m-b-10rpx">
|
||||
@@ -185,7 +185,7 @@
|
||||
共 {{ state.curOrder.carList.length }} 件
|
||||
</view>
|
||||
<view class="main-text-30 color-red!">¥ {{ hooks.useMoney(state.curOrder.totalPrice)
|
||||
}}
|
||||
}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -3,13 +3,9 @@
|
||||
<view class="text-center py-12">
|
||||
<view class="main-text-40 mb-2">请选择您的身份</view>
|
||||
</view>
|
||||
|
||||
<view class="px-6">
|
||||
<view
|
||||
class="card mb-6 overflow-hidden relative border-8 border-solid border-white duration-200"
|
||||
:class="{ 'border-8 border-solid border-blue!': userRole === 'user' }"
|
||||
@click="selectRole('user')"
|
||||
>
|
||||
<view class="card mb-6 overflow-hidden relative border-8 border-solid border-white duration-200"
|
||||
:class="{ 'border-8 border-solid border-blue!': userRole === 'user' }" @click="selectRole('user')">
|
||||
<view class="flex-row items-center p-6">
|
||||
<view class="w-64 h-64 rounded-full flex-col-center mr-8">
|
||||
<image src="@/static/page/userRole.svg" />
|
||||
@@ -17,12 +13,9 @@
|
||||
<view class="main-text-32 mb-1">我是用户</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="card mb-6 overflow-hidden relative border-8 border-solid border-white duration-200"
|
||||
<view class="card mb-6 overflow-hidden relative border-8 border-solid border-white duration-200"
|
||||
:class="{ 'border-8 border-solid border-blue!': userRole === 'merchant' }"
|
||||
@click="selectRole('merchant')"
|
||||
>
|
||||
@click="selectRole('merchant')">
|
||||
<view class="flex-row items-center p-6">
|
||||
<view class="w-64 h-64 rounded-full flex-col-center mr-8">
|
||||
<image src="@/static/page/merchantRole.svg" />
|
||||
@@ -30,12 +23,9 @@
|
||||
<view class="main-text-32 mb-1">我是合作商户</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="card overflow-hidden relative border-8 border-solid border-white duration-200"
|
||||
<view class="card overflow-hidden relative border-8 border-solid border-white duration-200"
|
||||
:class="{ 'border-8 border-solid border-blue!': userRole === 'doorAdmin' }"
|
||||
@click="selectRole('doorAdmin')"
|
||||
>
|
||||
@click="selectRole('doorAdmin')">
|
||||
<view class="flex-row items-center p-6">
|
||||
<view class="w-64 h-64 rounded-full flex-col-center mr-8">
|
||||
<image src="@/static/page/doorAdminRole.svg" />
|
||||
@@ -44,7 +34,6 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="flex-row-center px-10 mt-auto pb-10 font-bold">
|
||||
<tm-button block @click="confirmRole">确 定</tm-button>
|
||||
</view>
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue"
|
||||
import { hooks, router } from "@@/index"
|
||||
|
||||
import {
|
||||
hasRoleCode,
|
||||
MCH_USER,
|
||||
} from "@@/utils/user-role"
|
||||
|
||||
import { filePath } from "@@/utils/file"
|
||||
|
||||
import OrderStatusTag from "./order-status-tag.vue"
|
||||
|
||||
const emit = defineEmits(['cancel', 'confirmReceipt'])
|
||||
|
||||
export type Props = {
|
||||
// 订单详情
|
||||
cardetail: any
|
||||
// 商品信息是否折叠
|
||||
goodsCollapsed?: boolean
|
||||
// 是否显示商户信息
|
||||
visibleMch?: boolean
|
||||
// 是否显示用户信息
|
||||
visibleUser?: boolean
|
||||
// 是否显示底部边框
|
||||
visibleBottomBorder?: boolean
|
||||
// 是否是最后一个订单
|
||||
isLast?: boolean
|
||||
// 底部操作区域控制。
|
||||
// 传 true 时,等价于 ['refund', 'qrCodeDetail'],表示两个按钮都允许显示。
|
||||
// 传数组时,可按需精确控制具体显示哪些按钮。
|
||||
footerOperate?: boolean | Array<'refund' | 'qrCodeDetail' | 'cancel' | 'expressTracking'>
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
cardetail: {},
|
||||
goodsCollapsed: true,
|
||||
visibleMch: true,
|
||||
visibleUser: false,
|
||||
visibleBottomBorder: false,
|
||||
isLast: false,
|
||||
footerOperate: false,
|
||||
})
|
||||
|
||||
const collapseState = ref<Record<string, boolean>>({})
|
||||
|
||||
const getOrderKey = (order: any, index: number) => String(order?.id ?? index)
|
||||
|
||||
const hasMultipleGoods = (order: any) => (order?.carList?.length || 0) > 1
|
||||
|
||||
const isGoodsCollapsed = (order: any, index: number) => {
|
||||
if (!props.goodsCollapsed || !hasMultipleGoods(order)) return false
|
||||
return collapseState.value[getOrderKey(order, index)] ?? true
|
||||
}
|
||||
|
||||
const toggleGoodsCollapse = (order: any, index: number) => {
|
||||
if (!props.goodsCollapsed || !hasMultipleGoods(order)) return
|
||||
const key = getOrderKey(order, index)
|
||||
collapseState.value[key] = !isGoodsCollapsed(order, index)
|
||||
}
|
||||
|
||||
// 判断某个底部操作按钮是否允许显示。
|
||||
// `footerOperate === true` 时,视为开启全部按钮;
|
||||
// 未传或传 false 时,不显示任何底部操作按钮;
|
||||
// 传数组时,仅显示数组中包含的操作项。
|
||||
const hasFooterOperate = (operate: 'refund' | 'qrCodeDetail' | 'cancel' | 'expressTracking') => {
|
||||
if (props.footerOperate === true) return true
|
||||
if (!Array.isArray(props.footerOperate)) return false
|
||||
return props.footerOperate.includes(operate)
|
||||
}
|
||||
|
||||
// 退款按钮显示条件:
|
||||
// 1. footerOperate 允许 refund;
|
||||
// 2. 订单状态为 5、210
|
||||
// 3. 订单类型为 2、7
|
||||
const showRefundButton = (order: any) => {
|
||||
return hasFooterOperate('refund') && ['5', '210'].includes(String(order?.orderStatus)) && ['1', '2', '7'].includes(String(order?.orderType)) && ['2', '3', '4', '5'].includes(String(order?.merchantType))
|
||||
}
|
||||
|
||||
// 显示订单详情按钮条件:
|
||||
// 1. footerOperate 允许 refund;
|
||||
// 2. 订单状态为 10、20;
|
||||
// 3. 订单类型为 2。
|
||||
// 4. 订单退款为 10,20,30。
|
||||
const showRefundDetailButton = (order: any) => {
|
||||
return (
|
||||
hasFooterOperate('refund') &&
|
||||
['10', '20'].includes(String(order?.orderStatus)) &&
|
||||
['1', '2', '7'].includes(String(order?.orderType)) &&
|
||||
['10', '20', '30'].includes(order?.refundStatus || '')
|
||||
)
|
||||
}
|
||||
|
||||
// 核销码按钮显示条件:
|
||||
// 1. footerOperate 允许 qrCodeDetail;
|
||||
// 2. 订单状态为 5;
|
||||
// 3. 订单类型为 2 或 7。
|
||||
const showQrCodeDetailButton = (order: any) => {
|
||||
return (
|
||||
hasFooterOperate('qrCodeDetail') &&
|
||||
String(order?.orderStatus) === '5' &&
|
||||
['2'].includes(String(order?.orderType))
|
||||
)
|
||||
}
|
||||
|
||||
// 手动核销按钮显示条件:
|
||||
// 1. footerOperate 允许 cancel;
|
||||
// 2. 订单状态为 5;
|
||||
// 3. 订单类型为 2。
|
||||
// 4. 用户有'移动端商户角色'
|
||||
const showCancelButton = (order: any) => {
|
||||
return (
|
||||
hasFooterOperate('cancel') &&
|
||||
String(order?.orderStatus) === '5' &&
|
||||
['2'].includes(String(order?.orderType)) && hasRoleCode(MCH_USER)
|
||||
)
|
||||
}
|
||||
|
||||
// 查看订单和核销码
|
||||
const doToDetail = (v: any) => {
|
||||
router.jump("/pages/order/detail", { id: v.id })
|
||||
}
|
||||
|
||||
// 申请售后
|
||||
const doRefund = (v: any) => {
|
||||
router.jump("/pages/refund/apply", { id: v.id })
|
||||
}
|
||||
|
||||
const doCancel = (v: any) => {
|
||||
emit('cancel', v)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="flex-col justify-center pb-20rpx gap-20rpx"
|
||||
:class="!props.isLast && props.visibleBottomBorder ? 'car-border' : ''">
|
||||
<!-- start 用户信息 start -->
|
||||
<view v-if="props.visibleUser" class="flex items-start justify-between gap-16rpx">
|
||||
<view class="min-w-0 flex-1">
|
||||
<view class="flex items-center min-w-0">
|
||||
<text class="sub-text-26 truncate">{{ props.cardetail.username || "未知用户" }}</text>
|
||||
<text class="mx-10rpx text-18rpx text-[#d0d5dd]">|</text>
|
||||
<text class="second-text-24 truncate">{{ props.cardetail.userMobile || "-" }}</text>
|
||||
</view>
|
||||
<view class="mt-10rpx inline-flex max-w-full items-center rounded-24rpx bg-[#f8fafc] px-14rpx py-8rpx">
|
||||
<text class="text-20rpx text-[#98a2b3]">下单时间</text>
|
||||
<text v-if="props.cardetail.createTime" class="ml-10rpx text-20rpx text-[#475467] truncate">
|
||||
{{ hooks.useTime(props.cardetail.createTime, "{y}-{m}-{d} {h}:{i}:{s}") }}
|
||||
</text>
|
||||
<text v-else class="ml-10rpx text-20rpx text-[#1570ef]">正在下单</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-shrink-0">
|
||||
<view class="w-100rpx flex-row-center">
|
||||
<order-status-tag :cardetail="props.cardetail" />
|
||||
</view>
|
||||
<view class="w-100rpx flex-row-center second-text-22 mt-10rpx" v-if="props.cardetail.refundStatus">
|
||||
{{ hooks.useEnum("hardwareRefundStatusEnum", props.cardetail.refundStatus) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end 用户信息 end -->
|
||||
|
||||
<!-- start 商户信息 start -->
|
||||
<view v-if="props.visibleMch" class="flex-row">
|
||||
<image class="size-90rpx rounded-8rpx bg-[#999] shadow-main overflow-hidden"
|
||||
:src="filePath(props.cardetail.logoPic) || '/static/logo/zax.png'" mode="aspectFill" />
|
||||
<view class="flex-1 ml-20rpx">
|
||||
<view class="flex-row items-center justify-between">
|
||||
<view class="sub-text-26">{{ props.cardetail.merchantName }}</view>
|
||||
<view class="w-100rpx flex-row-center">
|
||||
<order-status-tag :cardetail="props.cardetail" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row items-center justify-between second-text-22">
|
||||
<view>
|
||||
<text>下单时间:</text>
|
||||
<text v-if="props.cardetail.createTime" class="ml-10rpx">
|
||||
{{ hooks.useTime(props.cardetail.createTime, "{y}-{m}-{d} {h}:{i}:{s}") }}
|
||||
</text>
|
||||
<text v-else class="ml-10rpx color-blue">正在下单</text>
|
||||
</view>
|
||||
<view class="w-100rpx flex-row-center mt-10rpx" v-if="props.cardetail.refundStatus">
|
||||
{{ hooks.useEnum("hardwareRefundStatusEnum", props.cardetail.refundStatus) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end 商户信息 end -->
|
||||
|
||||
<!-- start 商品信息 start -->
|
||||
<view v-if="props.cardetail?.carList?.length"
|
||||
class="flex items-center rounded-12rpx bg-[#fafafa] px-20rpx py-16rpx transition-all duration-200"
|
||||
@tap="toggleGoodsCollapse(props.cardetail, 0)">
|
||||
<view class="min-w-0 flex-1">
|
||||
<view v-if="isGoodsCollapsed(props.cardetail, 0)" class="flex items-center">
|
||||
<image class="h-90rpx w-120rpx flex-shrink-0 rounded-8rpx bg-[#999] shadow-main overflow-hidden"
|
||||
:src="filePath(props.cardetail.carList?.[0]?.productPic) || '/static/logo/zax.png'"
|
||||
mode="aspectFill" />
|
||||
<view class="ml-16rpx min-w-0 flex-1">
|
||||
<view class="second-text-22 truncate">
|
||||
{{ props.cardetail.carList?.[0]?.productName || "暂无商品" }}
|
||||
</view>
|
||||
<view v-if="hasMultipleGoods(props.cardetail)" class="mt-8rpx text-20rpx text-[#98a2b3]">
|
||||
共 {{ props.cardetail.carList?.length || 0 }} 件,点击展开
|
||||
</view>
|
||||
<view v-else class="mt-8rpx text-20rpx text-[#98a2b3]">共 1 件商品</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view v-if="!isGoodsCollapsed(props.cardetail, 0)" scroll-x
|
||||
class="overflow-hidden whitespace-nowrap">
|
||||
<view class="flex items-start">
|
||||
<view v-for="item in props.cardetail.carList || []" :key="item.id"
|
||||
class="mr-20rpx w-120rpx flex-shrink-0">
|
||||
<image class="h-90rpx w-120rpx rounded-8rpx bg-[#999] shadow-main overflow-hidden"
|
||||
:src="filePath(item.productPic) || '/static/logo/zax.png'" mode="aspectFill" />
|
||||
<view class="second-text-22 mt-8rpx truncate">{{ item.productName }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<view class="order-car__summary w-120rpx flex-col-center">
|
||||
<view class="sub-text-28">¥{{ hooks.useMoney(props.cardetail.payPrice) }}</view>
|
||||
<view class="second-text-20 font-400! line-height-1em!">共 {{ props.cardetail.carList?.length || 0 }} 件
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="hasMultipleGoods(props.cardetail)"
|
||||
class="ml-12rpx flex-col-center text-[#98a2b3] transition-transform duration-200">
|
||||
<text class="text-20rpx">{{ isGoodsCollapsed(props.cardetail, 0) ? "展开" : "收起" }}</text>
|
||||
<text class="iconfont icon-youjiantou mt-8rpx text-20rpx"
|
||||
:class="isGoodsCollapsed(props.cardetail, 0) ? 'rotate-90' : '-rotate-90'" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- end 商品信息 end -->
|
||||
|
||||
<!-- start 简单购买信息(付款方式+支付金额) start -->
|
||||
<view v-if="!props.cardetail?.carList?.length"
|
||||
class="flex items-center justify-between rounded-12rpx border-[#eef3f8] bg-[linear-gradient(90deg,#ffffff_0%,#fafafa_100%)] px-22rpx py-12rpx">
|
||||
<view class="flex-row-center sub-text-24 gap-8rpx">
|
||||
<text class="iconfont icon-zhifufangshi1 text-24rpx!" />
|
||||
<text> {{ hooks.useEnum('hardwarePayTypeEnum', props.cardetail.payType) }}</text>
|
||||
</view>
|
||||
<view class="order-car__summary w-120rpx flex-col-center">
|
||||
<view class="sub-text-28">¥{{ hooks.useMoney(props.cardetail.payPrice) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end 简单购买信息(付款方式+支付金额) end -->
|
||||
|
||||
<!-- start 预约信息 start -->
|
||||
<view v-if="props.cardetail.apptId && props.cardetail.apptStartTime && props.cardetail.apptEndTime"
|
||||
class="flex items-center justify-between rounded-12rpx border border-[#eef3f8] bg-[linear-gradient(90deg,#ffffff_0%,#fafafa_100%)] px-22rpx py-12rpx shadow-[0_8rpx_24rpx_rgba(15,23,42,0.04)]">
|
||||
<view class="min-w-0 flex-1">
|
||||
<view class="second-text-22 text-[#98a2b3]!">预约时间段</view>
|
||||
<view class="mt-10rpx sub-text-24">
|
||||
{{ props.cardetail.apptStartTime }} - {{ props.cardetail.apptEndTime }}
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="props.cardetail.apptTitle"
|
||||
class="flex items-center gap-4rpx ml-20rpx flex-shrink-0 rounded-full border border-[#d1e9ff] bg-[#eff8ff] px-18rpx py-16rpx text-22rpx line-height-1 text-[#1570ef]">
|
||||
<text> {{ props.cardetail.apptUseDate }}</text>
|
||||
<text>{{ props.cardetail.apptTitle }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end 预约信息 end -->
|
||||
|
||||
<!-- start 底部操作区域 start -->
|
||||
<view
|
||||
v-if="showRefundButton(props.cardetail) || showRefundDetailButton(props.cardetail) || showQrCodeDetailButton(props.cardetail) || showCancelButton(props.cardetail)"
|
||||
class="w-full flex-row items-center justify-end my-1">
|
||||
<view v-if="showRefundButton(props.cardetail)" class="botder_btn" @tap.stop="doRefund(props.cardetail)">
|
||||
退款
|
||||
</view>
|
||||
<view v-if="showRefundDetailButton(props.cardetail)" class="m-l-20rpx botder_btn"
|
||||
@tap.stop="doToDetail(props.cardetail)">
|
||||
售后详情
|
||||
</view>
|
||||
<view v-if="showQrCodeDetailButton(props.cardetail)" class="m-l-20rpx botder_btn"
|
||||
@tap.stop="doToDetail(props.cardetail)">
|
||||
核销码
|
||||
</view>
|
||||
<view v-if="showCancelButton(props.cardetail)" class="m-l-20rpx botder_btn"
|
||||
@tap.stop="doCancel(props.cardetail)">
|
||||
手动核销
|
||||
</view>
|
||||
</view>
|
||||
<!-- end 底部操作区域 end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.car-border {
|
||||
border-bottom: 1px solid #fafafa;
|
||||
}
|
||||
|
||||
.order-car__summary {
|
||||
position: relative;
|
||||
padding-left: 18rpx;
|
||||
}
|
||||
|
||||
.order-car__summary::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -8rpx;
|
||||
top: 8rpx;
|
||||
bottom: 8rpx;
|
||||
width: 20rpx;
|
||||
pointer-events: none;
|
||||
background: linear-gradient(90deg, rgba(15, 23, 42, 0.08) 0%, rgba(15, 23, 42, 0.03) 38%, rgba(15, 23, 42, 0) 100%);
|
||||
filter: blur(8rpx);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
export type Props = {
|
||||
// 订单详情
|
||||
cardetail: any
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
cardetail: {},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<slot v-if="props.cardetail.orderStatus == 5">
|
||||
<tm-tag v-if="props.cardetail.orderType == 2" color="success" size="xs">待使用</tm-tag>
|
||||
<tm-tag v-else-if="props.cardetail.orderType == 7" color="success" size="xs">待发货</tm-tag>
|
||||
<tm-tag v-else color="success" size="xs">已支付</tm-tag>
|
||||
</slot>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 200" color="success" size="xs">待发货</tm-tag>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 210" color="success" size="xs">待收货</tm-tag>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 220" size="xs">已收货</tm-tag>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 230" color="success" size="xs">已评价</tm-tag>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 10" color="error" size="xs">售后</tm-tag>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 20" size="xs">已核销</tm-tag>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 30" color="info" size="xs">已取消(智能柜)</tm-tag>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 110" color="success" size="xs">配送中</tm-tag>
|
||||
</template>
|
||||
@@ -36,6 +36,13 @@ const hardwareRefundStatusEnum = {
|
||||
30: "售后失败",
|
||||
}
|
||||
|
||||
const hardSaleStatusEnum = {
|
||||
0: "售后中",
|
||||
50: "售后完成",
|
||||
61: "买家取消",
|
||||
62: "卖家拒绝",
|
||||
}
|
||||
|
||||
const carTypeEnum = {
|
||||
1: "私家车",
|
||||
2: "公车",
|
||||
@@ -98,4 +105,5 @@ export default {
|
||||
actCouponLimitTypeEnum,
|
||||
actCouponTypeEnum,
|
||||
actUserReceiveEnum,
|
||||
hardSaleStatusEnum,
|
||||
}
|
||||
@@ -7,6 +7,7 @@ export function useScanCode(actModalShow) {
|
||||
const appInfo = await getAppInfo()
|
||||
|
||||
if (isDevEnv()) {
|
||||
let testQrCode = ""
|
||||
// 开发环境模拟扫码
|
||||
// const testQrCode = "eyJpZCI6IjE5MDU4ODg4NjQ0NTQ1MzMxMjEiLCJuYW1lIjoi6ICB5Y6/5bqc6aOf5aCCIn0=" // 测试线上-老县府食堂-收款二维码
|
||||
// const testQrCode = "eyJoYXJkRG9vcklkIjoiMTkxNDIxNTYwODQzNzQxMTg0MSIsImNhYmluZXRObyI6IjEifQ==" // 测试线上-智能柜-收款二维码
|
||||
@@ -15,7 +16,13 @@ export function useScanCode(actModalShow) {
|
||||
// const testQrCode = "http://192.168.101.45:8889/h5/#/pages/pay/scanPay?id=1905816751043452930&name=测试新县府超市" // 邓本地-测试环境-新县府超市收款二维码
|
||||
// const testQrCode = "http://192.168.101.45:8889/h5/#/pages/pay/scanPay?hardDoorId=1913157080418295809&cabinetNo=1" // 测试智能柜柜门二维码
|
||||
// const testQrCode = "eyJjYW5jZWxJZCI6IjE5ODQyNDA4MzM5NDMyMDc5MzcifQ==" // 测试商户活动核销
|
||||
const testQrCode = "https://stgl.pj.gov.cn/h5/#/pages/pay/scanPay?id=1931916121241079810"
|
||||
// const testQrCode = "https://stgl.pj.gov.cn/h5/#/pages/pay/scanPay?id=1931916121241079810"
|
||||
// 测试环境(自营食堂)-新县府食堂
|
||||
// testQrCode = "https://stgl.pj.gov.cn/h5/#/pages/pay/scanPay?id=1905816666859577346"
|
||||
// 测试环境(合作商家)-测试部门超市
|
||||
testQrCode = "https://stgl.pj.gov.cn/h5/#/pages/pay/scanPay?id=1931916121241079810"
|
||||
// 测试环境(自营商家)-老县府超市
|
||||
// testQrCode = "https://stgl.pj.gov.cn/h5/#/pages/pay/scanPay?id=1905816898011865090"
|
||||
uni.showModal({ content: "开发环境不是浙政钉和诗画环境,扫码仅供测试" })
|
||||
return Promise.resolve(testQrCode)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
@font-face {
|
||||
font-family: "iconfont";
|
||||
/* Project id 4740692 */
|
||||
src: url('//at.alicdn.com/t/c/font_4740692_uwg9mtj0d0p.woff2?t=1770172172940') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_4740692_uwg9mtj0d0p.woff?t=1770172172940') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_4740692_uwg9mtj0d0p.ttf?t=1770172172940') format('truetype');
|
||||
src: url('https://at.alicdn.com/t/c/font_4740692_ol93veips6n.woff2?t=1782372215492') format('woff2'),
|
||||
url('https://at.alicdn.com/t/c/font_4740692_ol93veips6n.woff?t=1782372215492') format('woff'),
|
||||
url('https://at.alicdn.com/t/c/font_4740692_ol93veips6n.ttf?t=1782372215492') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@@ -14,6 +14,114 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-jisuwuliu:before {
|
||||
content: "\e61a";
|
||||
}
|
||||
|
||||
.icon-add:before {
|
||||
content: "\e79e";
|
||||
}
|
||||
|
||||
.icon-add1:before {
|
||||
content: "\e6aa";
|
||||
}
|
||||
|
||||
.icon-bianji:before {
|
||||
content: "\e763";
|
||||
}
|
||||
|
||||
.icon-address1:before {
|
||||
content: "\e605";
|
||||
}
|
||||
|
||||
.icon-address:before {
|
||||
content: "\e659";
|
||||
}
|
||||
|
||||
.icon-address-f:before {
|
||||
content: "\e604";
|
||||
}
|
||||
|
||||
.icon-zhifufangshi:before {
|
||||
content: "\e759";
|
||||
}
|
||||
|
||||
.icon-zhifufangshi-yuezhifu:before {
|
||||
content: "\e68c";
|
||||
}
|
||||
|
||||
.icon-zhifufangshi1:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
.icon-rili:before {
|
||||
content: "\e60e";
|
||||
}
|
||||
|
||||
.icon-hexiaoicon:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.icon-hexiao1:before {
|
||||
content: "\e7fe";
|
||||
}
|
||||
|
||||
.icon-hexiao:before {
|
||||
content: "\e63f";
|
||||
}
|
||||
|
||||
.icon-fanhui:before {
|
||||
content: "\e8fb";
|
||||
}
|
||||
|
||||
.icon-tongzhi:before {
|
||||
content: "\e61b";
|
||||
}
|
||||
|
||||
.icon-dangqianweizhi:before {
|
||||
content: "\e678";
|
||||
}
|
||||
|
||||
.icon-sousuo:before {
|
||||
content: "\e619";
|
||||
}
|
||||
|
||||
.icon-yizuofei1:before {
|
||||
content: "\e60d";
|
||||
}
|
||||
|
||||
.icon-yizuofei:before {
|
||||
content: "\f2d8";
|
||||
}
|
||||
|
||||
.icon-jilu1:before {
|
||||
content: "\e631";
|
||||
}
|
||||
|
||||
.icon-jilu:before {
|
||||
content: "\e664";
|
||||
}
|
||||
|
||||
.icon-kefu:before {
|
||||
content: "\e677";
|
||||
}
|
||||
|
||||
.icon-kefu1:before {
|
||||
content: "\e612";
|
||||
}
|
||||
|
||||
.icon-info:before {
|
||||
content: "\e64a";
|
||||
}
|
||||
|
||||
.icon-setting:before {
|
||||
content: "\e8d8";
|
||||
}
|
||||
|
||||
.icon-shezhi:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.icon-yiguoqi:before {
|
||||
content: "\e642";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import { constant } from "@@/index"
|
||||
import { userApi } from "@@/api"
|
||||
|
||||
export const ROLE_ONLINE_CANTEEN_MCH = "ONLINE_CANTEEN_MCH"
|
||||
export const ROLE_CANTEEN_RIDER = "CANTEEN_RIDER"
|
||||
// 移动端商户角色(核销订餐二维码)
|
||||
export const MCH_USER = "MCH_USER"
|
||||
/** 移动端后台管理入口角色 */
|
||||
export const ROLE_MOBILE_ADMIN_PC = "MOBILE_ADMIN_PC"
|
||||
/** 新增用户默认角色 */
|
||||
export const ROLE_GENERAL_USER = "GENERAL_USER"
|
||||
export const ROLE_WALLET_AUTO_CREATE = "WALLET_AUTO_CREATE"
|
||||
|
||||
const DEFAULT_NEW_USER_ROLES = [
|
||||
{ roleCode: ROLE_GENERAL_USER, roleId: "2" },
|
||||
{ roleCode: ROLE_WALLET_AUTO_CREATE, roleId: "1873557615006810113" },
|
||||
] as const
|
||||
|
||||
/** 新增用户时默认勾选的角色 ID(优先按 roleCode 从列表解析) */
|
||||
export const resolveDefaultNewUserRoleIds = (roleList: { roleId?: string | number; roleCode?: string }[]): string[] =>
|
||||
DEFAULT_NEW_USER_ROLES.map(({ roleCode, roleId }) => {
|
||||
const hit = roleList.find((r) => r.roleCode === roleCode)
|
||||
return hit ? String(hit.roleId) : roleId
|
||||
})
|
||||
|
||||
export const getUserRoleCodes = (): string[] => {
|
||||
const userInfo: any = uni.getStorageSync(constant.storageConstant.USERINFO) || {}
|
||||
const codes = userInfo?.roleCodes
|
||||
if (Array.isArray(codes)) return codes.filter(Boolean)
|
||||
return []
|
||||
}
|
||||
|
||||
export const hasRoleCode = (code: string) => getUserRoleCodes().includes(code)
|
||||
|
||||
/** 刷新用户信息中的 roleCodes(我的页菜单、统计页鉴权用) */
|
||||
export const refreshUserRoleCodes = async (): Promise<string[]> => {
|
||||
try {
|
||||
const res: any = await userApi.userInfo()
|
||||
if (res?.code === 0 && res.data) {
|
||||
uni.setStorageSync(constant.storageConstant.USERINFO, res.data)
|
||||
return Array.isArray(res.data.roleCodes) ? res.data.roleCodes : []
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("refreshUserRoleCodes failed", e)
|
||||
}
|
||||
return getUserRoleCodes()
|
||||
}
|
||||
|
||||
/** 移动端后台管理 - 权限码(与 PC 角色菜单分配一致) */
|
||||
export const PERM_SYS_USER_ADD = "sys_user_add"
|
||||
export const PERM_SYS_USER_EDIT = "sys_user_edit"
|
||||
export const PERM_SYS_USER_DEL = "sys_user_del"
|
||||
export const PERM_WALLET_MANAGE_VIEW = "wallet_walletManage_view"
|
||||
export const PERM_WALLET_MANAGE_EDIT = "wallet_walletManage_edit"
|
||||
export const PERM_WALLET_UPDATE_BALANCE = "wallet_walletTransaction_update_balance"
|
||||
|
||||
export const ADMIN_USER_PERMS = [PERM_SYS_USER_ADD, PERM_SYS_USER_EDIT, PERM_SYS_USER_DEL]
|
||||
export const ADMIN_WALLET_PERMS = [PERM_WALLET_MANAGE_VIEW, PERM_WALLET_MANAGE_EDIT, PERM_WALLET_UPDATE_BALANCE]
|
||||
export const ADMIN_HUB_PERMS = [...ADMIN_USER_PERMS, ...ADMIN_WALLET_PERMS]
|
||||
|
||||
export const getUserPermissions = (): string[] => {
|
||||
const userInfo: any = uni.getStorageSync(constant.storageConstant.USERINFO) || {}
|
||||
const perms = userInfo?.permissions
|
||||
if (Array.isArray(perms)) return perms.filter(Boolean)
|
||||
return []
|
||||
}
|
||||
|
||||
export const hasPermission = (code: string) => getUserPermissions().includes(code)
|
||||
|
||||
export const hasAnyPermission = (codes: string[]) => codes.some((code) => hasPermission(code))
|
||||
|
||||
/** 刷新 permissions(顺带刷新 roleCodes) */
|
||||
export const refreshUserPermissions = async (): Promise<string[]> => {
|
||||
await refreshUserRoleCodes()
|
||||
return getUserPermissions()
|
||||
}
|
||||
Reference in new issue
Block a user