This commit is contained in:
dzc committed 2024-11-18 08:03:34 +08:00
1 parent 544fb32762
commit b85ec93e7a
10 files changed
+379 -46

No files matched your search

+19
View File
@@ -159,6 +159,25 @@
}
]
},
{
"root": "pages/refund",
"pages": [
{
"path": "apply",
"style": {
"navigationBarTitleText": "",
"disableScroll": true
}
},
{
"path": "history",
"style": {
"navigationBarTitleText": "",
"disableScroll": true
}
}
]
},
{
"root": "pages/wallet",
"pages": [
+70 -2
View File
@@ -4,7 +4,7 @@ import { onLoad, onShow } from "@dcloudio/uni-app";
import { isEmpty } from "radash"
import { hooks, constant, router } from "@@/index"
import { orderApi } from "@@/api"
import { orderApi, refundApi } from "@@/api"
const data = {
@@ -12,6 +12,7 @@ const data = {
const state = reactive<any>({
detailId: null,
detail: {},
refundDetail: {},
shopCarList: [],
})
@@ -30,6 +31,9 @@ const getDetail = async () => {
const _pa = { id: state.detailId };
const { data } = await orderApi.detail(_pa)
state.detail = data
if (state.detail.orderStatus == 10) {
getRefundDetail()
}
}
const getShopCarList = async () => {
@@ -39,6 +43,24 @@ const getShopCarList = async () => {
state.shopCarList = data
}
const getRefundDetail = async () => {
if (isEmpty(state.detailId)) return
const _pa = { id: state.detailId };
const { data } = await refundApi.get(_pa)
state.refundDetail = data
}
const doCancelRefund = async () => {
uni.showModal({
title: '提示',
content: '是否确定取消申请退款',
confirmColor: '#0094ff',
success: async (res) => {
}
})
}
</script>
@@ -89,7 +111,7 @@ const getShopCarList = async () => {
<view class="flex-row items-start justify-between" v-for="(v, i) in state.shopCarList" :key="i"
@tap.stop="router.jump('/pages/merchant/product-detail', { id: v.productId })">
<view class="flex-row items-center">
<image class="w-160rpx h-160rpx" :src="v.productPic" mode="aspectFill" />
<image class="w-160rpx h-160rpx rounded-8rpx" :src="v.productPic" mode="aspectFill" />
<view class="flex-col m-l-15rpx second-text-26">
<view class="sub-text-28">{{ v.productName }}</view>
<view class="m-t-5rpx">¥ {{ hooks.useMoney(v.productPrice) }}</view>
@@ -110,6 +132,52 @@ const getShopCarList = async () => {
</view>
</view>
</view>
<!-- start 退款相关 start -->
<slot v-if="state.detail.orderStatus == 10">
<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>退款申请待商家处理</view>
</view>
<view class="m-t-10rpx second-text-26">
{{ hooks.useTime(state.refundDetail.updateTime, "") }}
</view>
</view>
<view class="m-l-15rpx color-#999 font-size-26rpx! iconfont icon-youjiantou" />
</view>
<view class="flex-row items-center justify-between card p-x-20rpx p-y-30rpx m-b-20rpx">
<view class="sub-text-28">退款金额</view>
<view class="sub-text-28 color-red!">¥{{ hooks.useMoney(state.refundDetail.refundPrice) }}</view>
</view>
<view 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.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>
</slot>
<!-- end 退款相关 end -->
<view class="h-30rpx" />
<template #main-bottom>
<view v-if="state.detail.orderStatus == 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>
</template>
</crud-layout>
</template>
+185
View File
@@ -0,0 +1,185 @@
<script setup lang="ts">
import { ref, reactive } from "vue";
import { onLoad, onShow } from "@dcloudio/uni-app";
import { isEmpty } from "radash"
import { hooks, router } from "@@/index"
import { orderApi, refundApi, commonApi } from "@@/api"
const data = {
payType: [
{ text: "仅退款", disabled: false, type: "10", value: "10" },
{ text: "退款退货", disabled: false, type: "20", value: "20" },
]
}
const state = reactive<any>({
detailId: null,
detail: {},
shopCarList: [],
setting: {},
selectList: []
})
const applyForm = reactive<any>({
way: data.payType[0].type,
remark: "",
reason: "",
reasonStr: "",
})
onLoad((options: any) => {
if (!isEmpty(options.id)) {
state.detailId = options.id
}
});
onShow(() => {
getDetail()
getSetting()
getShopCarList()
})
const getSetting = async () => {
const _pa = {};
const { data } = await commonApi.setting(_pa)
state.setting = data
state.selectList = data.afterSaleRefundReasons.map(v => {
return {
id: v,
title: v,
}
})
}
const getDetail = async () => {
if (isEmpty(state.detailId)) return
const _pa = { id: state.detailId };
const { data } = await orderApi.detail(_pa)
state.detail = data
}
const getShopCarList = async () => {
if (isEmpty(state.detailId)) return
const _pa = { orderId: state.detailId };
const { data } = await orderApi.shopCarList(_pa)
state.shopCarList = data
}
const radioChange = (e: any) => {
switch (e) {
case "10":
state.selectList = state.setting.afterSaleRefundReasons.map(v => {
return {
id: v,
title: v,
}
})
break
case "20":
state.selectList = state.setting.afterSaleReturnReasons.map(v => {
return {
id: v,
title: v,
}
})
break
}
}
const doSubmit = async () => {
if (isEmpty(applyForm.reasonStr)) {
uni.showToast({ title: '请选择申请原因', icon: "none" });
return
}
const _pa = {
way: applyForm.way,
refundPrice: state.detail.practicalTotalPrice,
orderItemId: state.detailId,
images: [],
applyReason: applyForm.reasonStr,
applyDescription: applyForm.remark,
}
try {
uni.showLoading({ title: '申请中...', mask: false });
const data = await refundApi.create(_pa)
uni.hideLoading()
uni.showToast({ title: '申请成功', icon: "none" });
} catch (error) {
console.error(error);
uni.hideLoading()
}
}
</script>
<template>
<crud-layout title="申请售后" mainIsScroll bg="/static/page/blue-bg.png">
<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/merchant/product-detail', { id: v.productId })">
<view class="flex-row items-center">
<image class="w-160rpx h-160rpx rounded-8rpx" :src="v.productPic" mode="aspectFill" />
<view class="flex-col m-l-15rpx second-text-26">
<view class="sub-text-28">{{ v.productName }}</view>
<view class="m-t-5rpx">¥ {{ hooks.useMoney(v.productPrice) }}</view>
<view class="m-t-5rpx">x {{ v.productCount }}</view>
</view>
</view>
<view class="flex-row-center">
<view class="sub-text-32">¥ {{ hooks.useMoney(v.totalPrice) }}</view>
</view>
</view>
<view class="m-y-15rpx h-1px bg-#999 bg-opacity-5" />
<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.detail.practicalTotalPrice) }}</view>
</view>
</view>
</view>
</view>
<view class="card p-x-20rpx p-y-30rpx m-b-20rpx">
<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" :value="v.type"
:label="v.text" />
</tm-radio-group>
</view>
</view>
<view class="flex-row items-center justify-between card p-x-20rpx p-y-30rpx m-b-20rpx">
<view class="sub-text-28">退款金额</view>
<view class="sub-text-28 color-red!">¥{{ hooks.useMoney(state.detail.practicalTotalPrice) }}</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">
<view class="flex-row items-center justify-between">
<view class="sub-text-28">申请原因</view>
<view class="flex-row items-center second-text-24">
<text>{{ applyForm.reasonStr || '请选择申请原因' }} </text>
<text class="m-l-10rpx color-#b1b1b1 iconfont icon-xiangxiajiantouxiao" />
</view>
</view>
</tm-picker>
</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>
</view>
</view>
<view class="h-30rpx" />
<template #main-bottom>
<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">
提交申请
</view>
</template>
</crud-layout>
</template>
<style lang="scss" scoped></style>
+32
View File
@@ -0,0 +1,32 @@
<script setup lang="ts">
import { ref, reactive } from "vue";
import { onLoad, onShow } from "@dcloudio/uni-app";
import { hooks } from "@@/index"
import { foodApi } from "@@/api"
const data = {
}
const state = reactive<any>({
})
onLoad(() => {
});
onShow(() => {
})
</script>
<template>
<crud-layout mainIsScroll title="售后进度" bg="/static/page/blue-bg.png">
<view class="h-30rpx" />
<view class="h-30rpx" />
</crud-layout>
</template>
<style lang="scss" scoped></style>
+4 -2
View File
@@ -12,7 +12,7 @@ const data = {
{ id: null, name: '全部', disabled: false },
{ id: 1, name: '未支付', disabled: false },
{ id: 5, name: '待核销', disabled: false },
{ id: 10, name: '已退款', disabled: false },
{ id: 10, name: '售后中', disabled: false },
{ id: 15, name: '已核销', disabled: false },
]
}
@@ -51,6 +51,8 @@ const doAppraise = () => {
}
const doRefund = (v: any) => {
router.jump("/pages/refund/apply", { id: v.id })
return
uni.showModal({
title: '提示',
content: '是否确定退款',
@@ -100,7 +102,7 @@ const doRefund = (v: any) => {
</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 == 10" color="error" size="xs">售后中</tm-tag>
<tm-tag v-if="v.orderStatus == 15" size="xs">已核销</tm-tag>
</view>
<view class="m-t-5rpx">
+11 -1
View File
@@ -1,3 +1,13 @@
import request from "@/sheep/utils/request";
export default {};
export default {
setting: (params: any) =>
request({
url: "pay/setting/get",
method: "GET",
params,
custom: {
showLoading: false,
},
}),
};
+2
View File
@@ -14,6 +14,8 @@ export { default as payApi } from "./pay";
export { default as productApi } from "./product";
export { default as refundApi } from "./refund";
export { default as userApi } from "./user";
export { default as walletApi } from "./wallet";
+18
View File
@@ -0,0 +1,18 @@
import request from "@/sheep/utils/request";
export default {
create: (data) => {
return request({
url: "/hardware/trade-after-sale/create",
method: "POST",
data,
});
},
get: (params) => {
return request({
url: "/hardware/trade-after-sale/get-by-order-id",
method: "GET",
params,
});
},
};
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

@@ -1,5 +1,5 @@
<script lang="ts" setup>
import { ref, computed, onMounted, onBeforeUnmount, watch, PropType, getCurrentInstance, ComponentInstance, onUpdated, nextTick, VueElement, inject } from 'vue';
import { ref, computed, onMounted, onBeforeUnmount, watch, type PropType, getCurrentInstance, type ComponentInstance, onUpdated, nextTick, VueElement, inject } from 'vue';
import { arrayNumberValid, arrayNumberValidByStyleMP, covetUniNumber, arrayNumberValidByStyleBorderColor, linearValid, getUnit, getUid } from "../../libs/tool";
import { getDefaultColor, getDefaultColorObj, getOutlineColorObj, getTextColorObj, getThinColorObj } from "../../libs/colors";
import { useTmConfig } from "../../libs/config";
@@ -54,7 +54,7 @@ const props = defineProps({
* 当前选中项的id值
*/
modelValue: {
type: Array<string|number>,
type: Array<string | number>,
default: (): string[] => [] as string[]
},
/**
@@ -96,7 +96,7 @@ const props = defineProps({
const _cellUnits = computed(() => props.cellUnits)
const _list = computed(() => props.list)
const _nowShowList = ref<Record<string,any>[][]>([])
const _nowShowList = ref<Record<string, any>[][]>([])
const _maxDeep = computed(() => {
if (_list.value.length == 0) return 0;
function getdiepWidth(list: TM_PICKER_X_ITEM[]): number {
@@ -114,28 +114,28 @@ const _maxDeep = computed(() => {
const oninitFun = () => {
nowValue.value = props.modelValue.slice(0)
let currneinexs = getIndexsByids(nowValue.value).indexs;
_modelValueIndex.value = nowValue.value.length==0||currneinexs.length==0?new Array(_maxDeep.value).fill(0):currneinexs;
const {data,strs,ids} = getIdsByindexs(_modelValueIndex.value)
_modelValueIndex.value = nowValue.value.length == 0 || currneinexs.length == 0 ? new Array(_maxDeep.value).fill(0) : currneinexs;
const { data, strs, ids } = getIdsByindexs(_modelValueIndex.value)
_nowShowList.value = data.slice(0)
if(nowValue.value.length==0){
nowValue.value = ids.slice(0)
nextTick(()=>{
emits('update:modelStr', strs.join(","))
emits('update:modelValue', ids.slice(0))
})
if (nowValue.value.length == 0) {
nowValue.value = ids.slice(0)
nextTick(() => {
emits('update:modelStr', strs.join(","))
emits('update:modelValue', ids.slice(0))
})
}
}
const change = (ixs: number[]) => {
const {ids,data,strs} = getIdsByindexs(ixs)
const { ids, data, strs } = getIdsByindexs(ixs)
_modelValueIndex.value = getIndexsByids(ids).indexs;
_nowShowList.value = data.slice(0)
nowValue.value = ids;
/**
* 等同v-model
*/
@@ -148,14 +148,14 @@ const change = (ixs: number[]) => {
// 根据id返回索引
const getIndexsByids = (ids:Array<string|number>):{indexs:Array<number>,data:TM_PICKER_X_ITEM[][],strs:string[]}=> {
const getIndexsByids = (ids: Array<string | number>): { indexs: Array<number>, data: TM_PICKER_X_ITEM[][], strs: string[] } => {
let index = 0;
let val = ids.slice(0)
let indexs = [] as number[]
let data = [] as TM_PICKER_X_ITEM[][]
let strs = [] as string[]
if(_list.value.length==0||ids.length==0) return {indexs:[],data:[],strs:[]}
if (_list.value.length == 0 || ids.length == 0) return { indexs: [], data: [], strs: [] }
function getIndex(nodes: TM_PICKER_X_ITEM[]) {
if (val.length <= index || val.length == 0) return;
@@ -176,47 +176,47 @@ const getIndexsByids = (ids:Array<string|number>):{indexs:Array<number>,data:TM_
}
}
getIndex(_list.value)
return {indexs,data,strs}
return { indexs, data, strs }
}
//根据索引返回ids
const getIdsByindexs = (indexs:number[]):{ids:Array<string|number>,data:TM_PICKER_X_ITEM[][],strs:string[]} => {
const getIdsByindexs = (indexs: number[]): { ids: Array<string | number>, data: TM_PICKER_X_ITEM[][], strs: string[] } => {
let ids = [] as string[]
let data = [] as TM_PICKER_X_ITEM[][]
let index = 0;
let val = indexs.slice(0)
let strs = [] as string[]
if(_list.value.length==0||indexs.length==0) return {ids:[],data:[],strs:[]}
if (_list.value.length == 0 || indexs.length == 0) return { ids: [], data: [], strs: [] }
function getIds(nodes: TM_PICKER_X_ITEM[]) {
if (val.length <= index || val.length == 0) return;
let currentsIndex = val[index]
let id = ''
let str = ''
let children = [];
if(nodes.length-1 >= currentsIndex){
if (nodes.length - 1 >= currentsIndex) {
id = nodes[currentsIndex][props.rangKey]
str = nodes[currentsIndex][props.rangText]
children = nodes[currentsIndex]?.children??[]
}else{
children = nodes[currentsIndex]?.children ?? []
} else {
id = nodes[0][props.rangKey]
str = nodes[0][props.rangText]
children = nodes[0]?.children??[]
children = nodes[0]?.children ?? []
}
ids.push(id)
data.push(nodes)
strs.push(str)
if(children.length>0){
if (children.length > 0) {
index += 1
getIds(children)
}
}
getIds(_list.value)
return {ids,data,strs};
return { ids, data, strs };
}
const getNowCurrent = ()=>{
return getIdsByindexs(_modelValueIndex.value)
const getNowCurrent = () => {
return getIdsByindexs(_modelValueIndex.value)
}
// 获取相关数据。
@@ -233,11 +233,11 @@ onBeforeUnmount(() => {
watch(() => props.modelValue, (newValue: Array<string | number>) => {
if (newValue.join('') == nowValue.value.join('')) return;
nowValue.value = newValue.slice(0);
let defauleindexs = nowValue.value.length==0?new Array(_maxDeep.value).fill(0):getIndexsByids(nowValue.value).indexs;
let defauleindexs = nowValue.value.length == 0 ? new Array(_maxDeep.value).fill(0) : getIndexsByids(nowValue.value).indexs;
_modelValueIndex.value = defauleindexs;
const {data,strs} = getIdsByindexs(_modelValueIndex.value)
const { data, strs } = getIdsByindexs(_modelValueIndex.value)
_nowShowList.value = data.slice(0)
emits('update:modelStr', strs.join(","))
@@ -248,7 +248,7 @@ watch(() => props.list, (newValue) => {
oninitFun()
}, { deep: true })
defineExpose({getIndexsByids,getIdsByindexs,getNowCurrent,onInit:oninitFun})
defineExpose({ getIndexsByids, getIdsByindexs, getNowCurrent, onInit: oninitFun })
</script>
<script lang="ts">
@@ -263,14 +263,11 @@ export default {
</script>
<template>
<view class="tmPickerView">
<picker-item :rangKey="props.rangKey" :rangText="props.rangText"
:font-size="props.fontSize" :cellUnits="_cellUnits" @changeDeep="change"
:selectedIndex="_modelValueIndex" :list="_nowShowList"
<picker-item :rangKey="props.rangKey" :rangText="props.rangText" :font-size="props.fontSize"
:cellUnits="_cellUnits" @changeDeep="change" :selectedIndex="_modelValueIndex" :list="_nowShowList"
class="tmPickerViewItem"></picker-item>
</view>
</template>
<style scoped>
.tmPickerView {
}
.tmPickerView {}
</style>