feat:退款,支付返回
This commit is contained in:
1 parent
41d3b01c24
commit
68349eb8c0
17 files changed
+1092
-491
No files matched your search
@@ -0,0 +1,314 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue"
|
||||
import { hooks, router } from "@@/index"
|
||||
|
||||
import {
|
||||
hasRoleCode,
|
||||
MCH_USER,
|
||||
} from "@@/utils/user-role"
|
||||
|
||||
import { filePath } from "@@/utils/file"
|
||||
|
||||
import OrderStatusTag from "./order-status-tag.vue"
|
||||
|
||||
const emit = defineEmits(['cancel', 'confirmReceipt'])
|
||||
|
||||
export type Props = {
|
||||
// 订单详情
|
||||
cardetail: any
|
||||
// 商品信息是否折叠
|
||||
goodsCollapsed?: boolean
|
||||
// 是否显示商户信息
|
||||
visibleMch?: boolean
|
||||
// 是否显示用户信息
|
||||
visibleUser?: boolean
|
||||
// 是否显示底部边框
|
||||
visibleBottomBorder?: boolean
|
||||
// 是否是最后一个订单
|
||||
isLast?: boolean
|
||||
// 底部操作区域控制。
|
||||
// 传 true 时,等价于 ['refund', 'qrCodeDetail'],表示两个按钮都允许显示。
|
||||
// 传数组时,可按需精确控制具体显示哪些按钮。
|
||||
footerOperate?: boolean | Array<'refund' | 'qrCodeDetail' | 'cancel' | 'expressTracking'>
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
cardetail: {},
|
||||
goodsCollapsed: true,
|
||||
visibleMch: true,
|
||||
visibleUser: false,
|
||||
visibleBottomBorder: false,
|
||||
isLast: false,
|
||||
footerOperate: false,
|
||||
})
|
||||
|
||||
const collapseState = ref<Record<string, boolean>>({})
|
||||
|
||||
const getOrderKey = (order: any, index: number) => String(order?.id ?? index)
|
||||
|
||||
const hasMultipleGoods = (order: any) => (order?.carList?.length || 0) > 1
|
||||
|
||||
const isGoodsCollapsed = (order: any, index: number) => {
|
||||
if (!props.goodsCollapsed || !hasMultipleGoods(order)) return false
|
||||
return collapseState.value[getOrderKey(order, index)] ?? true
|
||||
}
|
||||
|
||||
const toggleGoodsCollapse = (order: any, index: number) => {
|
||||
if (!props.goodsCollapsed || !hasMultipleGoods(order)) return
|
||||
const key = getOrderKey(order, index)
|
||||
collapseState.value[key] = !isGoodsCollapsed(order, index)
|
||||
}
|
||||
|
||||
// 判断某个底部操作按钮是否允许显示。
|
||||
// `footerOperate === true` 时,视为开启全部按钮;
|
||||
// 未传或传 false 时,不显示任何底部操作按钮;
|
||||
// 传数组时,仅显示数组中包含的操作项。
|
||||
const hasFooterOperate = (operate: 'refund' | 'qrCodeDetail' | 'cancel' | 'expressTracking') => {
|
||||
if (props.footerOperate === true) return true
|
||||
if (!Array.isArray(props.footerOperate)) return false
|
||||
return props.footerOperate.includes(operate)
|
||||
}
|
||||
|
||||
// 退款按钮显示条件:
|
||||
// 1. footerOperate 允许 refund;
|
||||
// 2. 订单状态为 5、210
|
||||
// 3. 订单类型为 2、7
|
||||
const showRefundButton = (order: any) => {
|
||||
return hasFooterOperate('refund') && ['5', '210'].includes(String(order?.orderStatus)) && ['1', '2', '7'].includes(String(order?.orderType)) && ['2', '3', '4', '5'].includes(String(order?.merchantType))
|
||||
}
|
||||
|
||||
// 显示订单详情按钮条件:
|
||||
// 1. footerOperate 允许 refund;
|
||||
// 2. 订单状态为 10、20;
|
||||
// 3. 订单类型为 2。
|
||||
// 4. 订单退款为 10,20,30。
|
||||
const showRefundDetailButton = (order: any) => {
|
||||
return (
|
||||
hasFooterOperate('refund') &&
|
||||
['10', '20'].includes(String(order?.orderStatus)) &&
|
||||
['1', '2', '7'].includes(String(order?.orderType)) &&
|
||||
['10', '20', '30'].includes(order?.refundStatus || '')
|
||||
)
|
||||
}
|
||||
|
||||
// 核销码按钮显示条件:
|
||||
// 1. footerOperate 允许 qrCodeDetail;
|
||||
// 2. 订单状态为 5;
|
||||
// 3. 订单类型为 2 或 7。
|
||||
const showQrCodeDetailButton = (order: any) => {
|
||||
return (
|
||||
hasFooterOperate('qrCodeDetail') &&
|
||||
String(order?.orderStatus) === '5' &&
|
||||
['2'].includes(String(order?.orderType))
|
||||
)
|
||||
}
|
||||
|
||||
// 手动核销按钮显示条件:
|
||||
// 1. footerOperate 允许 cancel;
|
||||
// 2. 订单状态为 5;
|
||||
// 3. 订单类型为 2。
|
||||
// 4. 用户有'移动端商户角色'
|
||||
const showCancelButton = (order: any) => {
|
||||
return (
|
||||
hasFooterOperate('cancel') &&
|
||||
String(order?.orderStatus) === '5' &&
|
||||
['2'].includes(String(order?.orderType)) && hasRoleCode(MCH_USER)
|
||||
)
|
||||
}
|
||||
|
||||
// 查看订单和核销码
|
||||
const doToDetail = (v: any) => {
|
||||
router.jump("/pages/order/detail", { id: v.id })
|
||||
}
|
||||
|
||||
// 申请售后
|
||||
const doRefund = (v: any) => {
|
||||
router.jump("/pages/refund/apply", { id: v.id })
|
||||
}
|
||||
|
||||
const doCancel = (v: any) => {
|
||||
emit('cancel', v)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="flex-col justify-center pb-20rpx gap-20rpx"
|
||||
:class="!props.isLast && props.visibleBottomBorder ? 'car-border' : ''">
|
||||
<!-- start 用户信息 start -->
|
||||
<view v-if="props.visibleUser" class="flex items-start justify-between gap-16rpx">
|
||||
<view class="min-w-0 flex-1">
|
||||
<view class="flex items-center min-w-0">
|
||||
<text class="sub-text-26 truncate">{{ props.cardetail.username || "未知用户" }}</text>
|
||||
<text class="mx-10rpx text-18rpx text-[#d0d5dd]">|</text>
|
||||
<text class="second-text-24 truncate">{{ props.cardetail.userMobile || "-" }}</text>
|
||||
</view>
|
||||
<view class="mt-10rpx inline-flex max-w-full items-center rounded-24rpx bg-[#f8fafc] px-14rpx py-8rpx">
|
||||
<text class="text-20rpx text-[#98a2b3]">下单时间</text>
|
||||
<text v-if="props.cardetail.createTime" class="ml-10rpx text-20rpx text-[#475467] truncate">
|
||||
{{ hooks.useTime(props.cardetail.createTime, "{y}-{m}-{d} {h}:{i}:{s}") }}
|
||||
</text>
|
||||
<text v-else class="ml-10rpx text-20rpx text-[#1570ef]">正在下单</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-shrink-0">
|
||||
<view class="w-100rpx flex-row-center">
|
||||
<order-status-tag :cardetail="props.cardetail" />
|
||||
</view>
|
||||
<view class="w-100rpx flex-row-center second-text-22 mt-10rpx" v-if="props.cardetail.refundStatus">
|
||||
{{ hooks.useEnum("hardwareRefundStatusEnum", props.cardetail.refundStatus) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end 用户信息 end -->
|
||||
|
||||
<!-- start 商户信息 start -->
|
||||
<view v-if="props.visibleMch" class="flex-row">
|
||||
<image class="size-90rpx rounded-8rpx bg-[#999] shadow-main overflow-hidden"
|
||||
:src="filePath(props.cardetail.logoPic) || '/static/logo/zax.png'" mode="aspectFill" />
|
||||
<view class="flex-1 ml-20rpx">
|
||||
<view class="flex-row items-center justify-between">
|
||||
<view class="sub-text-26">{{ props.cardetail.merchantName }}</view>
|
||||
<view class="w-100rpx flex-row-center">
|
||||
<order-status-tag :cardetail="props.cardetail" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row items-center justify-between second-text-22">
|
||||
<view>
|
||||
<text>下单时间:</text>
|
||||
<text v-if="props.cardetail.createTime" class="ml-10rpx">
|
||||
{{ hooks.useTime(props.cardetail.createTime, "{y}-{m}-{d} {h}:{i}:{s}") }}
|
||||
</text>
|
||||
<text v-else class="ml-10rpx color-blue">正在下单</text>
|
||||
</view>
|
||||
<view class="w-100rpx flex-row-center mt-10rpx" v-if="props.cardetail.refundStatus">
|
||||
{{ hooks.useEnum("hardwareRefundStatusEnum", props.cardetail.refundStatus) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end 商户信息 end -->
|
||||
|
||||
<!-- start 商品信息 start -->
|
||||
<view v-if="props.cardetail?.carList?.length"
|
||||
class="flex items-center rounded-12rpx bg-[#fafafa] px-20rpx py-16rpx transition-all duration-200"
|
||||
@tap="toggleGoodsCollapse(props.cardetail, 0)">
|
||||
<view class="min-w-0 flex-1">
|
||||
<view v-if="isGoodsCollapsed(props.cardetail, 0)" class="flex items-center">
|
||||
<image class="h-90rpx w-120rpx flex-shrink-0 rounded-8rpx bg-[#999] shadow-main overflow-hidden"
|
||||
:src="filePath(props.cardetail.carList?.[0]?.productPic) || '/static/logo/zax.png'"
|
||||
mode="aspectFill" />
|
||||
<view class="ml-16rpx min-w-0 flex-1">
|
||||
<view class="second-text-22 truncate">
|
||||
{{ props.cardetail.carList?.[0]?.productName || "暂无商品" }}
|
||||
</view>
|
||||
<view v-if="hasMultipleGoods(props.cardetail)" class="mt-8rpx text-20rpx text-[#98a2b3]">
|
||||
共 {{ props.cardetail.carList?.length || 0 }} 件,点击展开
|
||||
</view>
|
||||
<view v-else class="mt-8rpx text-20rpx text-[#98a2b3]">共 1 件商品</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view v-if="!isGoodsCollapsed(props.cardetail, 0)" scroll-x
|
||||
class="overflow-hidden whitespace-nowrap">
|
||||
<view class="flex items-start">
|
||||
<view v-for="item in props.cardetail.carList || []" :key="item.id"
|
||||
class="mr-20rpx w-120rpx flex-shrink-0">
|
||||
<image class="h-90rpx w-120rpx rounded-8rpx bg-[#999] shadow-main overflow-hidden"
|
||||
:src="filePath(item.productPic) || '/static/logo/zax.png'" mode="aspectFill" />
|
||||
<view class="second-text-22 mt-8rpx truncate">{{ item.productName }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<view class="order-car__summary w-120rpx flex-col-center">
|
||||
<view class="sub-text-28">¥{{ hooks.useMoney(props.cardetail.payPrice) }}</view>
|
||||
<view class="second-text-20 font-400! line-height-1em!">共 {{ props.cardetail.carList?.length || 0 }} 件
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="hasMultipleGoods(props.cardetail)"
|
||||
class="ml-12rpx flex-col-center text-[#98a2b3] transition-transform duration-200">
|
||||
<text class="text-20rpx">{{ isGoodsCollapsed(props.cardetail, 0) ? "展开" : "收起" }}</text>
|
||||
<text class="iconfont icon-youjiantou mt-8rpx text-20rpx"
|
||||
:class="isGoodsCollapsed(props.cardetail, 0) ? 'rotate-90' : '-rotate-90'" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- end 商品信息 end -->
|
||||
|
||||
<!-- start 简单购买信息(付款方式+支付金额) start -->
|
||||
<view v-if="!props.cardetail?.carList?.length"
|
||||
class="flex items-center justify-between rounded-12rpx border-[#eef3f8] bg-[linear-gradient(90deg,#ffffff_0%,#fafafa_100%)] px-22rpx py-12rpx">
|
||||
<view class="flex-row-center sub-text-24 gap-8rpx">
|
||||
<text class="iconfont icon-zhifufangshi1 text-24rpx!" />
|
||||
<text> {{ hooks.useEnum('hardwarePayTypeEnum', props.cardetail.payType) }}</text>
|
||||
</view>
|
||||
<view class="order-car__summary w-120rpx flex-col-center">
|
||||
<view class="sub-text-28">¥{{ hooks.useMoney(props.cardetail.payPrice) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end 简单购买信息(付款方式+支付金额) end -->
|
||||
|
||||
<!-- start 预约信息 start -->
|
||||
<view v-if="props.cardetail.apptId && props.cardetail.apptStartTime && props.cardetail.apptEndTime"
|
||||
class="flex items-center justify-between rounded-12rpx border border-[#eef3f8] bg-[linear-gradient(90deg,#ffffff_0%,#fafafa_100%)] px-22rpx py-12rpx shadow-[0_8rpx_24rpx_rgba(15,23,42,0.04)]">
|
||||
<view class="min-w-0 flex-1">
|
||||
<view class="second-text-22 text-[#98a2b3]!">预约时间段</view>
|
||||
<view class="mt-10rpx sub-text-24">
|
||||
{{ props.cardetail.apptStartTime }} - {{ props.cardetail.apptEndTime }}
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="props.cardetail.apptTitle"
|
||||
class="flex items-center gap-4rpx ml-20rpx flex-shrink-0 rounded-full border border-[#d1e9ff] bg-[#eff8ff] px-18rpx py-16rpx text-22rpx line-height-1 text-[#1570ef]">
|
||||
<text> {{ props.cardetail.apptUseDate }}</text>
|
||||
<text>{{ props.cardetail.apptTitle }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- end 预约信息 end -->
|
||||
|
||||
<!-- start 底部操作区域 start -->
|
||||
<view
|
||||
v-if="showRefundButton(props.cardetail) || showRefundDetailButton(props.cardetail) || showQrCodeDetailButton(props.cardetail) || showCancelButton(props.cardetail)"
|
||||
class="w-full flex-row items-center justify-end my-1">
|
||||
<view v-if="showRefundButton(props.cardetail)" class="botder_btn" @tap.stop="doRefund(props.cardetail)">
|
||||
退款
|
||||
</view>
|
||||
<view v-if="showRefundDetailButton(props.cardetail)" class="m-l-20rpx botder_btn"
|
||||
@tap.stop="doToDetail(props.cardetail)">
|
||||
售后详情
|
||||
</view>
|
||||
<view v-if="showQrCodeDetailButton(props.cardetail)" class="m-l-20rpx botder_btn"
|
||||
@tap.stop="doToDetail(props.cardetail)">
|
||||
核销码
|
||||
</view>
|
||||
<view v-if="showCancelButton(props.cardetail)" class="m-l-20rpx botder_btn"
|
||||
@tap.stop="doCancel(props.cardetail)">
|
||||
手动核销
|
||||
</view>
|
||||
</view>
|
||||
<!-- end 底部操作区域 end -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.car-border {
|
||||
border-bottom: 1px solid #fafafa;
|
||||
}
|
||||
|
||||
.order-car__summary {
|
||||
position: relative;
|
||||
padding-left: 18rpx;
|
||||
}
|
||||
|
||||
.order-car__summary::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -8rpx;
|
||||
top: 8rpx;
|
||||
bottom: 8rpx;
|
||||
width: 20rpx;
|
||||
pointer-events: none;
|
||||
background: linear-gradient(90deg, rgba(15, 23, 42, 0.08) 0%, rgba(15, 23, 42, 0.03) 38%, rgba(15, 23, 42, 0) 100%);
|
||||
filter: blur(8rpx);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
export type Props = {
|
||||
// 订单详情
|
||||
cardetail: any
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
cardetail: {},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<slot v-if="props.cardetail.orderStatus == 5">
|
||||
<tm-tag v-if="props.cardetail.orderType == 2" color="success" size="xs">待使用</tm-tag>
|
||||
<tm-tag v-else-if="props.cardetail.orderType == 7" color="success" size="xs">待发货</tm-tag>
|
||||
<tm-tag v-else color="success" size="xs">已支付</tm-tag>
|
||||
</slot>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 200" color="success" size="xs">待发货</tm-tag>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 210" color="success" size="xs">待收货</tm-tag>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 220" size="xs">已收货</tm-tag>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 230" color="success" size="xs">已评价</tm-tag>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 10" color="error" size="xs">售后</tm-tag>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 20" size="xs">已核销</tm-tag>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 30" color="info" size="xs">已取消(智能柜)</tm-tag>
|
||||
<tm-tag v-if="props.cardetail.orderStatus == 110" color="success" size="xs">配送中</tm-tag>
|
||||
</template>
|
||||
@@ -36,6 +36,13 @@ const hardwareRefundStatusEnum = {
|
||||
30: "售后失败",
|
||||
}
|
||||
|
||||
const hardSaleStatusEnum = {
|
||||
0: "售后中",
|
||||
50: "售后完成",
|
||||
61: "买家取消",
|
||||
62: "卖家拒绝",
|
||||
}
|
||||
|
||||
const carTypeEnum = {
|
||||
1: "私家车",
|
||||
2: "公车",
|
||||
@@ -98,4 +105,5 @@ export default {
|
||||
actCouponLimitTypeEnum,
|
||||
actCouponTypeEnum,
|
||||
actUserReceiveEnum,
|
||||
hardSaleStatusEnum,
|
||||
}
|
||||
@@ -7,6 +7,7 @@ export function useScanCode(actModalShow) {
|
||||
const appInfo = await getAppInfo()
|
||||
|
||||
if (isDevEnv()) {
|
||||
let testQrCode = ""
|
||||
// 开发环境模拟扫码
|
||||
// const testQrCode = "eyJpZCI6IjE5MDU4ODg4NjQ0NTQ1MzMxMjEiLCJuYW1lIjoi6ICB5Y6/5bqc6aOf5aCCIn0=" // 测试线上-老县府食堂-收款二维码
|
||||
// const testQrCode = "eyJoYXJkRG9vcklkIjoiMTkxNDIxNTYwODQzNzQxMTg0MSIsImNhYmluZXRObyI6IjEifQ==" // 测试线上-智能柜-收款二维码
|
||||
@@ -15,7 +16,13 @@ export function useScanCode(actModalShow) {
|
||||
// const testQrCode = "http://192.168.101.45:8889/h5/#/pages/pay/scanPay?id=1905816751043452930&name=测试新县府超市" // 邓本地-测试环境-新县府超市收款二维码
|
||||
// const testQrCode = "http://192.168.101.45:8889/h5/#/pages/pay/scanPay?hardDoorId=1913157080418295809&cabinetNo=1" // 测试智能柜柜门二维码
|
||||
// const testQrCode = "eyJjYW5jZWxJZCI6IjE5ODQyNDA4MzM5NDMyMDc5MzcifQ==" // 测试商户活动核销
|
||||
const testQrCode = "https://stgl.pj.gov.cn/h5/#/pages/pay/scanPay?id=1931916121241079810"
|
||||
// const testQrCode = "https://stgl.pj.gov.cn/h5/#/pages/pay/scanPay?id=1931916121241079810"
|
||||
// 测试环境(自营食堂)-新县府食堂
|
||||
// testQrCode = "https://stgl.pj.gov.cn/h5/#/pages/pay/scanPay?id=1905816666859577346"
|
||||
// 测试环境(合作商家)-测试部门超市
|
||||
testQrCode = "https://stgl.pj.gov.cn/h5/#/pages/pay/scanPay?id=1931916121241079810"
|
||||
// 测试环境(自营商家)-老县府超市
|
||||
// testQrCode = "https://stgl.pj.gov.cn/h5/#/pages/pay/scanPay?id=1905816898011865090"
|
||||
uni.showModal({ content: "开发环境不是浙政钉和诗画环境,扫码仅供测试" })
|
||||
return Promise.resolve(testQrCode)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
@font-face {
|
||||
font-family: "iconfont";
|
||||
/* Project id 4740692 */
|
||||
src: url('//at.alicdn.com/t/c/font_4740692_uwg9mtj0d0p.woff2?t=1770172172940') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_4740692_uwg9mtj0d0p.woff?t=1770172172940') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_4740692_uwg9mtj0d0p.ttf?t=1770172172940') format('truetype');
|
||||
src: url('https://at.alicdn.com/t/c/font_4740692_ol93veips6n.woff2?t=1782372215492') format('woff2'),
|
||||
url('https://at.alicdn.com/t/c/font_4740692_ol93veips6n.woff?t=1782372215492') format('woff'),
|
||||
url('https://at.alicdn.com/t/c/font_4740692_ol93veips6n.ttf?t=1782372215492') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@@ -14,6 +14,114 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-jisuwuliu:before {
|
||||
content: "\e61a";
|
||||
}
|
||||
|
||||
.icon-add:before {
|
||||
content: "\e79e";
|
||||
}
|
||||
|
||||
.icon-add1:before {
|
||||
content: "\e6aa";
|
||||
}
|
||||
|
||||
.icon-bianji:before {
|
||||
content: "\e763";
|
||||
}
|
||||
|
||||
.icon-address1:before {
|
||||
content: "\e605";
|
||||
}
|
||||
|
||||
.icon-address:before {
|
||||
content: "\e659";
|
||||
}
|
||||
|
||||
.icon-address-f:before {
|
||||
content: "\e604";
|
||||
}
|
||||
|
||||
.icon-zhifufangshi:before {
|
||||
content: "\e759";
|
||||
}
|
||||
|
||||
.icon-zhifufangshi-yuezhifu:before {
|
||||
content: "\e68c";
|
||||
}
|
||||
|
||||
.icon-zhifufangshi1:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
.icon-rili:before {
|
||||
content: "\e60e";
|
||||
}
|
||||
|
||||
.icon-hexiaoicon:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.icon-hexiao1:before {
|
||||
content: "\e7fe";
|
||||
}
|
||||
|
||||
.icon-hexiao:before {
|
||||
content: "\e63f";
|
||||
}
|
||||
|
||||
.icon-fanhui:before {
|
||||
content: "\e8fb";
|
||||
}
|
||||
|
||||
.icon-tongzhi:before {
|
||||
content: "\e61b";
|
||||
}
|
||||
|
||||
.icon-dangqianweizhi:before {
|
||||
content: "\e678";
|
||||
}
|
||||
|
||||
.icon-sousuo:before {
|
||||
content: "\e619";
|
||||
}
|
||||
|
||||
.icon-yizuofei1:before {
|
||||
content: "\e60d";
|
||||
}
|
||||
|
||||
.icon-yizuofei:before {
|
||||
content: "\f2d8";
|
||||
}
|
||||
|
||||
.icon-jilu1:before {
|
||||
content: "\e631";
|
||||
}
|
||||
|
||||
.icon-jilu:before {
|
||||
content: "\e664";
|
||||
}
|
||||
|
||||
.icon-kefu:before {
|
||||
content: "\e677";
|
||||
}
|
||||
|
||||
.icon-kefu1:before {
|
||||
content: "\e612";
|
||||
}
|
||||
|
||||
.icon-info:before {
|
||||
content: "\e64a";
|
||||
}
|
||||
|
||||
.icon-setting:before {
|
||||
content: "\e8d8";
|
||||
}
|
||||
|
||||
.icon-shezhi:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.icon-yiguoqi:before {
|
||||
content: "\e642";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import { constant } from "@@/index"
|
||||
import { userApi } from "@@/api"
|
||||
|
||||
export const ROLE_ONLINE_CANTEEN_MCH = "ONLINE_CANTEEN_MCH"
|
||||
export const ROLE_CANTEEN_RIDER = "CANTEEN_RIDER"
|
||||
// 移动端商户角色(核销订餐二维码)
|
||||
export const MCH_USER = "MCH_USER"
|
||||
/** 移动端后台管理入口角色 */
|
||||
export const ROLE_MOBILE_ADMIN_PC = "MOBILE_ADMIN_PC"
|
||||
/** 新增用户默认角色 */
|
||||
export const ROLE_GENERAL_USER = "GENERAL_USER"
|
||||
export const ROLE_WALLET_AUTO_CREATE = "WALLET_AUTO_CREATE"
|
||||
|
||||
const DEFAULT_NEW_USER_ROLES = [
|
||||
{ roleCode: ROLE_GENERAL_USER, roleId: "2" },
|
||||
{ roleCode: ROLE_WALLET_AUTO_CREATE, roleId: "1873557615006810113" },
|
||||
] as const
|
||||
|
||||
/** 新增用户时默认勾选的角色 ID(优先按 roleCode 从列表解析) */
|
||||
export const resolveDefaultNewUserRoleIds = (roleList: { roleId?: string | number; roleCode?: string }[]): string[] =>
|
||||
DEFAULT_NEW_USER_ROLES.map(({ roleCode, roleId }) => {
|
||||
const hit = roleList.find((r) => r.roleCode === roleCode)
|
||||
return hit ? String(hit.roleId) : roleId
|
||||
})
|
||||
|
||||
export const getUserRoleCodes = (): string[] => {
|
||||
const userInfo: any = uni.getStorageSync(constant.storageConstant.USERINFO) || {}
|
||||
const codes = userInfo?.roleCodes
|
||||
if (Array.isArray(codes)) return codes.filter(Boolean)
|
||||
return []
|
||||
}
|
||||
|
||||
export const hasRoleCode = (code: string) => getUserRoleCodes().includes(code)
|
||||
|
||||
/** 刷新用户信息中的 roleCodes(我的页菜单、统计页鉴权用) */
|
||||
export const refreshUserRoleCodes = async (): Promise<string[]> => {
|
||||
try {
|
||||
const res: any = await userApi.userInfo()
|
||||
if (res?.code === 0 && res.data) {
|
||||
uni.setStorageSync(constant.storageConstant.USERINFO, res.data)
|
||||
return Array.isArray(res.data.roleCodes) ? res.data.roleCodes : []
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("refreshUserRoleCodes failed", e)
|
||||
}
|
||||
return getUserRoleCodes()
|
||||
}
|
||||
|
||||
/** 移动端后台管理 - 权限码(与 PC 角色菜单分配一致) */
|
||||
export const PERM_SYS_USER_ADD = "sys_user_add"
|
||||
export const PERM_SYS_USER_EDIT = "sys_user_edit"
|
||||
export const PERM_SYS_USER_DEL = "sys_user_del"
|
||||
export const PERM_WALLET_MANAGE_VIEW = "wallet_walletManage_view"
|
||||
export const PERM_WALLET_MANAGE_EDIT = "wallet_walletManage_edit"
|
||||
export const PERM_WALLET_UPDATE_BALANCE = "wallet_walletTransaction_update_balance"
|
||||
|
||||
export const ADMIN_USER_PERMS = [PERM_SYS_USER_ADD, PERM_SYS_USER_EDIT, PERM_SYS_USER_DEL]
|
||||
export const ADMIN_WALLET_PERMS = [PERM_WALLET_MANAGE_VIEW, PERM_WALLET_MANAGE_EDIT, PERM_WALLET_UPDATE_BALANCE]
|
||||
export const ADMIN_HUB_PERMS = [...ADMIN_USER_PERMS, ...ADMIN_WALLET_PERMS]
|
||||
|
||||
export const getUserPermissions = (): string[] => {
|
||||
const userInfo: any = uni.getStorageSync(constant.storageConstant.USERINFO) || {}
|
||||
const perms = userInfo?.permissions
|
||||
if (Array.isArray(perms)) return perms.filter(Boolean)
|
||||
return []
|
||||
}
|
||||
|
||||
export const hasPermission = (code: string) => getUserPermissions().includes(code)
|
||||
|
||||
export const hasAnyPermission = (codes: string[]) => codes.some((code) => hasPermission(code))
|
||||
|
||||
/** 刷新 permissions(顺带刷新 roleCodes) */
|
||||
export const refreshUserPermissions = async (): Promise<string[]> => {
|
||||
await refreshUserRoleCodes()
|
||||
return getUserPermissions()
|
||||
}
|
||||
Reference in new issue
Block a user