Merge branch 'master' of https://gitea.zianxin.com/zax/biz-mobile-react-cloud
This commit is contained in:
commit
6e46a9064c
23 files changed
+1290
-645
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 = http://127.0.0.1:9999 # 邓-本地
|
||||
# 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 = 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地址 ----------------------------------
|
||||
|
||||
@@ -60,9 +60,36 @@ const getActDetail = async () => {
|
||||
const goGetCoupon = () => {
|
||||
uni.navigateTo({ url: `/pages/merchant/merchant-activity?actId=${actDetail.value.actId}&actType=${actDetail.value.actType}` })
|
||||
}
|
||||
const normalizeRichText = (html: string) => {
|
||||
const origin = "https://stgl.pj.gov.cn"
|
||||
return html.replace(/<img\b[^>]*>/gi, (imgTag) => {
|
||||
let next = imgTag
|
||||
|
||||
next = next.replace(/\bsrc\s*=\s*(['"])(.*?)\1/i, (_m, quote: string, src: string) => {
|
||||
let resolved = src
|
||||
if (resolved?.startsWith("/api")) resolved = `${origin}${resolved}`
|
||||
if (resolved?.startsWith("//")) resolved = `https:${resolved}`
|
||||
return `src=${quote}${resolved}${quote}`
|
||||
})
|
||||
|
||||
const styleMatch = next.match(/\bstyle\s*=\s*(['"])([\s\S]*?)\1/i)
|
||||
const required = "max-width: 100%; height: auto; display: block;"
|
||||
if (styleMatch) {
|
||||
const quote = styleMatch[1]
|
||||
const styleValue = styleMatch[2] ?? ""
|
||||
if (styleValue.includes("max-width") || styleValue.includes("width")) return next
|
||||
const merged = styleValue.trim().length ? `${styleValue.replace(/;?\s*$/, "; ")}${required}` : required
|
||||
return next.replace(/\bstyle\s*=\s*(['"])([\s\S]*?)\1/i, `style=${quote}${merged}${quote}`)
|
||||
}
|
||||
|
||||
return next.replace(/<img\b/i, `<img style="${required}"`)
|
||||
})
|
||||
}
|
||||
|
||||
const nodes = computed(() => {
|
||||
return detail.value.description?.replaceAll(`<img src="/api`, `<img src="https://stgl.pj.gov.cn/api`)
|
||||
const html = detail.value.description
|
||||
if (!html) return ""
|
||||
return normalizeRichText(html)
|
||||
})
|
||||
|
||||
function getTypeLabel(type: string) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<crud-layout mainIsScroll bg="/static/page/blue-bg.png">
|
||||
<view v-if="state.actId" class="px-2 py-4">
|
||||
<view v-if="state.actId" class="py-4">
|
||||
<view v-if="state.actType == 'CANCEL_ACT'"
|
||||
class="card rounded-lb-0! rounded-rb-0! w-full h-400rpx relative activity-card overflow-hidden">
|
||||
<view class="ribbon">兑换券</view>
|
||||
@@ -68,10 +68,6 @@
|
||||
<text>天内使用</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="state.actDetail.description"
|
||||
class="m-l-20rpx m-y-20rpx w-55% text-28 bg-#eeeeee44 c-#fff p-2 rounded-16rpx">
|
||||
{{ state.actDetail.description }}
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="state.couponInfo.actStatus == '2'"
|
||||
class="text-center card rounded-lt-0! rounded-rt-0! p-3 sub-text-30">
|
||||
@@ -85,6 +81,9 @@
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<view class="detail-content">
|
||||
<rich-text :nodes="nodes || ''"></rich-text>
|
||||
</view>
|
||||
<template #main-bottom>
|
||||
<view class="text-center">
|
||||
<tm-button class="px-32 m-2" @click="doQrcode">我的礼券</tm-button>
|
||||
@@ -95,7 +94,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, nextTick } from "vue"
|
||||
import { reactive, ref, nextTick, computed } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
|
||||
import { actCancel, actComApi, actCouponApi, userApi } from "@/sheep/api"
|
||||
@@ -116,6 +115,10 @@ const state = reactive<any>({
|
||||
userDetail: {},
|
||||
})
|
||||
|
||||
const nodes = computed(() => {
|
||||
return state.actDetail.description?.replaceAll(`<img src="/api`, `<img src="https://stgl.pj.gov.cn/api`)
|
||||
})
|
||||
|
||||
onLoad((option: any) => {
|
||||
const { actId, actType } = option
|
||||
if (!actId || !actType) return uni.showToast({ title: "参数错误", icon: "error" })
|
||||
@@ -255,6 +258,16 @@ const modifyUserClose = () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.detail-content {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.activity-card {
|
||||
background-image: url("../../static/page/activity-card-bg.png");
|
||||
background-repeat: no-repeat;
|
||||
|
||||
@@ -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>
|
||||
+100
-34
@@ -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,23 +99,38 @@ 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>
|
||||
<crud-layout title="订单详情" mainIsScroll bg="/static/page/blue-bg.png">
|
||||
<view class="flex-row-center m-t-30rpx" v-if="state.detail.orderStatus === '5' && ['2', '7'].includes(state.detail.orderType)">
|
||||
<view class="flex-row-center m-t-30rpx"
|
||||
v-if="state.detail.orderStatus === '5' && ['2', '7'].includes(state.detail.orderType)">
|
||||
<view class="flex-row-center bg-white w-550rpx rounded-16rpx">
|
||||
<image
|
||||
class="w-500rpx"
|
||||
:src="filePath(state.detail.reserveCode)"
|
||||
mode="widthFix"
|
||||
@click.stop="hooks.usePreviewImage(filePath(state.detail.reserveCode))"
|
||||
/>
|
||||
<image class="w-500rpx" :src="filePath(state.detail.reserveCode)" mode="widthFix"
|
||||
@click.stop="hooks.usePreviewImage(filePath(state.detail.reserveCode))" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="h-30rpx" />
|
||||
<view class="relative flex-col justify-center overflow-hidden card p-x-20rpx p-y-30rpx m-b-20rpx">
|
||||
<image class="absolute top--20rpx right--60rpx w-160rpx h-160rpx" src="/static/icon/guarantee.png" mode="widthFix" />
|
||||
<image class="absolute top--20rpx right--60rpx w-160rpx h-160rpx" src="/static/icon/guarantee.png"
|
||||
mode="widthFix" />
|
||||
<view class="sub-text-32">订单信息</view>
|
||||
<view class="m-t-15rpx">
|
||||
<view class="info_cell">
|
||||
@@ -141,10 +190,8 @@ const doCancelRefund = async () => {
|
||||
</view>
|
||||
<!-- start 退款相关 start -->
|
||||
<slot v-if="['10'].includes(state.detail.orderStatus)">
|
||||
<view
|
||||
class="flex-row items-center justify-between card p-x-20rpx p-y-30rpx m-b-20rpx"
|
||||
@tap="router.jump('/pages/refund/history', { id: state.refundDetail.id })"
|
||||
>
|
||||
<view class="flex-row items-center justify-between card p-x-20rpx p-y-30rpx m-b-20rpx"
|
||||
@tap="router.jump('/pages/refund/history', { id: state.refundDetail.id })">
|
||||
<view>
|
||||
<view class="sub-text-28">
|
||||
<view>
|
||||
@@ -174,12 +221,20 @@ 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>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="state.refundDetail.status == 62" class="card p-x-20rpx p-y-30rpx space-y-10rpx m-b-20rpx second-text-24">
|
||||
<view v-if="state.refundDetail.status == 62"
|
||||
class="card p-x-20rpx p-y-30rpx space-y-10rpx m-b-20rpx second-text-24">
|
||||
<view class="flex-row items-center">
|
||||
<view>审核人:</view>
|
||||
<view>{{ state.refundDetail.auditUsername }}</view>
|
||||
@@ -197,22 +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>
|
||||
@@ -224,18 +290,18 @@ const doCancelRefund = async () => {
|
||||
margin-top: 15rpx;
|
||||
}
|
||||
|
||||
& > view {
|
||||
&>view {
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
& > view:nth-child(1) {
|
||||
&>view:nth-child(1) {
|
||||
width: 130rpx;
|
||||
}
|
||||
|
||||
& > view:nth-child(2) {
|
||||
&>view:nth-child(2) {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -72,7 +72,9 @@ onShow(() => {
|
||||
if (fromUrl) {
|
||||
uni.setStorageSync("launchParam", fromUrl)
|
||||
}
|
||||
jumpByParam()
|
||||
if (!isDevEnv()) {
|
||||
jumpByParam()
|
||||
}
|
||||
})
|
||||
|
||||
async function jumpIntegratedSubPage(launchParam: string): Promise<boolean> {
|
||||
|
||||
@@ -5,233 +5,68 @@
|
||||
: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 :visibleMchOrderStatus="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 +75,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 +100,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 +124,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>
|
||||
+89
-96
@@ -1,28 +1,44 @@
|
||||
<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"
|
||||
import { hasRoleCode, MCH_USER } from "@@/utils/user-role"
|
||||
|
||||
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[],
|
||||
currentUser: {},
|
||||
currentUserRole: "",
|
||||
})
|
||||
|
||||
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(() => {
|
||||
@@ -35,10 +51,39 @@ onShow(async () => {
|
||||
if (pageRef.value) {
|
||||
pageRef.value.reload(false)
|
||||
}
|
||||
getCurrentUserDetail()
|
||||
})
|
||||
|
||||
const computedCardBtn = (v: any): any => {
|
||||
if (state.currentUserRole && state.currentUserRole == "merchant") {
|
||||
const orderUserId = v.userId
|
||||
const currentUserId = state.currentUser?.sysUser?.userId
|
||||
if (hasRoleCode(MCH_USER) || orderUserId != currentUserId) {
|
||||
return ['qrCodeDetail']
|
||||
}
|
||||
}
|
||||
return ['refund', 'qrCodeDetail']
|
||||
}
|
||||
|
||||
const getCurrentUserDetail = () => {
|
||||
const userRole = uni.getStorageSync("userRole") ?? ""
|
||||
state.currentUserRole = userRole
|
||||
|
||||
const userInfo: any = uni.getStorageSync(constant.storageConstant.USERINFO) || {}
|
||||
if (userInfo) {
|
||||
state.currentUser = userInfo
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 +92,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 +106,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 +138,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="computedCardBtn(v)" />
|
||||
</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>
|
||||
@@ -1,57 +1,42 @@
|
||||
<template>
|
||||
<crud-layout bg="/static/page/blue-bg.png">
|
||||
<z-paging
|
||||
ref="pageRef"
|
||||
: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"
|
||||
>
|
||||
<z-paging ref="pageRef" :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 v-if="false">
|
||||
<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"
|
||||
>
|
||||
<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="w-100rpx text-center second-text-28 text-30 mb-4rpx">筛选</view>
|
||||
</tm-between-time>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
|
||||
<template #top>
|
||||
<view>
|
||||
<view class="h-20rpx" />
|
||||
<tm-input placeholder="请输入关键字" leftIcon="search-2-line" />
|
||||
<view class="h-20rpx" />
|
||||
<tabSearch />
|
||||
<tabSearch />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view class="h-20rpx" />
|
||||
|
||||
<view class="flex-col justify-center card p-3 m-b-20rpx border-2rpx border-solid border-color-#eeeeee" v-for="(v, i) in pageHook.list" :key="i">
|
||||
<view class="flex-col justify-center card p-3 m-b-20rpx border-2rpx border-solid border-color-#eeeeee"
|
||||
v-for="(v, i) in pageHook.list" :key="i">
|
||||
<view class="flex-row">
|
||||
<image class="w-160rpx h-212rpx 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 v-if="false"
|
||||
class="m-l-15rpx color-#999 font-size-26rpx! iconfont icon-youjiantou" />
|
||||
</view>
|
||||
<template v-if="false">
|
||||
<tm-tag v-if="v.orderStatus == 1" color="info" size="xs">未支付</tm-tag>
|
||||
@@ -60,7 +45,7 @@
|
||||
<tm-tag v-if="v.orderStatus == 20" size="xs">已核销</tm-tag>
|
||||
<tm-tag v-if="v.orderStatus == 30" color="info" size="xs">已取消(智能柜)</tm-tag>
|
||||
</template>
|
||||
|
||||
|
||||
</view>
|
||||
<view class="flex-row-center m-t-10rpx justify-left">
|
||||
<tm-icon name="map-pin-2-line" color="#999"></tm-icon>
|
||||
@@ -74,102 +59,104 @@
|
||||
<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 class="second-text-22 h-30rpx">{{ hooks.useEnum("hardwareRefundStatusEnum",
|
||||
v.refundStatus) }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="flex justify-between items-center m-b-10rpx">
|
||||
<view class="second-text-22">
|
||||
<text>商品</text>
|
||||
</view>
|
||||
<view class="second-text-22 color-#000! h-30rpx">3物品</view>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="flex justify-between items-center m-b-10rpx">
|
||||
<view class="second-text-22">
|
||||
<text>日期</text>
|
||||
</view>
|
||||
<view class="second-text-22 color-#000! h-30rpx">{{ hooks.useTime(v.createTime, "{y}-{m}-{d} {h}:{i}:{s}") }}</view>
|
||||
<view class="second-text-22 color-#000! h-30rpx">{{ hooks.useTime(v.createTime, "{y}-{m}-{d}
|
||||
{ h }: { i }: { s }") }}</view>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="flex justify-between items-center" v-if="false">
|
||||
<view class="second-text-22">
|
||||
<text>下单时间</text>
|
||||
<text class="m-l-10rpx">{{ hooks.useTime(v.createTime, "{y}-{m}-{d} {h}:{i}:{s}") }}</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="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="m-t-15rpx m-b-15rpx h-1rpx bg-#eeeeee "></view>
|
||||
|
||||
<view class="flex justify-between items-center m-b-10rpx">
|
||||
<view class="second-text-22">
|
||||
<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="main-text-30 color-red! min-w-140rpx text-right">¥ {{ hooks.useMoney(v.totalPrice) }}</view>
|
||||
|
||||
<view class="m-t-15rpx m-b-15rpx h-1rpx bg-#eeeeee "></view>
|
||||
|
||||
<view class="flex justify-between items-center m-b-10rpx">
|
||||
<view class="second-text-22">
|
||||
<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="main-text-30 color-red! min-w-140rpx text-right">¥ {{ hooks.useMoney(v.totalPrice) }}
|
||||
</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 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>
|
||||
</z-paging>
|
||||
|
||||
<tm-drawer title="退款" :showClose="true" size="90%" placement="bottom" bgColor="#EBF6FF" v-model:show="state.showDrawer" zIndex="999">
|
||||
<tm-drawer title="退款" :showClose="true" size="90%" placement="bottom" 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"
|
||||
/>
|
||||
<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" />
|
||||
<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 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>
|
||||
@@ -190,12 +177,16 @@
|
||||
</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="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">
|
||||
<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 class="main-text-30 color-red!">¥ {{ hooks.useMoney(state.curOrder.totalPrice)
|
||||
}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -234,7 +225,8 @@
|
||||
<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 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>
|
||||
@@ -256,24 +248,12 @@
|
||||
</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()"
|
||||
>
|
||||
<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()"
|
||||
>
|
||||
<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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
<template>
|
||||
<view class="tree-container">
|
||||
<view v-for="item in nodeData" :key="item.id">
|
||||
<view
|
||||
class="tree-item"
|
||||
:style="item.id == selectedNodeId ? { borderColor: '#1879ff' } : { color: '#000' }"
|
||||
@click.stop="toCurrentNode(item)"
|
||||
>
|
||||
<view class="tree-item" :style="item.id == selectedNodeId ? { borderColor: '#1879ff' } : { color: '#000' }"
|
||||
@click.stop="toCurrentNode(item)">
|
||||
<image class="tree-item-icon" :src="filePath(item.picUrl)" />
|
||||
<text>{{ item.name }}</text>
|
||||
</view>
|
||||
|
||||
<node-tree
|
||||
v-model="selectedNodeId"
|
||||
v-if="item.children && item.children.length"
|
||||
:node-data="item.children"
|
||||
:style="{ marginLeft: `${getLevel() * 60}rpx` }"
|
||||
@currentNode="(v) => emit('currentNode', v)"
|
||||
/>
|
||||
<node-tree v-model="selectedNodeId" v-if="item.children && item.children.length" :node-data="item.children"
|
||||
:style="{ marginLeft: `${getLevel() * 60}rpx` }" @currentNode="(v) => emit('currentNode', v)" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -53,6 +45,7 @@ const getLevel = () => {
|
||||
.tree-container {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tree-item {
|
||||
border: 4rpx solid #e4e7ed;
|
||||
margin-bottom: 16rpx;
|
||||
@@ -61,6 +54,7 @@ const getLevel = () => {
|
||||
padding: 10rpx 20rpx;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.tree-item-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
|
||||
@@ -0,0 +1,330 @@
|
||||
<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
|
||||
// 是否显示商户订单状态
|
||||
visibleMchOrderStatus?: 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,
|
||||
visibleMchOrderStatus: 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 v-if="props.visibleMchOrderStatus" 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 && props.visibleMchOrderStatus">
|
||||
{{ 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-24"
|
||||
v-if="props.cardetail.totalPrice && props.cardetail.payPrice && props.cardetail.totalPrice != props.cardetail.payPrice">
|
||||
¥{{ hooks.useMoney(props.cardetail.totalPrice) }}
|
||||
</view>
|
||||
<view class="sub-text-28 color-red!">¥{{ 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-180rpx flex-row-center justify-end gap-8rpx">
|
||||
<text class="sub-text-24 line-through"
|
||||
v-if="props.cardetail.totalPrice && props.cardetail.payPrice && props.cardetail.totalPrice != props.cardetail.payPrice">
|
||||
¥{{ hooks.useMoney(props.cardetail.totalPrice) }}
|
||||
</text>
|
||||
<text class="sub-text-28 color-red!">
|
||||
¥{{ hooks.useMoney(props.cardetail.payPrice) }}
|
||||
</text>
|
||||
</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>
|
||||
@@ -1,26 +1,15 @@
|
||||
<template>
|
||||
<view class="date-time-range">
|
||||
<view
|
||||
class="date-range-item"
|
||||
:class="[selectedDateIndex == index ? 'active' : '']"
|
||||
v-for="(item, index) in getLast7DaysWeek()"
|
||||
:key="index"
|
||||
@click="selectDate(item, index)"
|
||||
>
|
||||
<view class="date-range-item" :class="[selectedDateIndex == index ? 'active' : '']"
|
||||
v-for="(item, index) in getLast7DaysWeek()" :key="index" @click="selectDate(item, index)">
|
||||
<view>{{ item.week }}</view>
|
||||
<view>{{ item.date }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="day-time-point-list">
|
||||
<tm-button
|
||||
class="day-time-button"
|
||||
size="m"
|
||||
:color="selectedTimePointIndex == item.index ? '' : 'info'"
|
||||
:disabled="item.disabled"
|
||||
v-for="item in availableTimePoints"
|
||||
:key="item.index"
|
||||
@click="selectTimePoint(item.time, item.index)"
|
||||
>
|
||||
<tm-button class="day-time-button" size="m" :color="selectedTimePointIndex == item.index ? '' : 'info'"
|
||||
:disabled="item.disabled" v-for="item in availableTimePoints" :key="item.index"
|
||||
@click="selectTimePoint(item.time, item.index)">
|
||||
{{ item.time.slice(0, 5) }}
|
||||
</tm-button>
|
||||
</view>
|
||||
@@ -123,6 +112,7 @@ function onConfirm() {
|
||||
margin-bottom: 30rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.date-time-range .date-range-item {
|
||||
padding: 10rpx 16rpx;
|
||||
background-color: #eee;
|
||||
@@ -131,17 +121,20 @@ function onConfirm() {
|
||||
white-space: nowrap;
|
||||
transition: all 0.1s linear;
|
||||
}
|
||||
|
||||
.date-time-range .active {
|
||||
background: #0779fd;
|
||||
border-color: #4988f2;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.day-time-point-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.day-time-button {
|
||||
flex: 1 0 calc(100vw / 4);
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -226,8 +226,7 @@ const autoLogin = async (): Promise<boolean> => {
|
||||
function isZzdNeedSmsVerify(data: unknown): data is { needSmsVerify: true; bindSessionId: string; displayName?: string } {
|
||||
if (!data || typeof data !== "object") return false
|
||||
const o = data as Record<string, unknown>
|
||||
const need =
|
||||
o.needSmsVerify === true || o.needSmsVerify === "true" || o.needSmsVerify === 1 || o.needSmsVerify === "1"
|
||||
const need = o.needSmsVerify === true || o.needSmsVerify === "true" || o.needSmsVerify === 1 || o.needSmsVerify === "1"
|
||||
const sid = o.bindSessionId
|
||||
const sidStr = typeof sid === "string" ? sid : sid != null ? String(sid) : ""
|
||||
return need && sidStr.length > 0
|
||||
|
||||
@@ -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