Compare commits

3 Commits

Author SHA1 Message Date
3055d49644 Merge branch 'fix-109' of https://git.nianxx.cn/zoujing/YGChatCS 2025-10-20 18:28:02 +08:00
a08f3b65be feat: 问题反馈调整 2025-10-20 18:27:49 +08:00
duanshuwen
05569374cc feat: 呼叫服务页面布局调整 2025-10-20 18:27:47 +08:00
12 changed files with 80 additions and 718 deletions

View File

@@ -64,7 +64,6 @@ const workOrderTypeId = ref("");
const contactPhone = ref("");
const contactText = ref("");
const isCallSuccess = ref(false); // 呼叫成功状态
const workOrderId = ref(0); // 工单ID
const appName = computed(() => getCurrentConfig().name);
const handleCall = async () => {
@@ -99,26 +98,23 @@ const sendCreateWorkOrder = async () => {
});
if (res.code === 0) {
// 保存工单ID
workOrderId.value = res.data?.id || "";
// 设置呼叫成功状态
// 设置成功状态
isCallSuccess.value = true;
uni.showToast({
title: "工单创建成功",
title: "反馈意见成功",
icon: "success",
duration: 2000,
});
} else {
uni.showToast({
title: res.message || "创建工单失败",
title: res.message || "反馈意见失败",
icon: "none",
duration: 2000,
});
}
} catch (error) {
console.error("创建工单失败:", error);
console.error("反馈意见失败:", error);
uni.showToast({
title: "网络错误,请重试",
icon: "none",
@@ -127,15 +123,6 @@ const sendCreateWorkOrder = async () => {
}
};
// 查看工单
const viewWorkOrder = () => {
console.log("查看工单:", workOrderId.value);
// 这里可以跳转到工单详情页面
uni.navigateTo({
url: `/pages-order/order/list?id=${workOrderId.value}`,
});
};
onMounted(() => {
nextTick(() => {
setTimeout(() => {

View File

@@ -1,26 +0,0 @@
<template>
<view class="info-row flex items-center mt-8">
<text class="label font-size-12 color-99A0AE">{{ label }}</text>
<text class="value flex-full font-size-12 color-99A0AE">{{ value }}</text>
</view>
</template>
<script setup>
import { defineProps } from "vue";
// Props
const props = defineProps({
label: {
type: String,
required: true,
default: "",
},
value: {
type: [String, Number],
required: true,
default: "",
},
});
</script>
<style scoped lang="scss"></style>

View File

@@ -1,127 +0,0 @@
<template>
<view class="card-content border-box pt-12">
<view class="flex items-center justify-between">
<view
class="left flex-full font-size-14 line-height-20 color-171717 mr-12"
>
{{ orderData.commodityName }}
</view>
<view class="right font-size-18 font-bold line-height-20 color-525866">
{{ orderData.orderAmt }}
</view>
</view>
<!-- 动态渲染信息行 -->
<InfoRow
v-for="item in displayItems"
:key="item.label"
:label="item.label"
:value="item.value"
/>
</view>
</template>
<script setup>
import { defineProps, computed } from "vue";
import InfoRow from "./InfoRow.vue";
// 订单类型常量
const ORDER_TYPES = {
HOTEL: "0", // 酒店订单
TICKET: "1", // 门票订单
OTHER: "2", // 其他订单
};
// 标签常量
const LABELS = {
CHECK_IN_TIME: "入住时间",
VISITOR_NAME: "游客姓名",
CONTACT_PHONE: "联系电话",
QUANTITY: "份数",
CREATE_TIME: "创建时间",
CONTACT_GUEST: "联系房客",
};
// Props
const props = defineProps({
orderData: {
type: Object,
required: true,
default: () => ({
orderType: undefined,
orderId: "",
checkInTime: "",
visitorName: "",
contactPhone: "",
userName: "",
userPhone: "",
commodityAmount: 0,
createTime: "",
}),
},
});
// 格式化份数
const formatQuantity = (amount) => {
return `${Math.floor(amount || 0)}`;
};
// 计算显示项目
const displayItems = computed(() => {
const { orderData } = props;
const { orderType } = orderData;
// 工单情况orderType 为 undefined
if (orderType === undefined) {
return [
{ label: LABELS.CREATE_TIME, value: orderData.createTime },
{ label: LABELS.CONTACT_GUEST, value: orderData.userName },
{ label: LABELS.CONTACT_PHONE, value: orderData.userPhone },
];
}
// 订单情况:根据 orderType 返回不同的显示项
switch (orderType) {
case ORDER_TYPES.HOTEL:
return [
{
label: LABELS.CHECK_IN_TIME,
value:
orderData.checkInData?.replace(
/(\d{4})-(\d{1,2})-(\d{1,2})/,
"$2月$3日"
) +
"-" +
orderData.checkOutData?.replace(
/(\d{4})-(\d{1,2})-(\d{1,2})/,
"$2月$3日"
),
},
{ label: LABELS.VISITOR_NAME, value: orderData.visitorName },
{ label: LABELS.CONTACT_PHONE, value: orderData.contactPhone },
];
case ORDER_TYPES.TICKET:
case ORDER_TYPES.OTHER:
return [
{
label: LABELS.QUANTITY,
value: formatQuantity(orderData.commodityAmount),
},
];
default:
// 兜底情况,返回空数组
return [];
}
});
</script>
<style scoped lang="scss">
.right {
&::before {
content: "¥";
font-weight: 500;
font-size: 16px;
}
}
</style>

View File

@@ -1,59 +0,0 @@
// 订单类型
export const ORDER_TYPE_MAP = {
0: [
{
label: '订单编号',
key: 'orderId'
},
{
label: '入住时间',
key: 'checkInData'
},
{
label: '游客姓名',
key: 'visitorName'
},
{
label: '联系电话',
key: 'contactPhone'
}
],
1: [
{
label: '订单编号',
key: 'orderId'
},
{
label: '份数',
key: 'commodityAmount'
}
],
2: [
{
label: '订单编号',
key: 'orderId'
},
{
label: '份数',
key: 'commodityAmount'
}
],
}
// 工单类型
export const SERVICE_TYPE_MAP = {
0: [
{
label: '创建时间',
key: 'createTime'
},
{
label: '联系房客',
key: 'userName'
},
{
label: '联系电话',
key: 'userPhone'
}
],
}

View File

@@ -4,114 +4,76 @@
@click="handleCardClick"
>
<!-- 卡片头部 -->
<view class="card-header flex items-center">
<view class="status-info flex items-center flex-full">
<image class="status-icon mr-4" :src="getStatusIcon()" />
<view class="order-title font-size-14 line-height-20 color-525866">
{{ getOrderTypeName() }}
</view>
</view>
<view
v-if="orderData.status !== 'pending'"
:class="[
'status-tag font-size-12',
`tag-${orderData.orderStatus || orderData.workOrderStatus}`,
]"
<view class="border-box flex flex-items-center pb-12">
<image
class="icon mr-4"
src="https://oss.nianxx.cn/mp/static/version_101/service/service_icon.png"
/>
<text class="font-size-14 color-525866 line-height-20">工单</text>
<text class="font-size-12 color-525866 line-height-20 ml-auto"
>已完成</text
>
{{ getStatusText(orderData.orderStatus || orderData.workOrderStatus) }}
</view>
<!-- 卡片内容 -->
<view class="border-box card-content flex flex-items-center pb-12">
<view class="border-box left flex-full pr-20">
<view class="font-size-12 color-525866 line-height-20 mb-4"
>房间号A01</view
>
<view class="font-size-12 color-525866 line-height-20 mb-4"
>联系方式:173822042402</view
>
<view class="font-size-12 color-525866 line-height-20 ellipsis-2"
>需求描述:我太渴了立即立刻马上现在给我送两瓶水过来我太渴了立即立刻马上现在给我送两瓶水过来我太渴了立即立刻马上现在给我送两瓶水过来我太渴了立即立刻马上现在给我送两瓶水过来</view
>
</view>
<image
class="right rounded-6"
src="https://picsum.photos/300/300"
mode="aspectFill"
/>
</view>
<!-- 卡片内容 -->
<OrderCardContent :order-data="orderData" />
<!-- 服务人员 -->
<view
class="service-user border-box p-8 flex flex-items-center flex-justify-between mb-12"
>
<view class="font-size-12 line-height-16">服务人员张三</view>
<uni-icons
class="ml-auto mr-4"
type="phone-filled"
size="14"
color="#436799"
/>
<text class="font-size-12 line-height-16">拨打电话</text>
</view>
<!-- 取消操作 -->
<view class="flex flex-items-center flex-justify-between">
<text
class="cancel border-box border rounded-6 font-size-12 line-height-16 color-525866 ml-auto"
>取消呼叫</text
>
</view>
</view>
</template>
<script setup>
import { defineProps } from "vue";
import OrderCardContent from "./OrderCardContent.vue";
// Props
const props = defineProps({
orderData: {
item: {
type: Object,
required: true,
default: () => ({
id: "",
workOrderTypeName: "",
createTime: "",
contactName: "",
contactPhone: "",
orderStatus: "0", // pending-待处理, completed-已完成, cancelled-已取消
orderType: undefined, // 0-酒店订单, 1-门票订单, 2-其他订单, undefined-工单
orderNumber: "", // 订单编号
checkInTime: "", // 入住时间
visitorName: "", // 游客姓名
commodityAmount: 0, // 份数
workOrderStatus: 0, // 工单状态0-待处理, 1-已完成
}),
default: () => ({}),
},
});
// Emits
const emit = defineEmits(["click", "call"]);
// 图标映射
const ICON_MAP = {
0: "https://oss.nianxx.cn/mp/static/version_101/order/room.png", // 酒店订单
1: "https://oss.nianxx.cn/mp/static/version_101/order/ticket.png", // 门票订单
2: "https://oss.nianxx.cn/mp/static/version_101/order/food.png", // 餐饮
};
// 订单类型映射
const ORDER_NAME_MAP = {
0: "房间",
1: "门票",
2: "餐饮",
};
// 获取状态图标
const getStatusIcon = () => {
// 订单情况:根据 orderType 返回对应图标
return ICON_MAP[props.orderData.orderType];
};
// 获取订单类型名称
const getOrderTypeName = () => {
return ORDER_NAME_MAP[props.orderData.orderType] || "其他订单";
};
// 获取状态文本
const getStatusText = (status) => {
// 工单情况orderType 为 undefined
if (props.orderData.orderType === undefined) {
const workOrderStatusMap = {
0: "待接单",
1: "处理中",
2: "已完成",
3: "已关闭",
};
return workOrderStatusMap[status] || "未知状态";
}
// 订单情况orderType 有值
const orderStatusMap = {
0: "待支付",
1: "待确认",
2: "待使用",
3: "已取消",
4: "退款中",
5: "已退款",
6: "已完成",
};
return orderStatusMap[status] || "未知状态";
};
// 处理卡片点击
const handleCardClick = () => {
if (props.orderData.orderType === undefined) return;
emit("click", props.orderData);
};
const handleCardClick = () => {};
</script>
<style scoped lang="scss">

View File

@@ -7,37 +7,22 @@
}
}
.status-icon {
width: 20px;
.icon {
height: 20px;
width: 20px;
}
.status-tag {
&.tag-0 {
color: #ff3d60;
}
&.tag-1 {
color: #f00044;
}
&.tag-2 {
color: #40ae36;
}
&.tag-3 {
color: #808389;
}
&.tag-4 {
color: #2d91ff;
}
&.tag-5 {
color: #808389;
}
&.tag-6 {
color: #fd8702;
}
.right {
height: 88px;
width: 88px;
}
.service-user {
background-color: rgba(67, 103, 153, 0.1);
border-radius: 5px;
color: #436799;
}
.cancel {
padding: 4px 10px;
}

View File

@@ -1,208 +0,0 @@
<template>
<view class="order-info">
<view class="order-item">
<text class="label">订单号</text>
<text class="value">{{ orderData.orderId }}</text>
</view>
<view class="order-item">
<text class="label">流水号</text>
<text class="value">{{ orderData.paySerialNumber }}</text>
</view>
<view class="order-item">
<text class="label">支付方式</text>
<text class="value">{{ payWayText }}</text>
</view>
<!-- 在已退款状态显示 -->
<view v-if="orderData.orderStatus === '4'" class="order-item">
<text class="label">退款单号</text>
<text class="value">{{ orderData.refundOrderNo }}</text>
</view>
<view class="line"></view>
<view class="order-item amount">
<text class="label">实际支付金额</text>
<text class="value">{{ formattedAmount }}</text>
</view>
<!-- 根据订单状态动态显示按钮 -->
<button
v-if="shouldShowButton"
:class="['reserve-button', { loading: isLoading }]"
:disabled="isLoading"
@click="handleButtonClick(orderData)"
>
{{ isLoading ? "处理中..." : buttonText }}
</button>
<view class="feedback">
<text @click="openFeedback">投诉反馈</text>
</view>
</view>
</template>
<script setup>
import { defineProps, computed, ref, defineEmits } from "vue";
import { orderPayNow } from "@/request/api/OrderApi";
// 支付方式映射常量
const PAY_WAY_MAP = {
0: "微信",
1: "支付宝",
2: "云闪付",
};
// 加载状态
const isLoading = ref(false);
// 定义事件发射器
const emit = defineEmits(["show-refund-popup", "pay-success"]);
const props = defineProps({
orderData: {
type: Object,
required: true,
default: () => ({
orderId: "",
paySerialNumber: "",
payWay: "", // 支付方式 0-微信 1-支付宝 2-云闪付
payAmt: "",
orderStatus: "0", // 订单状态 0-待支付 1-待确认 2-待使用 3-已取消 4-退款中 5-已关闭 6-已完成
orderType: "0", // 0-酒店订单, 1-门票订单, 2-餐饮
}),
},
});
// 使用计算属性缓存支付方式文本
const payWayText = computed(() => {
return PAY_WAY_MAP[props.orderData.payWay] || "未知支付方式";
});
// 格式化金额显示
const formattedAmount = computed(() => {
const amount = props.orderData.payAmt;
return amount ? `${parseFloat(amount).toFixed(2)}` : "0.00";
});
// 按钮文案逻辑,订单状态 0-待支付 1-待确认 2-待使用 3-已取消 4-退款中 5-已关闭 6-已完成
const buttonText = computed(() => {
const status = props.orderData.orderStatus;
switch (status) {
case "0": // 待支付状态
return "立即支付";
case "2": // 待使用状态
return "申请退款";
case "3": // 已取消状态
case "5": // 已关闭状态
case "6": // 已完成状态
return "再次预定";
}
});
// 是否显示按钮(待支付、待使用、已取消、已关闭、已完成)
const shouldShowButton = computed(() => {
const status = props.orderData.orderStatus;
return ["0", "2", "3", "5", "6"].includes(status);
});
// 处理按钮点击事件
const handleButtonClick = async (orderData) => {
if (isLoading.value) return; // 防止重复点击
try {
isLoading.value = true;
const status = orderData.orderStatus;
if (status === "2") {
// 情况2待使用状态显示退款弹窗
emit("show-refund-popup");
return; // 直接返回,不执行后续代码
}
// 再次预定跳转商品详情
if (["3", "5", "6"].includes(status)) {
uni.navigateTo({
url: `/pages/goods/index?commodityId=${orderData.commodityId}`,
});
}
// 待支付状态,调用支付接口
if (status === "0") {
const orderId = orderData.orderId;
const payWay = orderData.payWay;
const paySource = orderData.paySource;
const res = await orderPayNow({ orderId, payWay, paySource });
console.log("确认订单---2:", res);
// 检查接口返回数据
if (!res || !res.data) {
uni.showToast({
title: "订单创建失败,请重试",
icon: "none",
duration: 2000,
});
return;
}
const { data } = res;
const { nonceStr, packageVal, paySign, signType, timeStamp } = data;
// 验证支付参数是否完整
if (!nonceStr || !packageVal || !paySign || !signType || !timeStamp) {
console.error("支付参数不完整:", {
nonceStr: !!nonceStr,
packageVal: !!packageVal,
paySign: !!paySign,
signType: !!signType,
timeStamp: !!timeStamp,
});
uni.showToast({
title: "支付参数错误,请重试",
icon: "none",
duration: 2000,
});
return;
}
// 调用微信支付
uni.requestPayment({
provider: "wxpay",
timeStamp: String(timeStamp), // 确保为字符串类型
nonceStr: String(nonceStr),
package: String(packageVal), // 确保为字符串类型
signType: String(signType),
paySign: String(paySign),
success: () => {
uni.showToast({
title: "支付成功",
icon: "success",
duration: 2000,
success: () => {
emit("pay-success");
},
});
},
fail: (err) => {
uni.showToast({
title: "支付失败,请重试",
icon: "none",
duration: 2000,
});
},
});
}
} catch (error) {
console.error("操作失败:", error);
} finally {
isLoading.value = false;
}
};
// 投诉电话
const openFeedback = () => {
const phoneNumber = props.orderData.complaintHotline;
uni.makePhoneCall({ phoneNumber });
};
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
</style>

View File

@@ -1,156 +0,0 @@
// 颜色系统
$order-bg-color: #fff;
$text-color-primary: #333;
$text-color-secondary: #666;
$text-color-accent: #ff5722;
$button-color: #00a6ff;
$button-disabled-color: #ccc;
$border-color: #ececec;
$shadow-color: rgba(0, 0, 0, 0.08);
// 尺寸和间距
$order-border-radius: 10px;
$order-padding: 16px 18px;
$spacing-small: 8px;
$spacing-medium: 10px;
$spacing-large: 20px;
$button-height: 42px;
// 字体系统
$font-size-small: 12px;
$font-size-medium: 14px;
$font-size-large: 18px;
$font-weight-normal: 400;
$font-weight-medium: 500;
$font-weight-semibold: 600;
// 过渡动画
$transition-fast: 0.2s ease;
$transition-normal: 0.3s ease;
.order-info {
background-color: $order-bg-color;
border-radius: $order-border-radius;
padding: $order-padding;
box-shadow: 0 2px 8px $shadow-color;
transition: box-shadow $transition-normal;
&:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
}
// 订单项样式,优化布局和视觉层次
.order-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: $spacing-small;
padding: 4px 0;
transition: background-color $transition-fast;
.label {
font-size: $font-size-small;
color: $text-color-secondary;
font-weight: $font-weight-normal;
flex-shrink: 0;
line-height: 1.4;
}
.value {
font-size: $font-size-small;
color: $text-color-primary;
font-weight: $font-weight-normal;
text-align: right;
word-break: break-word;
overflow-wrap: break-word;
line-height: 1.4;
max-width: 60%;
}
// 金额特殊样式,增强视觉重点
&.amount {
.label {
color: $text-color-primary;
font-weight: $font-weight-medium;
font-size: $font-size-medium;
}
.value {
color: $text-color-accent;
font-size: $font-size-large;
font-weight: $font-weight-semibold;
max-width: none;
// 货币符号样式
&::before {
content: "¥";
margin-right: 2px;
font-size: 11px;
}
}
}
}
.line {
border-bottom: 1px solid $border-color;
margin: $spacing-medium 0;
height: 0;
opacity: 0.6;
transition: opacity $transition-fast;
&:hover {
opacity: 1;
}
}
.reserve-button {
width: 100%;
background: linear-gradient(179deg, #00a6ff 0%, #0256ff 100%);
color: #fff;
border: none;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: $uni-border-radius-50px;
height: $button-height;
font-size: $font-size-medium;
font-weight: $font-weight-medium;
margin-top: $spacing-large;
position: relative;
overflow: hidden;
letter-spacing: 0.5px;
&:disabled {
background: $button-disabled-color;
cursor: not-allowed;
transform: none;
box-shadow: none;
&::before {
display: none;
}
}
// 加载状态样式
&.loading {
background: $button-disabled-color;
cursor: not-allowed;
transform: none;
box-shadow: none;
position: relative;
&::before {
display: none;
}
}
}
.feedback {
text-align: center;
font-size: $font-size-medium;
color: $text-color-primary;
font-weight: $font-weight-normal;
margin-top: $spacing-medium;
}
}

View File

@@ -10,13 +10,13 @@
@query="queryList"
>
<template #top>
<TopNavBar title="全部服务工单" />
<TopNavBar title="呼叫服务" />
</template>
<template #empty>
<CustomEmpty
emptyIcon="https://oss.nianxx.cn/mp/static/version_101/order/service_empty.png"
statusText="您暂无服务工单"
statusText="您暂无呼叫服务"
/>
</template>

View File

@@ -72,8 +72,8 @@ const list = ref([
},
{
icon: "https://oss.nianxx.cn/mp/static/version_101/home/wdgd.png",
title: "我的工单",
content: "查看服务工单、进度与处理情况",
title: "呼叫服务",
content: "查看呼叫服务、进度与处理情况",
btnText: "去查看",
type: Command.myWorkOrder,
path: "/pages-service/order/list",

View File

@@ -1,6 +1,6 @@
// 边框
.border {
border: 1px solid #000;
border: 1px solid #e5e8ee;
}
.border-bottom {

View File

@@ -3,6 +3,10 @@
border-radius: 4px;
}
.rounded-6 {
border-radius: 6px;
}
.rounded-8 {
border-radius: 8px;
}