Merge branch 'Branch_1' of https://git.u8t.cn/tangxinyue/alipay-emulator into Branch_1
# Conflicts: # main.js
2
App.vue
|
|
@ -7,7 +7,7 @@ export default {
|
|||
},
|
||||
onLaunch: function (options) {
|
||||
|
||||
console.log=()=>{}
|
||||
// console.log=()=>{}
|
||||
// === wgt 包启动诊断日志 ===
|
||||
console.log('=== App Launch 开始 ===')
|
||||
console.log('启动参数:', JSON.stringify(options))
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
</view>
|
||||
<view class="money alipay-font"
|
||||
:class="item.isAdd ? (isBalance ? 'add-color' : 'red-add-color') : 'minus-color', { 'line-height-51rpx': isBalance }">
|
||||
{{ item.isAdd ? '+' : '-' }}{{ Number(item.money).toFixed(2) }}
|
||||
{{ item.isAdd ? '+' : '-' }}{{ numberUtil.formatMoneyWithThousand(item.money) }}
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
<view v-if="item.isRefund" class="refund" :class="{ 'item-box': !isBalance }">已全额退款</view>
|
||||
<view v-if="isBalance" class="balance secondary" :class="{ 'item-box': !isBalance }">余额
|
||||
<text class="balance-text wx-font-regular">{{
|
||||
Number(item.balance).toFixed(2)
|
||||
numberUtil.formatMoneyWithThousand(item.balance)
|
||||
}}</text>元
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -58,6 +58,10 @@ import {
|
|||
reactive
|
||||
} from 'vue'
|
||||
|
||||
import {
|
||||
numberUtil
|
||||
} from '@/utils/common.js'
|
||||
|
||||
// 定义组件属性
|
||||
const props = defineProps({
|
||||
list: {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,213 @@
|
|||
<template>
|
||||
<view class="auto-width-input-container" :class="{ 'is-textarea': type === 'textarea' }">
|
||||
<!-- 测量层:用于计算宽度的影藏文本,必须保持与 input 相同的字体样式 -->
|
||||
<text v-if="type !== 'textarea'" class="measure-text" :style="[inputStyle, { visibility: 'hidden', position: 'absolute', whiteSpace: 'nowrap' }]">
|
||||
{{ modelValue || placeholder }}
|
||||
</text>
|
||||
|
||||
<!-- 输入层 -->
|
||||
<template v-if="type !== 'textarea'">
|
||||
<input class="auto-input" :type="type" :value="modelValue" :placeholder="placeholder" :placeholder-style="placeholderStyle"
|
||||
:style="[inputStyle, { width: finalInputWidth }]" @input="onInput" :maxlength="maxlength" :focus="isFocus" @blur="onBlur" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<textarea class="auto-textarea" :value="modelValue" :placeholder="placeholder" :placeholder-style="placeholderStyle"
|
||||
:style="[inputStyle]" @input="onInput" :maxlength="maxlength" auto-height :focus="isFocus" @blur="onBlur" />
|
||||
</template>
|
||||
|
||||
<!-- 编辑图标 -->
|
||||
<image v-if="showEdit" class="edit-icon" src="/static/image/common/edit.png" @click="handleFocusIcon"></image>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, nextTick, getCurrentInstance, onMounted } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'text' // 支持所有原生类型如 'number', 'tel', 'digit' 或 'textarea'
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请输入'
|
||||
},
|
||||
placeholderStyle: {
|
||||
type: String,
|
||||
default: 'color: #999;'
|
||||
},
|
||||
fontSize: {
|
||||
type: String,
|
||||
default: '28rpx'
|
||||
},
|
||||
fontWeight: {
|
||||
type: String,
|
||||
default: 'normal'
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#1A1A1A'
|
||||
},
|
||||
maxlength: {
|
||||
type: Number,
|
||||
default: 140
|
||||
},
|
||||
minWidth: {
|
||||
type: String,
|
||||
default: '20rpx'
|
||||
},
|
||||
extraWidth: {
|
||||
type: Number,
|
||||
default: 10 // 额外的缓冲像素,防止文字抖动
|
||||
},
|
||||
showEdit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'change']);
|
||||
const instance = getCurrentInstance();
|
||||
const inputWidth = ref(props.minWidth);
|
||||
// 最终应用的宽度样式
|
||||
const finalInputWidth = computed(() => {
|
||||
// 如果是 textarea 或者设置了填满父级,则不使用测量出的宽度
|
||||
if (props.type === 'textarea') return '100%';
|
||||
// 尝试检测 class 中是否包含撑开逻辑
|
||||
const classStr = instance.proxy.$attrs.class || '';
|
||||
if (classStr.includes('flex-1') || classStr.includes('w100')) {
|
||||
return '100%';
|
||||
}
|
||||
return inputWidth.value;
|
||||
});
|
||||
const isFocus = ref(false);
|
||||
|
||||
const inputStyle = computed(() => ({
|
||||
fontSize: props.fontSize,
|
||||
fontWeight: props.fontWeight,
|
||||
color: props.color,
|
||||
fontFamily: 'inherit'
|
||||
}));
|
||||
|
||||
/**
|
||||
* 点击图标触发聚焦
|
||||
*/
|
||||
const handleFocusIcon = () => {
|
||||
isFocus.value = false;
|
||||
nextTick(() => {
|
||||
isFocus.value = true;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 失去焦点处理
|
||||
*/
|
||||
const onBlur = () => {
|
||||
isFocus.value = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 核心逻辑:测量隐藏文本的物理宽度
|
||||
*/
|
||||
const updateWidth = () => {
|
||||
if (props.type === 'textarea') return;
|
||||
// 如果是强制撑开模式,理论上不需要测量,但为了防止切换状态时的布局闪烁,我们仍保持测量
|
||||
nextTick(() => {
|
||||
const query = uni.createSelectorQuery().in(instance.proxy);
|
||||
query.select('.measure-text').boundingClientRect(data => {
|
||||
if (data && data.width) {
|
||||
heatWidth(data.width);
|
||||
}
|
||||
}).exec();
|
||||
});
|
||||
};
|
||||
|
||||
const heatWidth = (width) => {
|
||||
// 加上一点额外的空间,避免在某些平台上因为小数点或字体渲染导致的文字换行
|
||||
inputWidth.value = (width + props.extraWidth) + 'px';
|
||||
};
|
||||
|
||||
const onInput = (e) => {
|
||||
const val = e.detail.value;
|
||||
emit('update:modelValue', val);
|
||||
emit('change', val);
|
||||
};
|
||||
|
||||
// 监听值的变化实时更新宽度
|
||||
watch(() => props.modelValue, () => {
|
||||
updateWidth();
|
||||
});
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
updateWidth();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.auto-width-input-container {
|
||||
position: relative;
|
||||
display: inline-flex; // 默认维持自适应宽度
|
||||
align-items: center;
|
||||
vertical-align: middle;
|
||||
max-width: 100%;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
// 当父级赋予 flex-1 或手动设置 width: 100% 时,转为标准 flex 布局
|
||||
&.flex-1, &.w100 {
|
||||
display: flex !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
&.is-textarea {
|
||||
display: flex !important;
|
||||
width: 100%;
|
||||
align-items: flex-start;
|
||||
flex-direction: row !important;
|
||||
}
|
||||
|
||||
.measure-text {
|
||||
left: -9999rpx;
|
||||
top: -9999rpx;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.auto-input {
|
||||
min-width: v-bind('props.minWidth');
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
text-align: inherit;
|
||||
height: 1.4em;
|
||||
line-height: 1.4em;
|
||||
flex-shrink: 0;
|
||||
|
||||
// 如果容器是撑开的,input 也应该撑开
|
||||
& {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.auto-textarea {
|
||||
flex: 1 !important;
|
||||
width: 0 !important;
|
||||
min-width: 0;
|
||||
min-height: 1.4em;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: 1.4em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.edit-icon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
margin-left: 8rpx;
|
||||
flex-shrink: 0;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
:src="chatInfo.img || `/static/image/phone-message/${phone}/default.png`">
|
||||
</image>
|
||||
<text v-if="phone != 'iphone'" class="title">{{ chatInfo.title }}</text>
|
||||
<text v-if="phone == 'oppo'" class="second-text">重庆</text>
|
||||
<text v-if="phone == 'oppo' && chatInfo.area" class="second-text">{{ chatInfo.area }}</text>
|
||||
</view>
|
||||
<view class="right flex-align-center">
|
||||
<image v-if="phone == 'mi'" class="img shrink-0"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<view class="shopping-card">
|
||||
<view class="shopping-card" @longpress="onLongPress">
|
||||
<!-- Header -->
|
||||
<view class="card-header">
|
||||
<view class="shop-info">
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
<view v-if="item.status === '等待付款'" class="status-warning">
|
||||
<image style="width: 116rpx;height: 30rpx;" src="/static/image/shopping/jingdong/dengdaifukuan.png">
|
||||
</image>
|
||||
<text class="status-desc" v-if="item.statusDesc">{{ item.statusDesc }}</text>
|
||||
<text class="status-desc" v-if="item.statusDesc">{{ formatStatusDesc(item.statusDesc) }}</text>
|
||||
</view>
|
||||
<text v-else class="status-text"
|
||||
:class="{ red: item.statusColor === 'red' || item.status === '正在出库' || item.status === '商家备餐中' || item.status === '骑手到店取餐中' || item.status === '骑手已到店' }">{{
|
||||
|
|
@ -63,8 +63,8 @@
|
|||
<view class="product-info">
|
||||
<text class="product-title">{{ item.products[0].title }}</text>
|
||||
<text class="product-desc" v-if="item.products[0].desc">{{ item.products[0].desc }}</text>
|
||||
<view class="product-tags" v-if="item.products[0].tags && item.products[0].tags.length">
|
||||
<text class="tag" v-for="(tag, index) in item.products[0].tags" :key="index">{{ tag }}</text>
|
||||
<view class="product-tags" v-if="item.products[0].service">
|
||||
<text class="tag">{{ item.products[0].service }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
|
@ -87,8 +87,7 @@
|
|||
<view class="product-price-box">
|
||||
<view class="price-wrap wx-font-regular">
|
||||
<text class="price-symbol">¥</text>
|
||||
<text class="price-num">{{ item.price || (item.products && item.products[0] &&
|
||||
item.products[0].price) }}</text>
|
||||
<text class="price-num">{{ safeFormatPrice(item) }}</text>
|
||||
</view>
|
||||
<text class="product-count"
|
||||
v-if="item.count || (item.products && item.products[0] && item.products[0].count)">共{{
|
||||
|
|
@ -98,8 +97,7 @@
|
|||
|
||||
<!-- Promo -->
|
||||
<view class="promo-box"
|
||||
:class="{ 'plus-promo': item.promoType === 'plus', 'cashback-promo': item.promoType === 'cashback', 'coupon-promo': item.promoType === 'coupon' }"
|
||||
v-if="item.promoType || item.promoText || item.promoHighlight">
|
||||
:class="{ 'plus-promo': item.promoType === 'plus', 'cashback-promo': item.shopType == 'waimai' && (item.status == '骑手到店取餐中' || item.status == '商家备餐中'), 'coupon-promo': item.promoType === 'coupon' }">
|
||||
<template v-if="item.promoType === 'plus'">
|
||||
<view class="plus-row">
|
||||
<image class="plus-tag" src="/static/image/shopping/jingdong/plus.png"></image>
|
||||
|
|
@ -107,11 +105,9 @@
|
|||
</view>
|
||||
<text class="promo-action">解锁权益 <uni-icons type="right" size="10" color="#654629"></uni-icons> </text>
|
||||
</template>
|
||||
<template v-else-if="item.promoType === 'cashback'">
|
||||
<text class="promo-text">{{ item.promoText }} <text class="highlight" v-if="item.promoHighlight">{{
|
||||
item.promoHighlight }}</text></text>
|
||||
<text class="promo-action red">{{ item.promoAction || '点击领取' }} <uni-icons type="right" size="10"
|
||||
color="#ED1C04"></uni-icons></text>
|
||||
<template v-else-if="item.shopType == 'waimai' && (item.status == '骑手到店取餐中' || item.status == '商家备餐中')">
|
||||
<text class="promo-text text-basic">当笔订单返现成功到账,<text style="color: #E31700;">点击领取</text></text>
|
||||
<uni-icons type="right" size="10" color="#1A1A1A"></uni-icons>
|
||||
</template>
|
||||
<template v-else-if="item.promoType === 'coupon'">
|
||||
<view class="coupon-row">
|
||||
|
|
@ -149,7 +145,7 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, computed } from 'vue';
|
||||
import { defineProps, computed, defineEmits } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
|
|
@ -159,6 +155,27 @@ const props = defineProps({
|
|||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['btnClick', 'longpress']);
|
||||
|
||||
const onLongPress = (e) => {
|
||||
emit('longpress', { event: e, item: props.item });
|
||||
};
|
||||
|
||||
const formatStatusDesc = (desc) => {
|
||||
if (!desc || !desc.includes(' : ')) return desc;
|
||||
const parts = desc.split(' : ');
|
||||
if (parts.length >= 2) {
|
||||
return `${parts[0]}时${parts[1]}分`;
|
||||
}
|
||||
return desc;
|
||||
};
|
||||
|
||||
const safeFormatPrice = (item) => {
|
||||
const val = item.price || (item.products && item.products[0] && item.products[0].price);
|
||||
const num = Number(val);
|
||||
return isNaN(num) ? '0.00' : num.toFixed(2);
|
||||
};
|
||||
|
||||
const getButtons = (shopType, status, item) => {
|
||||
const buttons = [];
|
||||
if (status == '等待付款') {
|
||||
|
|
@ -269,7 +286,7 @@ const getButtons = (shopType, status, item) => {
|
|||
.shop-name {
|
||||
white-space: nowrap;
|
||||
font-size: 26rpx;
|
||||
line-height: 26rpx;
|
||||
line-height: 28rpx;
|
||||
color: #1A1A1A;
|
||||
font-weight: 700;
|
||||
overflow: hidden;
|
||||
|
|
@ -682,7 +699,7 @@ const getButtons = (shopType, status, item) => {
|
|||
border-radius: 8rpx;
|
||||
font-size: 22rpx;
|
||||
margin-left: 16rpx;
|
||||
border: 1rpx solid #C7C7C7;
|
||||
border: 0.5px solid #C7C7C7;
|
||||
color: #1A1A1A;
|
||||
background-color: #FFFFFF;
|
||||
|
||||
|
|
|
|||
2
main.js
|
|
@ -27,7 +27,7 @@ export function createApp() {
|
|||
const systemInfo = uni.getStorageSync('systemInfo') || {}
|
||||
app.config.globalProperties.$system = systemInfo.platform == 'ios' ? 'iOS' : 'Android'
|
||||
app.config.globalProperties.$systemInfo = systemInfo
|
||||
uni.setStorageSync('version', '1.0.3.sp18')
|
||||
uni.setStorageSync('version', '1.0.4.sp3')
|
||||
app.config.globalProperties.$version = uni.getStorageSync('version')
|
||||
app.use(globalMethods);
|
||||
return {
|
||||
|
|
|
|||
62
pages.json
|
|
@ -9,23 +9,19 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"subPackages": [
|
||||
{
|
||||
"subPackages": [{
|
||||
"root": "pages/call-log",
|
||||
"pages": [
|
||||
{
|
||||
"path": "call",
|
||||
"style": {
|
||||
"navigationBarTitleText": "通话记录页面",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
"pages": [{
|
||||
"path": "call",
|
||||
"style": {
|
||||
"navigationBarTitleText": "通话记录页面",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
]
|
||||
}]
|
||||
},
|
||||
{
|
||||
"root": "pages/message",
|
||||
"pages": [
|
||||
{
|
||||
"pages": [{
|
||||
"path": "list-index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "短信列表首页",
|
||||
|
|
@ -43,8 +39,7 @@
|
|||
},
|
||||
{
|
||||
"root": "pages/shopping",
|
||||
"pages": [
|
||||
{
|
||||
"pages": [{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "购物app首页",
|
||||
|
|
@ -57,13 +52,26 @@
|
|||
"navigationBarTitleText": "京东列表首页",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "jingdong/order-detail/order-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "订单详情",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "jingdong/add-order/add-order",
|
||||
"style": {
|
||||
"navigationBarTitleText": "添加订单",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/balance",
|
||||
"pages": [
|
||||
{
|
||||
"pages": [{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "余额页面",
|
||||
|
|
@ -89,8 +97,7 @@
|
|||
},
|
||||
{
|
||||
"root": "pages/bill",
|
||||
"pages": [
|
||||
{
|
||||
"pages": [{
|
||||
"path": "bill-list/bill-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "账单列表页面",
|
||||
|
|
@ -115,8 +122,7 @@
|
|||
},
|
||||
{
|
||||
"root": "pages/ant-credit-pay",
|
||||
"pages": [
|
||||
{
|
||||
"pages": [{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "花呗首页",
|
||||
|
|
@ -134,8 +140,7 @@
|
|||
},
|
||||
{
|
||||
"root": "pages/finance-management",
|
||||
"pages": [
|
||||
{
|
||||
"pages": [{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "理财首页",
|
||||
|
|
@ -160,8 +165,7 @@
|
|||
},
|
||||
{
|
||||
"root": "pages/other",
|
||||
"pages": [
|
||||
{
|
||||
"pages": [{
|
||||
"path": "/video-group-chat/video-group-chat",
|
||||
"style": {
|
||||
"navigationBarTitleText": "视频群聊",
|
||||
|
|
@ -262,13 +266,19 @@
|
|||
"navigationBarTitleText": "飞猪火车票",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "ranking/ranking",
|
||||
"style": {
|
||||
"navigationBarTitleText": "从夯倒拉排名",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/common",
|
||||
"pages": [
|
||||
{
|
||||
"pages": [{
|
||||
"path": "hot-icon/hot-icon",
|
||||
"style": {
|
||||
"navigationBarTitleText": "热门图标",
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@
|
|||
<!-- 金额 -->
|
||||
<view class=" money info-item-input alipay-font" style="height: 77rpx;">
|
||||
<!-- 隐藏的text用于测量宽度 -->
|
||||
<text class="text-measure font-w500" style="font-size: 64rpx;">{{ billData.money }}</text>
|
||||
<text class="text-measure font-w500" style="font-size: 64rpx;">{{
|
||||
numberUtil.formatMoneyWithThousand(billData.money) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
|
@ -253,7 +254,8 @@ const {
|
|||
} = addBillJson
|
||||
import {
|
||||
util,
|
||||
randomUtil
|
||||
randomUtil,
|
||||
numberUtil
|
||||
} from '@/utils/common.js'
|
||||
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@
|
|||
<view class="income-ande-outCome flex-between">
|
||||
<view class="flex">
|
||||
<view class="item"><text>支出¥</text><text class="money wx-font-regular">{{
|
||||
Number(currentMonthData.outCome).toFixed(2) }}</text></view>
|
||||
numberUtil.formatMoneyWithThousand(currentMonthData.outCome) }}</text></view>
|
||||
<view class="item"><text>收入¥</text><text class="money wx-font-regular">{{
|
||||
Number(currentMonthData.inCome).toFixed(2) }}</text></view>
|
||||
numberUtil.formatMoneyWithThousand(currentMonthData.inCome) }}</text></view>
|
||||
|
||||
</view>
|
||||
<view class="">
|
||||
|
|
@ -83,13 +83,13 @@
|
|||
<view class="outCome item">
|
||||
<text class="title">支出</text>
|
||||
<text class="amount alipay-font"><text class="font-11 wx-font-regular">¥</text>{{
|
||||
Number(item.outCome).toFixed(2)
|
||||
numberUtil.formatMoneyWithThousand(item.outCome)
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="income item">
|
||||
<text class="title">收入</text>
|
||||
<text class="amount alipay-font"><text class="font-11 wx-font-regular">¥</text>{{
|
||||
Number(item.inCome).toFixed(2)
|
||||
numberUtil.formatMoneyWithThousand(item.inCome)
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -129,7 +129,8 @@
|
|||
<script setup>
|
||||
import {
|
||||
dateUtil,
|
||||
util
|
||||
util,
|
||||
numberUtil
|
||||
} from '@/utils/common.js'
|
||||
import navBar from '@/components/nav-bar/nav-bar.vue'
|
||||
import BalanceList from '@/components/balance-list/balance-list.vue'
|
||||
|
|
|
|||
|
|
@ -275,11 +275,16 @@ const otherList = [{
|
|||
name: "通话",
|
||||
path: "/pages/common/call-and-message-entry/call-and-message-entry?type=call"
|
||||
},
|
||||
// {
|
||||
// icon: "/static/image/index/qita/gouwu.png",
|
||||
// name: "购物",
|
||||
// path: "/pages/shopping/index"
|
||||
// },
|
||||
{
|
||||
icon: "/static/image/index/qita/ranking.png",
|
||||
name: "从夯倒拉排名",
|
||||
path: "/pages/other/ranking/ranking"
|
||||
},
|
||||
{
|
||||
icon: "/static/image/index/qita/gouwu.png",
|
||||
name: "购物",
|
||||
path: "/pages/shopping/index"
|
||||
},
|
||||
]
|
||||
|
||||
const data = reactive({
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@
|
|||
<text class="add-label required">联系人</text>
|
||||
<input class="add-input" v-model="addForm.title" placeholder="请输入名称或号码" />
|
||||
</view>
|
||||
<view class="add-row" v-if="data.phone == 'oppo'">
|
||||
<text class="add-label">地区</text>
|
||||
<input class="add-input" v-model="addForm.area" placeholder="请输入地区" />
|
||||
</view>
|
||||
<view class="add-row between" v-if="data.phone == 'iphone'">
|
||||
<text class="add-label">取消通知</text>
|
||||
<switch :checked="addForm.noNotice" @change="addForm.noNotice = !addForm.noNotice" />
|
||||
|
|
@ -313,6 +317,7 @@ const openAddPopup = () => {
|
|||
addForm.title = ''
|
||||
addForm.img = ''
|
||||
addForm.content = ''
|
||||
addForm.area = ''
|
||||
addForm.unRead = false
|
||||
addForm.unReadNumber = 1
|
||||
addForm.noNotice = false
|
||||
|
|
@ -347,6 +352,7 @@ const editItem = (item) => {
|
|||
addForm.img = item.img || ''
|
||||
addForm.imgShape = item.imgShape || 'circle'
|
||||
addForm.content = ''
|
||||
addForm.area = item.area || ''
|
||||
addForm.unRead = !!item.unRead
|
||||
addForm.unReadNumber = item.unReadNumber || 0
|
||||
addForm.noNotice = item.noNotice || false
|
||||
|
|
@ -387,6 +393,7 @@ const confirmAdd = async () => {
|
|||
defaultList.value[idx].unReadNumber = addForm.unReadNumber
|
||||
defaultList.value[idx].noNotice = addForm.noNotice
|
||||
defaultList.value[idx].imgShape = addForm.imgShape
|
||||
defaultList.value[idx].area = addForm.area
|
||||
defaultList.value[idx].time = time
|
||||
}
|
||||
} else {
|
||||
|
|
@ -399,6 +406,7 @@ const confirmAdd = async () => {
|
|||
img: finalImgPath,
|
||||
title: addForm.title.trim(),
|
||||
imgShape: addForm.imgShape,
|
||||
area: addForm.area,
|
||||
chatList: addForm.content.trim() ? [
|
||||
{
|
||||
id: stringUtil.uuid(),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,784 @@
|
|||
<template>
|
||||
<view class="ranking-page">
|
||||
<nav-bar title="从夯到拉" bgColor="#F5F5F5" isRightButton :rightButtonText="rightButtonText"
|
||||
@right-click="onRightClick">
|
||||
</nav-bar>
|
||||
|
||||
<view class="content-container">
|
||||
<view :class="{ 'skin-box': type == 'skin', 'table-box': type != 'skin' }"
|
||||
:style="type == 'skin' ? { backgroundColor: skinBgColor } : {}">
|
||||
<template v-if="type == 'skin'">
|
||||
<view v-if="!isEdit" class="title">{{ title }}</view>
|
||||
<input v-else class="title title-input" v-model="title" maxlength="12" placeholder="请输入排名标题" />
|
||||
<image class="img happy" src="/static/image/other/ranking/happy.png"></image>
|
||||
<image class="img sad" src="/static/image/other/ranking/sad.png"></image>
|
||||
</template>
|
||||
<image v-if="$isVip()" class="watermark" :class="{}" src="/static/image/other/card/shuiyin2.png"
|
||||
mode="heightFix">
|
||||
</image>
|
||||
|
||||
<view class="ranking-table">
|
||||
<view v-for="(item, index) in tierList" :key="index" class="ranking-row">
|
||||
<view class="label-box" :style="{ backgroundColor: item.bgColor }"
|
||||
@click="changeRowBgColor(index)">
|
||||
<!-- <text class="label-text" :class="{ 'with-stroke': item.hasStroke }"
|
||||
:style="{ color: item.textColor }">
|
||||
{{ item.label }}
|
||||
</text> -->
|
||||
<image :style="`height:60rpx;width:160rpx;`"
|
||||
:src="`/static/image/other/ranking/${type == 'skin' ? item.img + '_skin' : item.img}.png`">
|
||||
</image>
|
||||
</view>
|
||||
|
||||
<view class="items-box ranking-item-list" :id="'row-' + index">
|
||||
<view v-for="(img, imgIdx) in item.images" :key="imgIdx" class="item-wrapper"
|
||||
:class="{ 'is-dragging': drag.tierIndex === index && drag.imgIdx === imgIdx }"
|
||||
:style="getDragStyle(index, imgIdx)" @touchstart="onTouchStart($event, index, imgIdx)"
|
||||
@touchmove.stop.prevent="onTouchMove" @touchend="onTouchEnd">
|
||||
|
||||
<image :src="img" mode="aspectFill" class="item-img"></image>
|
||||
<view v-if="isEdit" class="del-btn" @click.stop="deleteImage(index, imgIdx)">×</view>
|
||||
</view>
|
||||
|
||||
<view v-if="isEdit && item.images.length < 4" class="add-btn" @click="chooseImage(index)">
|
||||
<image class="add-icon" src="/static/image/common/add.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="save-action">
|
||||
<button v-if="!isEdit" class="save-btn" @click="handleSave">保存图片</button>
|
||||
<!-- 编辑模式下的全局颜色控制器 -->
|
||||
<view v-else-if="type == 'skin'" class="bottom-edit-actions">
|
||||
<view class="color-picker-wrapper">
|
||||
<view class="color-picker">
|
||||
<view v-for="color in ['#FFDFDF', '#DFF0FF', '#E0FFDF', '#FDF5C8', '#F3DFFF']" :key="color"
|
||||
class="color-dot" :style="{ backgroundColor: color }" @click="skinBgColor = color">
|
||||
</view>
|
||||
</view>
|
||||
<input v-if="false" class="hex-input" v-model="skinBgColor" placeholder="#HEX" maxlength="7" />
|
||||
</view>
|
||||
<view class="spectrum-picker" @touchstart="handleHueTouch" @touchmove.stop.prevent="handleHueTouch">
|
||||
<view class="spectrum-bar"></view>
|
||||
<view class="slider-thumb" :style="{ left: (skinHue / 360 * 100) + '%' }"></view>
|
||||
</view>
|
||||
|
||||
<text class="edit-tip">点击左侧分类标签可切换背景色</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bottom-tabs">
|
||||
<view class="tab-item" :class="{ active: type == 'base' }" @click="switchType('base')">基础</view>
|
||||
<view class="tab-item" :class="{ active: type == 'skin' }" @click="switchType('skin')">皮肤</view>
|
||||
</view>
|
||||
|
||||
<view class="painter-container" v-if="isSnapshot">
|
||||
<l-painter isCanvasToTempFilePath @success="onPainterSuccess"
|
||||
:css="`width:750rpx; padding: 40rpx; background-color:${type == 'skin' ? skinBgColor : '#F8F8F8'};`">
|
||||
<l-painter-view
|
||||
:css="`width: 100%; display: flex; flex-direction: column; position: relative; ${type == 'skin' ? 'padding-top: 120rpx;padding-bottom: 120rpx;' : ''}`">
|
||||
<template v-if="type == 'skin'">
|
||||
<l-painter-text :text="title"
|
||||
css="position: absolute; top: 26rpx; left: 50%; transform: translateX(-50%); font-size: 36rpx; font-weight: bold; color: #333;" />
|
||||
<l-painter-image src="/static/image/other/ranking/happy.png"
|
||||
css="position: absolute;top: 58rpx;right: 24rpx; width: 96rpx; height: 96rpx;" />
|
||||
</template>
|
||||
|
||||
<l-painter-view css="border: 3rpx solid #333; background-color: #fff; width: 100%;">
|
||||
<l-painter-view v-for="(item, index) in tierList" :key="index"
|
||||
:css="`display: flex; min-height: 148rpx; border-bottom: ${index === tierList.length - 1 ? 'none' : '3rpx solid #333'};`">
|
||||
<l-painter-view
|
||||
:css="`width: 176rpx; min-height: 148rpx; background-color: ${item.bgColor}; display: flex; align-items: center; justify-content: center; border-right: 3rpx solid #333;`">
|
||||
<!-- <l-painter-text :text="item.label"
|
||||
:css="`font-size: 52rpx; font-weight: bold; color: ${item.textColor}; ${item.hasStroke ? 'text-shadow: 2rpx 2rpx 0 #000, -2rpx -2rpx 0 #000, 2rpx -2rpx 0 #000, -2rpx 2rpx 0 #000, 0 2rpx 0 #000, 0 -2rpx 0 #000, 2rpx 0 0 #000, -2rpx 0 0 #000;' : ''}`" /> -->
|
||||
<l-painter-image
|
||||
:src="`/static/image/other/ranking/${type == 'skin' ? item.img + '_skin' : item.img}.png`"
|
||||
:css="`height: 60rpx; width: 160rpx;`" mode="heightFix" />
|
||||
</l-painter-view>
|
||||
<l-painter-view
|
||||
:css="`flex: 1; display: flex; align-items: center;height: 148rpx;width:490rpx;padding:0 12rpx;`">
|
||||
<l-painter-image v-for="(img, imgIdx) in item.images" :key="imgIdx" :src="img"
|
||||
css="width: 105rpx; height: 105rpx; margin: 0 8rpx; object-fit: cover;"
|
||||
mode="aspectFill" />
|
||||
</l-painter-view>
|
||||
</l-painter-view>
|
||||
</l-painter-view>
|
||||
<l-painter-view v-if="$isVip()"
|
||||
:css="type == 'skin' ? `position: absolute;bottom: 32rpx;right: 14rpx;` : `position: absolute;top: 50%;right: 50%;transform: translate(50%, -50%);`">
|
||||
<l-painter-image src="/static/image/other/card/shuiyin2.png"
|
||||
css="width: 194rpx;height: 56rpx;" />
|
||||
</l-painter-view>
|
||||
<l-painter-image v-if="type == 'skin'" src="/static/image/other/ranking/sad.png"
|
||||
css="position: absolute;bottom: 76rpx;left: 116rpx; width: 96rpx; height: 96rpx;" />
|
||||
</l-painter-view>
|
||||
</l-painter>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
reactive,
|
||||
getCurrentInstance
|
||||
} from 'vue';
|
||||
import {
|
||||
onLoad
|
||||
} from '@dcloudio/uni-app';
|
||||
|
||||
const {
|
||||
proxy
|
||||
} = getCurrentInstance();
|
||||
|
||||
const type = ref("base");
|
||||
const title = ref("xx排名");
|
||||
const skinBgColor = ref("#FFDFDF");
|
||||
const skinHue = ref(0); // 记录色相位置
|
||||
const isSnapshot = ref(false);
|
||||
const isEdit = ref(false);
|
||||
const rightButtonText = ref("编辑");
|
||||
|
||||
const tierList = ref([{
|
||||
label: '夯',
|
||||
bgColor: '#D5171C',
|
||||
img: 'hang',
|
||||
textColor: '#FFFFFF',
|
||||
hasStroke: true,
|
||||
images: [],
|
||||
width: 60,
|
||||
},
|
||||
{
|
||||
label: '顶级',
|
||||
bgColor: '#FF6A0B',
|
||||
img: 'dingji',
|
||||
textColor: '#FFFFFF',
|
||||
hasStroke: true,
|
||||
images: [],
|
||||
width: 104,
|
||||
},
|
||||
{
|
||||
label: '人上人',
|
||||
bgColor: '#FFF06A',
|
||||
img: 'renshangren',
|
||||
textColor: '#FFFFFF',
|
||||
hasStroke: true,
|
||||
images: [],
|
||||
width: 156,
|
||||
},
|
||||
{
|
||||
label: 'NPC',
|
||||
bgColor: '#FDF5C8',
|
||||
img: 'npc',
|
||||
textColor: '#FFFFFF',
|
||||
hasStroke: true,
|
||||
images: [],
|
||||
width: 110,
|
||||
},
|
||||
{
|
||||
label: '拉完了',
|
||||
bgColor: '#FFFFFF',
|
||||
img: 'lawanle',
|
||||
textColor: '#FFFFFF',
|
||||
hasStroke: true,
|
||||
images: [],
|
||||
width: 156,
|
||||
}
|
||||
]);
|
||||
|
||||
// --- 生命周期:加载缓存 ---
|
||||
onLoad(() => {
|
||||
// 进入页面埋点
|
||||
proxy.$apiUserEvent('all', {
|
||||
type: 'click',
|
||||
key: 'ranking',
|
||||
value: "从夯倒拉排名"
|
||||
})
|
||||
// 获取缓存数据
|
||||
const cache = uni.getStorageSync('ranking_config_data');
|
||||
if (cache) {
|
||||
title.value = cache.title || title.value;
|
||||
type.value = cache.type || type.value;
|
||||
skinBgColor.value = cache.skinBgColor || skinBgColor.value;
|
||||
skinHue.value = cache.skinHue ?? skinHue.value;
|
||||
if (cache.tierList) tierList.value = cache.tierList;
|
||||
console.log(tierList.value);
|
||||
}
|
||||
});
|
||||
|
||||
// --- 拖拽排序逻辑 ---
|
||||
const drag = reactive({
|
||||
tierIndex: -1,
|
||||
imgIdx: -1,
|
||||
startX: 0,
|
||||
startY: 0,
|
||||
moveX: 0,
|
||||
moveY: 0
|
||||
});
|
||||
|
||||
// 计算拖拽样式
|
||||
const getDragStyle = (tIdx, iIdx) => {
|
||||
if (drag.tierIndex === tIdx && drag.imgIdx === iIdx) {
|
||||
return {
|
||||
transform: `translate(${drag.moveX}px, ${drag.moveY}px)`,
|
||||
zIndex: 99,
|
||||
transition: 'none'
|
||||
};
|
||||
}
|
||||
return {
|
||||
transition: 'transform 0.3s ease'
|
||||
};
|
||||
};
|
||||
|
||||
const onTouchStart = (e, tIdx, iIdx) => {
|
||||
if (!isEdit.value) return;
|
||||
const touch = e.touches[0];
|
||||
drag.tierIndex = tIdx;
|
||||
drag.imgIdx = iIdx;
|
||||
drag.startX = touch.clientX;
|
||||
drag.startY = touch.clientY;
|
||||
drag.moveX = 0;
|
||||
drag.moveY = 0;
|
||||
};
|
||||
|
||||
const onTouchMove = (e) => {
|
||||
if (drag.tierIndex === -1) return;
|
||||
const touch = e.touches[0];
|
||||
drag.moveX = touch.clientX - drag.startX;
|
||||
drag.moveY = touch.clientY - drag.startY;
|
||||
};
|
||||
|
||||
const onTouchEnd = () => {
|
||||
if (drag.tierIndex === -1) return;
|
||||
|
||||
const {
|
||||
tierIndex,
|
||||
imgIdx,
|
||||
moveX
|
||||
} = drag;
|
||||
const rowData = tierList.value[tierIndex].images;
|
||||
|
||||
// 估算单个item跨度 (100rpx宽度 + 12rpx间距 ≈ 56px,建议根据真机微调)
|
||||
const itemWidth = 56;
|
||||
const offset = Math.round(moveX / itemWidth);
|
||||
let newIndex = imgIdx + offset;
|
||||
|
||||
// 限制索引范围
|
||||
newIndex = Math.max(0, Math.min(newIndex, rowData.length - 1));
|
||||
|
||||
if (newIndex !== imgIdx) {
|
||||
const temp = rowData.splice(imgIdx, 1)[0];
|
||||
rowData.splice(newIndex, 0, temp);
|
||||
}
|
||||
|
||||
// 重置拖拽状态
|
||||
drag.tierIndex = -1;
|
||||
drag.imgIdx = -1;
|
||||
};
|
||||
|
||||
// --- 其他业务逻辑 ---
|
||||
const chooseImage = (index) => {
|
||||
const currentCount = tierList.value[index].images.length;
|
||||
uni.chooseImage({
|
||||
count: 4 - currentCount,
|
||||
sizeType: ['compressed'],
|
||||
success: (res) => {
|
||||
tierList.value[index].images.push(...res.tempFilePaths);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const deleteImage = (tIdx, iIdx) => {
|
||||
const path = tierList.value[tIdx].images[iIdx];
|
||||
removeLocalFile(path); // 物理删除已有文件
|
||||
tierList.value[tIdx].images.splice(iIdx, 1);
|
||||
};
|
||||
|
||||
const onRightClick = async () => {
|
||||
if (isEdit.value) {
|
||||
uni.showLoading({
|
||||
title: '正在持久化图片...',
|
||||
mask: true
|
||||
});
|
||||
// 1. 深度遍历并持久化所有临时图片
|
||||
for (let tierIdx = 0; tierIdx < tierList.value.length; tierIdx++) {
|
||||
const tier = tierList.value[tierIdx];
|
||||
for (let i = 0; i < tier.images.length; i++) {
|
||||
const path = tier.images[i];
|
||||
// 逻辑逻辑:如果是 static 或者是已经保存的 _doc/usr 路径,则跳过
|
||||
const isStatic = path.startsWith('/static/') || path.startsWith('static/');
|
||||
const isPersistent = path.indexOf('_doc/') !== -1 || path.indexOf('usr/') !== -1;
|
||||
|
||||
if (!isStatic && !isPersistent) {
|
||||
console.log('检测到待持久化图片:', path);
|
||||
const newPath = await saveImageToLocal(path);
|
||||
if (newPath) {
|
||||
tier.images[i] = newPath;
|
||||
console.log('持久化成功,新路径:', newPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 全部处理完后,进行数据持久化
|
||||
uni.setStorageSync('ranking_config_data', {
|
||||
title: title.value,
|
||||
type: type.value,
|
||||
skinBgColor: skinBgColor.value,
|
||||
skinHue: skinHue.value,
|
||||
tierList: tierList.value
|
||||
});
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '已保存',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
isEdit.value = !isEdit.value;
|
||||
rightButtonText.value = isEdit.value ? "确定" : "编辑";
|
||||
};
|
||||
|
||||
/**
|
||||
* 将临时图片保存到本地永久目录
|
||||
*/
|
||||
const saveImageToLocal = (tempFilePath) => {
|
||||
return new Promise((resolve) => {
|
||||
// 如果已经是持久化路径,直接返回
|
||||
if (tempFilePath.indexOf('_doc/') !== -1 || tempFilePath.indexOf('usr/') !== -1) {
|
||||
return resolve(tempFilePath);
|
||||
}
|
||||
|
||||
uni.saveFile({
|
||||
tempFilePath: tempFilePath,
|
||||
success: (res) => {
|
||||
resolve(res.savedFilePath);
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('本地持久化保存失败:', err);
|
||||
// 提示:H5 环境不支持 saveFile 持久化,仅 App/小程序支持
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 物理删除本地已保存的文件
|
||||
*/
|
||||
const removeLocalFile = (path) => {
|
||||
if (!path) return;
|
||||
// 仅针对非静态资源的本地文件进行删除
|
||||
if (path.indexOf('_doc/') !== -1 || path.indexOf('usr/') !== -1) {
|
||||
uni.removeSavedFile({
|
||||
filePath: path,
|
||||
success: () => console.log('文件物理删除成功:', path),
|
||||
fail: (err) => console.log('文件删除失败:', err)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
uni.showLoading({
|
||||
title: '生成中...',
|
||||
mask: true
|
||||
});
|
||||
isSnapshot.value = true;
|
||||
};
|
||||
|
||||
const onPainterSuccess = (path) => {
|
||||
const done = () => {
|
||||
isSnapshot.value = false;
|
||||
uni.hideLoading();
|
||||
};
|
||||
if (!path) return done();
|
||||
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath: path,
|
||||
success: () => uni.showToast({
|
||||
title: '保存成功'
|
||||
}),
|
||||
fail: () => uni.showToast({
|
||||
title: '保存失败',
|
||||
icon: 'none'
|
||||
}),
|
||||
complete: done
|
||||
});
|
||||
};
|
||||
|
||||
const switchType = (val) => {
|
||||
type.value = val;
|
||||
if (val == 'skin') {
|
||||
tierList.value[0].bgColor = '#F3575B'
|
||||
tierList.value[1].bgColor = '#FF9B5B'
|
||||
tierList.value[2].bgColor = '#FFF59E'
|
||||
tierList.value[3].bgColor = '#FFFBE1'
|
||||
tierList.value[4].bgColor = '#FFFFFF'
|
||||
} else {
|
||||
tierList.value[0].bgColor = '#D5171C'
|
||||
tierList.value[1].bgColor = '#FF6A0B'
|
||||
tierList.value[2].bgColor = '#FFF06A'
|
||||
tierList.value[3].bgColor = '#FDF5C8'
|
||||
tierList.value[4].bgColor = '#FFFFFF'
|
||||
}
|
||||
|
||||
// 切换时由于改变了 type,立即同步到缓存中以便记录最后选择的模式
|
||||
const cache = uni.getStorageSync('ranking_config_data') || {};
|
||||
cache.type = val;
|
||||
uni.setStorageSync('ranking_config_data', cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* 循环切换行背景色 (编辑模式下)
|
||||
*/
|
||||
const changeRowBgColor = (index) => {
|
||||
if (!isEdit.value) return;
|
||||
const colors = ['#D5171C', '#FF6A0B', '#FFF06A', '#FDF5C8', '#FFFFFF', '#1777FF', '#333333'];
|
||||
const curr = tierList.value[index].bgColor;
|
||||
let nextIdx = (colors.indexOf(curr.toUpperCase()) + 1) % colors.length;
|
||||
if (nextIdx === -1) nextIdx = 0;
|
||||
tierList.value[index].bgColor = colors[nextIdx];
|
||||
|
||||
// 自动适配文字颜色 (深色背景用白色,浅色用黑色)
|
||||
const darkColors = ['#D5171C', '#1777FF', '#333333'];
|
||||
tierList.value[index].textColor = darkColors.includes(colors[nextIdx]) ? '#FFFFFF' : '#FFFFFF';
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理色域滑动
|
||||
*/
|
||||
const handleHueTouch = (e) => {
|
||||
const touch = e.touches[0];
|
||||
uni.createSelectorQuery().select('.spectrum-picker').boundingClientRect(rect => {
|
||||
if (rect) {
|
||||
const x = Math.max(0, Math.min(touch.clientX - rect.left, rect.width));
|
||||
skinHue.value = Math.round((x / rect.width) * 360);
|
||||
|
||||
// 1. 获取 HSL 的数值
|
||||
const h = skinHue.value;
|
||||
const s = 70;
|
||||
const l = 90;
|
||||
|
||||
// 2. 转换为 16 进制色值
|
||||
skinBgColor.value = hslToHex(h, s, l);
|
||||
}
|
||||
}).exec();
|
||||
};
|
||||
|
||||
/**
|
||||
* HSL 转 Hex 工具函数
|
||||
*/
|
||||
function hslToHex(h, s, l) {
|
||||
l /= 100;
|
||||
const a = s * Math.min(l, 1 - l) / 100;
|
||||
const f = n => {
|
||||
const k = (n + h / 30) % 12;
|
||||
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
|
||||
return Math.round(255 * color).toString(16).padStart(2, '0');
|
||||
};
|
||||
return `#${f(0)}${f(8)}${f(4)}`.toUpperCase();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ranking-page {
|
||||
min-height: 100vh;
|
||||
background-color: #F8F8F8;
|
||||
padding-bottom: 200rpx;
|
||||
}
|
||||
|
||||
.content-container {
|
||||
position: relative;
|
||||
padding: 12rpx 24rpx;
|
||||
|
||||
}
|
||||
|
||||
.table-box {
|
||||
position: relative;
|
||||
|
||||
.watermark {
|
||||
position: absolute;
|
||||
height: 56rpx;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 99;
|
||||
}
|
||||
}
|
||||
|
||||
.ranking-table {
|
||||
border: 3rpx solid #333;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.ranking-row {
|
||||
display: flex;
|
||||
min-height: 148rpx;
|
||||
border-bottom: 3rpx solid #333;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.label-box {
|
||||
width: 176rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-right: 3rpx solid #333;
|
||||
}
|
||||
|
||||
.label-text {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
|
||||
&.with-stroke {
|
||||
text-shadow: 2rpx 2rpx 0 #000, -2rpx -2rpx 0 #000, 2rpx -2rpx 0 #000, -2rpx 2rpx 0 #000;
|
||||
}
|
||||
}
|
||||
|
||||
.items-box {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 14rpx 12rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.item-wrapper {
|
||||
width: 105rpx;
|
||||
height: 105rpx;
|
||||
position: relative;
|
||||
margin: 0 6rpx;
|
||||
touch-action: none;
|
||||
/* 关键:禁止浏览器默认触摸行为 */
|
||||
|
||||
&.is-dragging {
|
||||
opacity: 0.7;
|
||||
scale: 1.1;
|
||||
box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.item-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
|
||||
.del-btn {
|
||||
position: absolute;
|
||||
top: -12rpx;
|
||||
right: -12rpx;
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
background: #ff4d4f;
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 24rpx;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
background: #eee;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 4rpx;
|
||||
|
||||
.add-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
margin-top: 60rpx;
|
||||
width: 400rpx;
|
||||
background: #1777FF;
|
||||
color: #fff;
|
||||
border-radius: 50rpx;
|
||||
}
|
||||
|
||||
.bottom-tabs {
|
||||
position: fixed;
|
||||
bottom: 40rpx;
|
||||
bottom: calc(32rpx + env(safe-area-inset-bottom));
|
||||
bottom: calc(32rpx + constant(safe-area-inset-bottom));
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.tab-item {
|
||||
width: 180rpx;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
margin: 0 20rpx;
|
||||
border-radius: 10rpx;
|
||||
|
||||
&.active {
|
||||
border: 4rpx solid #1777FF;
|
||||
color: #1777FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.skin-box {
|
||||
position: relative;
|
||||
padding: 120rpx 12rpx;
|
||||
background-color: #FFDFDF;
|
||||
|
||||
.watermark {
|
||||
height: 56rpx !important;
|
||||
position: absolute;
|
||||
right: 14rpx !important;
|
||||
bottom: 32rpx !important;
|
||||
}
|
||||
|
||||
.title {
|
||||
width: 260px;
|
||||
position: absolute;
|
||||
top: 30rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
font-size: 36rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.title-input {
|
||||
min-width: 260px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border-radius: 8rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
border: 1rpx dashed #1777FF;
|
||||
}
|
||||
|
||||
.title-input {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border-radius: 8rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
width: 300rpx;
|
||||
border: 1rpx dashed #1777FF;
|
||||
}
|
||||
|
||||
.img {
|
||||
position: absolute;
|
||||
width: 90rpx;
|
||||
height: 90rpx;
|
||||
}
|
||||
|
||||
.happy {
|
||||
top: 40rpx;
|
||||
right: 30rpx;
|
||||
}
|
||||
|
||||
.sad {
|
||||
bottom: 60rpx;
|
||||
left: 100rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.save-action {
|
||||
margin-top: 60rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-bottom: 60rpx;
|
||||
}
|
||||
|
||||
.bottom-edit-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.edit-tip {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.color-picker {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
background: #fff;
|
||||
padding: 12rpx 20rpx;
|
||||
border-radius: 40rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.color-picker-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 12rpx 0;
|
||||
}
|
||||
|
||||
.hex-input {
|
||||
width: 150rpx;
|
||||
height: 56rpx;
|
||||
background: #fff;
|
||||
border-radius: 28rpx;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
border: 1rpx solid #eee;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.spectrum-picker {
|
||||
width: 600rpx;
|
||||
height: 32rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 4rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
|
||||
position: relative;
|
||||
margin: 12rpx 0;
|
||||
}
|
||||
|
||||
.slider-thumb {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 38rpx;
|
||||
height: 38rpx;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.3);
|
||||
border: 2rpx solid #fff;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.spectrum-bar {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 12rpx;
|
||||
background: linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
|
||||
}
|
||||
|
||||
.color-dot {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
border-radius: 50%;
|
||||
border: 2rpx solid #fff;
|
||||
box-shadow: 0 0 4rpx rgba(0, 0, 0, 0.2);
|
||||
margin: 0 10rpx;
|
||||
}
|
||||
|
||||
.painter-container {
|
||||
position: fixed;
|
||||
left: -9999rpx;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
const list = ref([
|
||||
{ label: '澶?, bgColor: '#BE0012', textColor: '#FFFFFF', hasShadow: true },
|
||||
{ label: '椤剁骇', bgColor: '#F17415', textColor: '#FFFFFF', hasShadow: true },
|
||||
{ label: '浜轰笂浜?, bgColor: '#F9E962', textColor: '#FFFFFF', hasShadow: true },
|
||||
{ label: 'NPC', bgColor: '#FDF5C0', textColor: '#555555', hasShadow: false },
|
||||
{ label: '鎷夊畬浜?, bgColor: '#FFFFFF', textColor: '#555555', hasShadow: false }
|
||||
]);
|
||||
|
||||
const handleAdd = (index) => {
|
||||
console.log('娣诲姞椤?, index);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="ranking-container">
|
||||
<view class="ranking-table">
|
||||
<view v-for="(item, index) in list" :key="index" class="ranking-row">
|
||||
<!-- 鏍囩鍒?-->
|
||||
<view class="label-col" :style="{ backgroundColor: item.bgColor }">
|
||||
<text class="label-text" :class="{ 'with-shadow': item.hasShadow }" :style="{ color: item.textColor }">
|
||||
{{ item.label }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<!-- 鍐呭鍒?-->
|
||||
<view class="content-col">
|
||||
<!-- 浠呭湪绗竴琛屽睍绀烘紨绀哄浘鐗?-->
|
||||
<template v-if="index === 0">
|
||||
<view class="item-box">
|
||||
<image src="/static/images/food.jpg" mode="aspectFill" class="item-img" />
|
||||
</view>
|
||||
</template>
|
||||
<!-- 娣诲姞鎸夐挳 -->
|
||||
<view class="add-btn" @tap="handleAdd(index)">
|
||||
<text class="plus-icon">+</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.ranking-container {
|
||||
padding: 30rpx 20rpx;
|
||||
background-color: #F8F8F8;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.ranking-table {
|
||||
border: 2rpx solid #333;
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ranking-row {
|
||||
display: flex;
|
||||
min-height: 180rpx;
|
||||
border-bottom: 2rpx solid #333;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.label-col {
|
||||
width: 200rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-right: 2rpx solid #333;
|
||||
padding: 0 10rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.label-text {
|
||||
font-size: 52rpx;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
line-height: 1.2;
|
||||
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||
|
||||
&.with-shadow {
|
||||
/* 寮哄姏榛戣壊鎻忚竟锛屾ā鎷?:1鏁堟灉 */
|
||||
text-shadow:
|
||||
2rpx 2rpx 0 #000,
|
||||
-2rpx -2rpx 0 #000,
|
||||
2rpx -2rpx 0 #000,
|
||||
-2rpx 2rpx 0 #000,
|
||||
0 2rpx 0 #000,
|
||||
0 -2rpx 0 #000,
|
||||
2rpx 0 0 #000,
|
||||
-2rpx 0 0 #000;
|
||||
}
|
||||
}
|
||||
|
||||
.content-col {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
padding: 20rpx;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.item-box {
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
background-color: #eee;
|
||||
border: 1rpx solid #ddd;
|
||||
}
|
||||
|
||||
.item-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
background-color: #F2F2F2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.plus-icon {
|
||||
font-size: 70rpx;
|
||||
color: #DBDBDB;
|
||||
font-weight: 200;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,399 @@
|
|||
{
|
||||
"shoppingClassfiy": {
|
||||
"dengdaifukuan": {
|
||||
"id": "",
|
||||
"shopType": "self",
|
||||
"shopName": "",
|
||||
"status": "等待付款",
|
||||
"statusDesc": "",
|
||||
"consignee": "",
|
||||
"phone": "",
|
||||
"fullAddress": "",
|
||||
"totalPrice": "",
|
||||
"carriage": "0.00",
|
||||
"products": [
|
||||
{
|
||||
"image": "",
|
||||
"name": "",
|
||||
"title": "",
|
||||
"desc": "",
|
||||
"service": "",
|
||||
"price": "",
|
||||
"count": ""
|
||||
}
|
||||
],
|
||||
"orderInfo": [
|
||||
{
|
||||
"label": "订单编号",
|
||||
"key": "orderNumber",
|
||||
"value": "",
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"label": "交易快照",
|
||||
"key": "transactionSnapshot",
|
||||
"value": "发生交易争执时,可作为判断依据"
|
||||
},
|
||||
{
|
||||
"label": "支付方式",
|
||||
"key": "paymentMethod",
|
||||
"value": "在线支付"
|
||||
},
|
||||
{
|
||||
"label": "发票类型",
|
||||
"key": "invoiceType",
|
||||
"value": "电子普通发票"
|
||||
},
|
||||
{
|
||||
"label": "下单时间",
|
||||
"key": "orderTime",
|
||||
"value": "",
|
||||
"type": "time"
|
||||
}
|
||||
],
|
||||
"sendType": [
|
||||
{
|
||||
"label": "配送方式",
|
||||
"key": "sendType",
|
||||
"value": "快递运输"
|
||||
},
|
||||
{
|
||||
"label": "期望配送时间",
|
||||
"key": "expectedDeliveryTime",
|
||||
"value": " ",
|
||||
"type": "timeRange"
|
||||
},
|
||||
{
|
||||
"label": "收货方式",
|
||||
"key": "shippingMethod",
|
||||
"value": "送货上门"
|
||||
}
|
||||
],
|
||||
"promoType": "text",
|
||||
"promoHighlight": "白条支付券0.5元优惠券"
|
||||
},
|
||||
"zhengzaichuku": {
|
||||
"id": "",
|
||||
"shopType": "self",
|
||||
"shopName": "",
|
||||
"status": "正在出库",
|
||||
"trackingTitle": "仓库处理中",
|
||||
"trackingDesc": "预计明天9:00-15:00送达",
|
||||
"trackingDesc2": "快递运输 · 温馨提示:您的订单预计x月xx日09:00- 15:00送达",
|
||||
"trackingTime": "",
|
||||
"consignee": "",
|
||||
"phone": "",
|
||||
"fullAddress": "",
|
||||
"totalPrice": "",
|
||||
"carriage": "0.00",
|
||||
"discount": "0.00",
|
||||
"products": [
|
||||
{
|
||||
"image": "",
|
||||
"title": "",
|
||||
"desc": "",
|
||||
"service": "",
|
||||
"price": "",
|
||||
"count": ""
|
||||
}
|
||||
],
|
||||
"orderInfo": [
|
||||
{
|
||||
"label": "订单编号",
|
||||
"key": "orderNumber",
|
||||
"value": "",
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"label": "交易快照",
|
||||
"key": "transactionSnapshot",
|
||||
"value": "发生交易争执时,可作为判断依据"
|
||||
},
|
||||
{
|
||||
"label": "支付方式",
|
||||
"key": "paymentMethod",
|
||||
"value": "在线支付"
|
||||
},
|
||||
{
|
||||
"label": "支付时间",
|
||||
"key": "paymentTime",
|
||||
"value": "",
|
||||
"type": "time"
|
||||
},
|
||||
{
|
||||
"label": "下单时间",
|
||||
"key": "orderTime",
|
||||
"value": "",
|
||||
"type": "time"
|
||||
}
|
||||
],
|
||||
"sendType": [
|
||||
{
|
||||
"label": "配送方式",
|
||||
"key": "sendType",
|
||||
"value": "快递运输"
|
||||
},
|
||||
{
|
||||
"label": "收货信息",
|
||||
"key": "userInfo",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"label": "收货地址",
|
||||
"key": "address",
|
||||
"value": "",
|
||||
"type": "textarea"
|
||||
},
|
||||
{
|
||||
"label": "期望配送时间",
|
||||
"key": "expectedDeliveryTime",
|
||||
"value": "",
|
||||
"type": "timeRange"
|
||||
},
|
||||
{
|
||||
"label": "收货方式",
|
||||
"key": "shippingMethod",
|
||||
"value": "送货上门"
|
||||
}
|
||||
],
|
||||
"promoType": "plus",
|
||||
"promoText": "告别凑单, 享免运优惠"
|
||||
},
|
||||
"yiqianshou": {
|
||||
"id": "",
|
||||
"shopType": "self",
|
||||
"shopName": "",
|
||||
"status": "完成",
|
||||
"statusColor": "gray",
|
||||
"trackingTitle": "已签收",
|
||||
"courier": "",
|
||||
"courierImg": "",
|
||||
"trackingDesc": "您的订单已签收,可对快递员的服务进行评价或打赏哦~",
|
||||
"trackingDesc2": "快递运输 · 温馨提示:您的订单已签收",
|
||||
"trackingTime": "",
|
||||
"carriage": "0.00",
|
||||
"discount": "0.00",
|
||||
"products": [
|
||||
{
|
||||
"image": "",
|
||||
"title": "",
|
||||
"desc": "",
|
||||
"service": "",
|
||||
"price": "",
|
||||
"count": ""
|
||||
}
|
||||
],
|
||||
"orderInfo": [
|
||||
{
|
||||
"label": "订单编号",
|
||||
"key": "orderNumber",
|
||||
"value": "",
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"label": "交易快照",
|
||||
"key": "transactionSnapshot",
|
||||
"value": "发生交易争执时,可作为判断依据"
|
||||
},
|
||||
{
|
||||
"label": "支付方式",
|
||||
"key": "paymentMethod",
|
||||
"value": "在线支付"
|
||||
},
|
||||
{
|
||||
"label": "支付时间",
|
||||
"key": "paymentTime",
|
||||
"value": "",
|
||||
"type": "time"
|
||||
},
|
||||
{
|
||||
"label": "下单时间",
|
||||
"key": "orderTime",
|
||||
"value": "",
|
||||
"type": "time"
|
||||
}
|
||||
],
|
||||
"sendType": [
|
||||
{
|
||||
"label": "配送方式",
|
||||
"key": "sendType",
|
||||
"value": "快递运输"
|
||||
},
|
||||
{
|
||||
"label": "期望配送时间",
|
||||
"key": "expectedDeliveryTime",
|
||||
"value": "",
|
||||
"type": "timeRange"
|
||||
},
|
||||
{
|
||||
"label": "收货方式",
|
||||
"key": "shippingMethod",
|
||||
"value": "送货上门"
|
||||
}
|
||||
],
|
||||
"promoType": "plus",
|
||||
"promoText": "告别凑单, 享免运优惠",
|
||||
"hasMore": true
|
||||
},
|
||||
"wancheng": {
|
||||
"id": "",
|
||||
"shopType": "jd",
|
||||
"shopName": "",
|
||||
"status": "完成",
|
||||
"statusColor": "gray",
|
||||
"carriage": "0.00",
|
||||
"discount": "0.00",
|
||||
"products": [
|
||||
{
|
||||
"image": "",
|
||||
"title": "",
|
||||
"desc": "",
|
||||
"service": "",
|
||||
"price": "",
|
||||
"count": ""
|
||||
}
|
||||
],
|
||||
"orderInfo": [
|
||||
{
|
||||
"label": "订单编号",
|
||||
"key": "orderNumber",
|
||||
"value": "",
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"label": "交易快照",
|
||||
"key": "transactionSnapshot",
|
||||
"value": "发生交易争执时,可作为判断依据"
|
||||
},
|
||||
{
|
||||
"label": "支付方式",
|
||||
"key": "paymentMethod",
|
||||
"value": "在线支付"
|
||||
},
|
||||
{
|
||||
"label": "支付时间",
|
||||
"key": "paymentTime",
|
||||
"value": "",
|
||||
"type": "time"
|
||||
},
|
||||
{
|
||||
"label": "下单时间",
|
||||
"key": "orderTime",
|
||||
"value": "",
|
||||
"type": "time"
|
||||
}
|
||||
],
|
||||
"sendType": [
|
||||
{
|
||||
"label": "配送方式",
|
||||
"key": "sendType",
|
||||
"value": "快递运输"
|
||||
},
|
||||
{
|
||||
"label": "收货信息",
|
||||
"key": "userInfo",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"label": "收货地址",
|
||||
"key": "address",
|
||||
"value": "",
|
||||
"type": "textarea"
|
||||
}
|
||||
],
|
||||
"hasMore": true
|
||||
},
|
||||
"yiquxiao": {
|
||||
"id": "",
|
||||
"shopType": "self",
|
||||
"shopName": "",
|
||||
"status": "已取消",
|
||||
"statusColor": "gray",
|
||||
"carriage": "0.00",
|
||||
"discount": "0.00",
|
||||
"consignee": "",
|
||||
"phone": "",
|
||||
"fullAddress": "",
|
||||
"products": [
|
||||
{
|
||||
"image": "",
|
||||
"title": "",
|
||||
"desc": "",
|
||||
"service": "",
|
||||
"price": "",
|
||||
"count": ""
|
||||
}
|
||||
],
|
||||
"orderInfo": [
|
||||
{
|
||||
"label": "订单编号",
|
||||
"key": "orderNumber",
|
||||
"value": "",
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"label": "交易快照",
|
||||
"key": "transactionSnapshot",
|
||||
"value": "发生交易争执时,可作为判断依据"
|
||||
},
|
||||
{
|
||||
"label": "支付方式",
|
||||
"key": "paymentMethod",
|
||||
"value": "在线支付"
|
||||
},
|
||||
{
|
||||
"label": "发票类型",
|
||||
"key": "invoiceType",
|
||||
"value": "电子普通发票"
|
||||
},
|
||||
{
|
||||
"label": "下单时间",
|
||||
"key": "orderTime",
|
||||
"value": "",
|
||||
"type": "time"
|
||||
}
|
||||
],
|
||||
"sendType": [
|
||||
{
|
||||
"label": "配送方式",
|
||||
"key": "sendType",
|
||||
"value": "快递运输"
|
||||
},
|
||||
{
|
||||
"label": "期望配送时间",
|
||||
"key": "expectedDeliveryTime",
|
||||
"value": "",
|
||||
"type": "timeRange"
|
||||
},
|
||||
{
|
||||
"label": "收货方式",
|
||||
"key": "shippingMethod",
|
||||
"value": "送货上门"
|
||||
}
|
||||
],
|
||||
"hasMore": true
|
||||
}
|
||||
},
|
||||
"shoppingType": [
|
||||
{
|
||||
"label": "等待付款",
|
||||
"key": "dengdaifukuan"
|
||||
},
|
||||
{
|
||||
"label": "正在出库",
|
||||
"key": "zhengzaichuku"
|
||||
},
|
||||
{
|
||||
"label": "完成-已签收",
|
||||
"key": "yiqianshou"
|
||||
},
|
||||
{
|
||||
"label": "完成",
|
||||
"key": "wancheng"
|
||||
},
|
||||
{
|
||||
"label": "已取消",
|
||||
"key": "yiquxiao"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
<template>
|
||||
<view class="top-fixed">
|
||||
<nav-bar title="京东" bgColor="#F0F4F9">
|
||||
<nav-bar title="京东" bgColor="#F0F4F9" :buttonGroup="buttonGroup" @button-click="util.clickTitlePopupButton">
|
||||
<template v-slot:center>
|
||||
<view class="search-box">
|
||||
<image class="search-icon" src="/static/image/shopping/jingdong/search-icon.png" mode="aspectFit">
|
||||
</image>
|
||||
<input class="input" type="text" placeholder="搜索我的订单" disabled />
|
||||
<input class="input" type="text" placeholder="搜索我的订单" />
|
||||
</view>
|
||||
</template>
|
||||
<template v-slot:right>
|
||||
|
|
@ -43,9 +43,14 @@
|
|||
</view>
|
||||
</view>
|
||||
<view class="content" :style="{ paddingTop: contentPaddingTop }">
|
||||
<shopping-card v-for="(item, index) in filteredOrderList" :key="index" :item="item"></shopping-card>
|
||||
<shopping-card v-for="(item, index) in filteredOrderList" :key="index" :item="item" @longpress="handleLongPress"
|
||||
@click="handleCardClick(item)"></shopping-card>
|
||||
<view class="empty-state" v-if="filteredOrderList.length === 0">
|
||||
<image class="empty-icon" src="/static/image/shopping/jingdong/null.png" mode="heightFix"></image>
|
||||
<text class="empty-text">您还没有相关订单</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bottom-fixed">
|
||||
<view class="bottom-fixed" :style="{ height: bottomBoxHeight }">
|
||||
<view class="bottom-item">
|
||||
<image class="like-icon" src="/static/image/shopping/jingdong/weinituijian.png" mode="aspectFit"></image>
|
||||
<text>为你推荐</text>
|
||||
|
|
@ -58,15 +63,161 @@
|
|||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 长按操作气泡菜单 -->
|
||||
<view v-if="showActionMenu" class="action-menu-mask" @click="showActionMenu = false">
|
||||
<view class="action-menu-bubble" :style="{ left: actionMenuState.x + 'px', top: actionMenuState.y + 'px' }"
|
||||
@click.stop>
|
||||
<view class="menu-item" @click.stop="editOrder">修改</view>
|
||||
<view class="menu-line"></view>
|
||||
<view class="menu-item" @click.stop="handleDeleteOrder">删除</view>
|
||||
<view class="bubble-arrow"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, getCurrentInstance } from 'vue';
|
||||
import { onShow } from '@dcloudio/uni-app';
|
||||
import ShoppingCard from '@/components/shopping/jingdong/shopping-card.vue';
|
||||
import { util } from '@/utils/common.js';
|
||||
|
||||
const showActionMenu = ref(false);
|
||||
const actionMenuState = ref({ x: 0, y: 0, item: null });
|
||||
|
||||
//导航栏菜单按钮
|
||||
const buttonGroup = [
|
||||
{
|
||||
name: "新增购物订单",
|
||||
click: () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/shopping/jingdong/add-order/add-order'
|
||||
});
|
||||
}
|
||||
}, {
|
||||
name: "新增秒送订单",
|
||||
click: () => {
|
||||
uni.showToast({
|
||||
title: '开发中,敬请期待',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
]
|
||||
/**
|
||||
* 长按弹出气泡菜单
|
||||
* @param data
|
||||
*/
|
||||
const handleLongPress = (data) => {
|
||||
console.log("长按", data);
|
||||
const event = data.event;
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
|
||||
// 兼容不同平台的坐标获取
|
||||
if (event.touches && event.touches.length > 0) {
|
||||
x = event.touches[0].clientX;
|
||||
y = event.touches[0].clientY;
|
||||
} else if (event.changedTouches && event.changedTouches.length > 0) {
|
||||
x = event.changedTouches[0].clientX;
|
||||
y = event.changedTouches[0].clientY;
|
||||
} else {
|
||||
// 兜底处理 (如模拟器点击或 detail 携带)
|
||||
x = event.clientX || (event.detail && event.detail.x) || 0;
|
||||
y = event.clientY || (event.detail && event.detail.y) || 0;
|
||||
}
|
||||
|
||||
if (x || y) {
|
||||
actionMenuState.value = {
|
||||
x: x,
|
||||
y: y,
|
||||
item: data.item
|
||||
};
|
||||
showActionMenu.value = true;
|
||||
} else {
|
||||
console.warn("无法获取长按坐标");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改订单
|
||||
*/
|
||||
const editOrder = () => {
|
||||
const item = actionMenuState.value.item;
|
||||
if (!item) return;
|
||||
showActionMenu.value = false;
|
||||
uni.navigateTo({
|
||||
url: '/pages/shopping/jingdong/add-order/add-order?id=' + item.id + '&type=' + item.shopType + '&isEdit=true'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 点击订单卡片
|
||||
* @param item 订单项
|
||||
*/
|
||||
const handleCardClick = (item) => {
|
||||
if (item.shopType !== "waimai") {
|
||||
uni.navigateTo({
|
||||
url: '/pages/shopping/jingdong/order-detail/order-detail?id=' + item.id
|
||||
});
|
||||
} else {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 删除订单
|
||||
*/
|
||||
const handleDeleteOrder = () => {
|
||||
const itemToDel = actionMenuState.value.item;
|
||||
|
||||
// 1. 尝试删除本地持久化图片文件 (商品图 + 快递员头像)
|
||||
const productImage = itemToDel?.products?.[0]?.image;
|
||||
const courierImage = itemToDel?.courierImg;
|
||||
|
||||
const cleanupFile = (path) => {
|
||||
if (path && (path.includes('_doc/') || path.includes('_downloads/') || path.includes('store_') || path.includes('at_'))) {
|
||||
uni.removeSavedFile({
|
||||
filePath: path,
|
||||
success: () => console.log('文件删除成功:', path),
|
||||
fail: (err) => console.error('文件删除失败:', err)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
cleanupFile(productImage);
|
||||
cleanupFile(courierImage);
|
||||
|
||||
// 2. 从列表中移除数据
|
||||
const realIndex = mockOrderList.value.findIndex(item => item === itemToDel);
|
||||
if (realIndex > -1) {
|
||||
mockOrderList.value.splice(realIndex, 1);
|
||||
// 同步更新缓存
|
||||
uni.setStorageSync('jingdongShopping', mockOrderList.value);
|
||||
}
|
||||
showActionMenu.value = false;
|
||||
uni.showToast({
|
||||
title: '已删除',
|
||||
icon: 'none'
|
||||
});
|
||||
};
|
||||
|
||||
const contentPaddingTop = ref('0px');
|
||||
const instance = getCurrentInstance();
|
||||
|
||||
/**
|
||||
* 底部盒子高度
|
||||
*/
|
||||
const bottomBoxHeight = computed(() => {
|
||||
const { windowHeight } = uni.getSystemInfoSync();
|
||||
return `calc(${windowHeight}px - ${contentPaddingTop.value} - 324rpx)`;
|
||||
});
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
const query = uni.createSelectorQuery().in(instance.proxy);
|
||||
|
|
@ -78,6 +229,15 @@ onMounted(() => {
|
|||
}, 100);
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
const cachedData = uni.getStorageSync('jingdongShopping');
|
||||
if (cachedData && Array.isArray(cachedData)) {
|
||||
mockOrderList.value = cachedData;
|
||||
}
|
||||
|
||||
console.log("mockOrderList", mockOrderList.value);
|
||||
});
|
||||
|
||||
const currentTab = ref(0);
|
||||
const tabList = ref([
|
||||
{ name: '全部' },
|
||||
|
|
@ -86,6 +246,11 @@ const tabList = ref([
|
|||
{ name: '服务', icon: '/static/image/shopping/jingdong/jiazheng.png', disabled: true }
|
||||
]);
|
||||
|
||||
|
||||
/**
|
||||
* 切换tab
|
||||
* @param index
|
||||
*/
|
||||
const switchTab = (index) => {
|
||||
if (tabList.value[index].disabled) return;
|
||||
currentTab.value = index;
|
||||
|
|
@ -95,12 +260,16 @@ const currentFilter = ref(-1);
|
|||
const filterList = ref([
|
||||
{ name: '待付款' },
|
||||
{ name: '待收货' },
|
||||
{ name: '待使用', disabled: true },
|
||||
{ name: '待使用', disabled: false },
|
||||
{ name: '已完成' },
|
||||
{ name: '待评价' },
|
||||
{ name: '已取消' }
|
||||
]);
|
||||
|
||||
/**
|
||||
* 切换筛选
|
||||
* @param index 索引
|
||||
*/
|
||||
const switchFilter = (index) => {
|
||||
if (filterList.value[index].disabled) return;
|
||||
if (currentFilter.value === index) {
|
||||
|
|
@ -110,298 +279,279 @@ const switchFilter = (index) => {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 提取订单的时间戳用于排序
|
||||
*/
|
||||
const getOrderTimestamp = (item) => {
|
||||
let timeStr = "";
|
||||
if (item.orderInfo) {
|
||||
const target = item.orderInfo.find(i => i.label === '下单时间' || i.label === '支付时间');
|
||||
if (target && target.value) timeStr = target.value;
|
||||
}
|
||||
if (!timeStr && item.trackingTime) {
|
||||
timeStr = item.trackingTime;
|
||||
}
|
||||
return timeStr ? new Date(timeStr.replace(/-/g, '/')).getTime() : 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* 筛选订单列表
|
||||
*/
|
||||
const filteredOrderList = computed(() => {
|
||||
const tabName = tabList.value[currentTab.value].name;
|
||||
let baseList = mockOrderList.value;
|
||||
let baseList = [...mockOrderList.value];
|
||||
|
||||
if (tabName === '购物') {
|
||||
baseList = mockOrderList.value.filter(item => item.shopType !== 'waimai');
|
||||
baseList = baseList.filter(item => item.shopType !== 'waimai');
|
||||
} else if (tabName === '秒送') {
|
||||
baseList = mockOrderList.value.filter(item => item.shopType === 'waimai');
|
||||
baseList = baseList.filter(item => item.shopType === 'waimai');
|
||||
}
|
||||
|
||||
let result = [];
|
||||
if (currentFilter.value === -1) {
|
||||
return baseList;
|
||||
result = baseList;
|
||||
} else {
|
||||
const filterName = filterList.value[currentFilter.value].name;
|
||||
result = baseList.filter(item => {
|
||||
if (filterName === '待付款') return item.status === '等待付款';
|
||||
if (filterName === '待收货') return item.status === '正在出库' || item.status === '待收货' || item.status === '运输中' || item.status === '已发货' || item.status === '商家备餐中' || item.status === '骑手到店取餐中';
|
||||
if (filterName === '待使用') return item.status === '待使用';
|
||||
if (filterName === '已完成') return item.status === '完成' || item.status === '已完成' || item.status === '已签收';
|
||||
if (filterName === '待评价') return item.status === '待评价' || item.status === '完成' || item.status === '已完成';
|
||||
if (filterName === '已取消') return item.status === '已取消';
|
||||
return true;
|
||||
});
|
||||
}
|
||||
const filterName = filterList.value[currentFilter.value].name;
|
||||
|
||||
return baseList.filter(item => {
|
||||
if (filterName === '待付款') return item.status === '等待付款';
|
||||
if (filterName === '待收货') return item.status === '正在出库' || item.status === '待收货' || item.status === '运输中' || item.status === '已发货' || item.status === '商家备餐中' || item.status === '骑手到店取餐中';
|
||||
if (filterName === '待使用') return item.status === '待使用';
|
||||
if (filterName === '已完成') return item.status === '完成' || item.status === '已完成' || item.status === '已签收';
|
||||
if (filterName === '待评价') return item.status === '待评价' || item.status === '完成' || item.status === '已完成';
|
||||
if (filterName === '已取消') return item.status === '已取消';
|
||||
return true;
|
||||
});
|
||||
// 执行倒序排序
|
||||
return result.sort((a, b) => getOrderTimestamp(b) - getOrderTimestamp(a));
|
||||
});
|
||||
|
||||
/**
|
||||
* 模拟订单列表
|
||||
*/
|
||||
const mockOrderList = ref([
|
||||
{
|
||||
shopType: 'waimai',
|
||||
shopName: '安野屋 (AARYE) 京...',
|
||||
status: '等待付款',
|
||||
statusDesc: '29分钟',
|
||||
products: [
|
||||
{
|
||||
image: '/static/image/shopping/jingdong/product1.png',
|
||||
title: '超值哈哈哈哈哈哈哈哈哈哈哈哈哈哈好一人份',
|
||||
desc: '不支持7天无理由退货',
|
||||
tags: [],
|
||||
price: '69.00',
|
||||
count: 1,
|
||||
}
|
||||
],
|
||||
promoType: 'text',
|
||||
promoHighlight: '近90天600+人回购',
|
||||
buttons: [
|
||||
{ text: '取消订单', type: 'default' },
|
||||
{ text: '查看发票', type: 'default' },
|
||||
{ text: '修改订单', type: 'default' },
|
||||
{ text: '去支付', type: 'primary' }
|
||||
]
|
||||
},
|
||||
{
|
||||
shopType: 'waimai',
|
||||
shopName: '安野屋 (AARYE) 京...',
|
||||
status: '骑手到店取餐中',
|
||||
trackingTitle: '10:22-10:55',
|
||||
trackingDesc: '骑手已到店,大王',
|
||||
trackingTime: '2026-03-10 15:14:30',
|
||||
products: [
|
||||
{
|
||||
image: '/static/image/shopping/jingdong/product1.png',
|
||||
title: '超值哈哈哈哈哈哈哈哈哈哈哈哈哈哈好热 少糖',
|
||||
desc: '不支持7天无理由退货',
|
||||
tags: [],
|
||||
price: '69.00',
|
||||
count: 1,
|
||||
}
|
||||
],
|
||||
promoType: 'cashback',
|
||||
promoText: '当笔订单返现成功到账,',
|
||||
promoAction: '点击领取',
|
||||
buttons: [
|
||||
{ text: '申请退款', type: 'default' },
|
||||
{ text: '查看发票', type: 'default' }
|
||||
]
|
||||
},
|
||||
{
|
||||
shopType: 'waimai',
|
||||
shopName: '安野屋 (AARYE) 京...',
|
||||
status: '商家备餐中',
|
||||
trackingTitle: '10:22-10:55',
|
||||
trackingDesc: '商家已接单,商品备餐中',
|
||||
trackingTime: '2026-03-10 15:14:30',
|
||||
products: [
|
||||
{
|
||||
image: '/static/image/shopping/jingdong/product1.png',
|
||||
title: '超值哈哈哈哈哈哈哈哈哈哈哈哈哈哈好热 少糖',
|
||||
desc: '不支持7天无理由退货',
|
||||
tags: [],
|
||||
price: '69.00',
|
||||
count: 1,
|
||||
}
|
||||
],
|
||||
promoType: 'cashback',
|
||||
promoText: '当笔订单返现成功到账,',
|
||||
promoAction: '点击领取',
|
||||
buttons: [
|
||||
{ text: '申请退款', type: 'default' },
|
||||
{ text: '查看发票', type: 'default' }
|
||||
]
|
||||
},
|
||||
{
|
||||
shopType: 'waimai',
|
||||
shopName: '瑞幸咖啡',
|
||||
status: '完成',
|
||||
statusColor: 'gray',
|
||||
products: [
|
||||
{
|
||||
image: '/static/image/shopping/jingdong/product1.png',
|
||||
title: '多肉桃桃哈哈哈哈哈哈哈哈哈哈好和和好',
|
||||
desc: '不支持7天无理由退货',
|
||||
tags: [],
|
||||
price: '69.00',
|
||||
count: 1,
|
||||
}
|
||||
],
|
||||
promoType: 'coupon',
|
||||
promoText: '恭喜您获得3元京东购物券',
|
||||
promoAction: '去领券',
|
||||
buttons: [
|
||||
{ text: '删除订单', type: 'default' },
|
||||
{ text: '查看发票', type: 'default' },
|
||||
{ text: '退换/售后', type: 'default' },
|
||||
{ text: '再次购买', type: 'primary' }
|
||||
]
|
||||
},
|
||||
{
|
||||
shopType: 'waimai',
|
||||
shopName: '瑞幸咖啡',
|
||||
status: '完成',
|
||||
statusColor: 'gray',
|
||||
products: [
|
||||
{
|
||||
image: '/static/image/shopping/jingdong/product1.png',
|
||||
},
|
||||
{
|
||||
image: '/static/image/shopping/jingdong/product1.png',
|
||||
},
|
||||
{
|
||||
image: '/static/image/shopping/jingdong/product1.png',
|
||||
}
|
||||
],
|
||||
price: '17.00',
|
||||
count: 2,
|
||||
buttons: [
|
||||
{ text: '删除订单', type: 'default' },
|
||||
{ text: '查看发票', type: 'default' },
|
||||
{ text: '退换/售后', type: 'default' },
|
||||
{ text: '再次购买', type: 'primary' }
|
||||
]
|
||||
},
|
||||
{
|
||||
shopType: 'waimai',
|
||||
shopName: '瑞幸咖啡',
|
||||
status: '已取消',
|
||||
statusColor: 'gray',
|
||||
products: [
|
||||
{
|
||||
image: '/static/image/shopping/jingdong/product1.png',
|
||||
title: '多肉桃桃哈哈哈哈哈哈哈哈哈哈好和和好',
|
||||
desc: '不支持7天无理由退货',
|
||||
tags: [],
|
||||
price: '69.00',
|
||||
count: 1,
|
||||
}
|
||||
],
|
||||
buttons: [
|
||||
{ text: '删除订单', type: 'default' },
|
||||
{ text: '钱款去向', type: 'default' },
|
||||
{ text: '再次购买', type: 'primary' }
|
||||
]
|
||||
},
|
||||
{
|
||||
shopType: 'self',
|
||||
shopName: '安野屋 (AARYE) 京联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
|
||||
status: '等待付款',
|
||||
statusDesc: '20小时11分钟',
|
||||
products: [
|
||||
{
|
||||
image: '/static/image/shopping/jingdong/product1.png',
|
||||
title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
|
||||
desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
|
||||
tags: ['无理由退货政策'],
|
||||
price: '69.00',
|
||||
count: 1,
|
||||
}
|
||||
],
|
||||
promoType: 'text',
|
||||
promoHighlight: '白条支付券0.5元优惠券',
|
||||
buttons: [
|
||||
{ text: '取消订单', type: 'default' },
|
||||
{ text: '查看发票', type: 'default' },
|
||||
{ text: '修改订单', type: 'default' },
|
||||
{ text: '去支付', type: 'primary', badge: '减0.5元' }
|
||||
]
|
||||
},
|
||||
{
|
||||
shopType: 'none',
|
||||
shopName: '甜小南旗舰店',
|
||||
status: '正在出库',
|
||||
trackingTitle: '仓库处理中',
|
||||
trackingDesc: '预计 3月12日24:00 前发货,3月15日 24:00 前送达',
|
||||
trackingTime: '2026-03-10 15:14:30',
|
||||
products: [
|
||||
{
|
||||
image: '/static/image/shopping/jingdong/product1.png',
|
||||
title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
|
||||
desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
|
||||
tags: ['无理由退货政策'],
|
||||
price: '69.00',
|
||||
count: 1,
|
||||
}
|
||||
],
|
||||
promoType: 'plus',
|
||||
promoText: '告别凑单, 享免运优惠',
|
||||
buttons: [
|
||||
{ text: '查看发票', type: 'default' },
|
||||
{ text: '再次购买', type: 'default' },
|
||||
{ text: '申请退款', type: 'default' },
|
||||
{ text: '修改订单', type: 'default' }
|
||||
]
|
||||
},
|
||||
{
|
||||
shopType: 'self',
|
||||
shopName: '甜小南旗舰店',
|
||||
status: '完成',
|
||||
statusColor: 'gray',
|
||||
trackingTitle: '已签收',
|
||||
trackingDesc: '您的订单已签收,可对快递员的服务进行评价或打赏哦~',
|
||||
trackingTime: '2026-03-10 15:14:30',
|
||||
products: [
|
||||
{
|
||||
image: '/static/image/shopping/jingdong/product1.png',
|
||||
title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
|
||||
desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
|
||||
tags: ['无理由退货政策'],
|
||||
price: '69.00',
|
||||
count: 1,
|
||||
}
|
||||
],
|
||||
promoType: 'plus',
|
||||
promoText: '告别凑单, 享免运优惠',
|
||||
hasMore: true,
|
||||
buttons: [
|
||||
{ text: '卖了换钱', type: 'default' },
|
||||
{ text: '退还/售后', type: 'default' },
|
||||
{ text: '再次购买', type: 'primary' }
|
||||
]
|
||||
},
|
||||
{
|
||||
shopType: 'jd',
|
||||
shopName: '甜小南旗舰店',
|
||||
status: '完成',
|
||||
statusColor: 'gray',
|
||||
products: [
|
||||
{
|
||||
image: '/static/image/shopping/jingdong/product1.png',
|
||||
title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
|
||||
desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
|
||||
tags: ['无理由退货政策'],
|
||||
price: '1669.00',
|
||||
count: 1,
|
||||
}
|
||||
],
|
||||
hasMore: true,
|
||||
buttons: [
|
||||
{ text: '再次购买', type: 'default' },
|
||||
{ text: '申请退款', type: 'default' },
|
||||
{ text: '修改订单', type: 'default' }
|
||||
]
|
||||
},
|
||||
{
|
||||
shopType: 'self',
|
||||
shopName: '甜小南旗舰店',
|
||||
status: '已取消',
|
||||
statusColor: 'gray',
|
||||
products: [
|
||||
{
|
||||
image: '/static/image/shopping/jingdong/product1.png',
|
||||
title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
|
||||
desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
|
||||
tags: ['无理由退货政策'],
|
||||
price: '1669.00',
|
||||
count: 1,
|
||||
}
|
||||
],
|
||||
buttons: [
|
||||
{ text: '再次购买', type: 'default' },
|
||||
{ text: '申请退款', type: 'default' },
|
||||
{ text: '修改订单', type: 'primary' }
|
||||
]
|
||||
}
|
||||
// {
|
||||
// id: 123211111,
|
||||
// shopType: 'waimai',
|
||||
// shopName: '安野屋 (AARYE) 京...',
|
||||
// status: '等待付款',
|
||||
// statusDesc: '29分钟',
|
||||
// products: [
|
||||
// {
|
||||
// image: '/static/image/shopping/jingdong/product1.png',
|
||||
// title: '超值哈哈哈哈哈哈哈哈哈哈哈哈哈哈好一人份',
|
||||
// desc: '不支持7天无理由退货',
|
||||
// service: "",
|
||||
// price: '69.00',
|
||||
// count: 1,
|
||||
// }
|
||||
// ],
|
||||
// promoType: 'text',
|
||||
// promoHighlight: '近90天600+人回购',
|
||||
// },
|
||||
// {
|
||||
// id: 9632554,
|
||||
// shopType: 'waimai',
|
||||
// shopName: '安野屋 (AARYE) 京...',
|
||||
// status: '骑手到店取餐中',
|
||||
// trackingTitle: '10:22-10:55',
|
||||
// trackingDesc: '骑手已到店,大王',
|
||||
// trackingTime: '2026-03-10 15:14:30',
|
||||
// products: [
|
||||
// {
|
||||
// image: '/static/image/shopping/jingdong/product1.png',
|
||||
// title: '超值哈哈哈哈哈哈哈哈哈哈哈哈哈哈好热 少糖',
|
||||
// desc: '不支持7天无理由退货',
|
||||
// service: "",
|
||||
// tags: [],
|
||||
// price: '69.00',
|
||||
// count: 1,
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// id: 63254112,
|
||||
// shopType: 'waimai',
|
||||
// shopName: '安野屋 (AARYE) 京...',
|
||||
// status: '商家备餐中',
|
||||
// trackingTitle: '10:22-10:55',
|
||||
// trackingDesc: '商家已接单,商品备餐中',
|
||||
// trackingTime: '2026-03-10 15:14:30',
|
||||
// products: [
|
||||
// {
|
||||
// image: '/static/image/shopping/jingdong/product1.png',
|
||||
// title: '超值哈哈哈哈哈哈哈哈哈哈哈哈哈哈好热 少糖',
|
||||
// desc: '不支持7天无理由退货',
|
||||
// service: "",
|
||||
// tags: [],
|
||||
// price: '69.00',
|
||||
// count: 1,
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// id: 78456211,
|
||||
// shopType: 'waimai',
|
||||
// shopName: '瑞幸咖啡',
|
||||
// status: '完成',
|
||||
// statusColor: 'gray',
|
||||
// products: [
|
||||
// {
|
||||
// image: '/static/image/shopping/jingdong/product1.png',
|
||||
// title: '多肉桃桃哈哈哈哈哈哈哈哈哈哈好和和好',
|
||||
// desc: '不支持7天无理由退货',
|
||||
// service: "",
|
||||
// tags: [],
|
||||
// price: '69.00',
|
||||
// count: 1,
|
||||
// }
|
||||
// ],
|
||||
// promoType: 'coupon',
|
||||
// promoText: '恭喜您获得3元京东购物券',
|
||||
// promoAction: '去领券'
|
||||
// },
|
||||
// {
|
||||
// id: 56322115,
|
||||
// shopType: 'waimai',
|
||||
// shopName: '瑞幸咖啡',
|
||||
// status: '完成',
|
||||
// statusColor: 'gray',
|
||||
// products: [
|
||||
// {
|
||||
// image: '/static/image/shopping/jingdong/product1.png',
|
||||
// },
|
||||
// {
|
||||
// image: '/static/image/shopping/jingdong/product1.png',
|
||||
// },
|
||||
// {
|
||||
// image: '/static/image/shopping/jingdong/product1.png',
|
||||
// }
|
||||
// ],
|
||||
// price: '17.00',
|
||||
// count: 2,
|
||||
// },
|
||||
// {
|
||||
// id: 52322221,
|
||||
// shopType: 'waimai',
|
||||
// shopName: '瑞幸咖啡',
|
||||
// status: '已取消',
|
||||
// statusColor: 'gray',
|
||||
// products: [
|
||||
// {
|
||||
// image: '/static/image/shopping/jingdong/product1.png',
|
||||
// title: '多肉桃桃哈哈哈哈哈哈哈哈哈哈好和和好',
|
||||
// desc: '不支持7天无理由退货',
|
||||
// tags: [],
|
||||
// service: "",
|
||||
// price: '69.00',
|
||||
// count: 1,
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// id: 8562245551,
|
||||
// shopType: 'self',
|
||||
// shopName: '安野屋 (AARYE) 京联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
|
||||
// status: '等待付款',
|
||||
// statusDesc: '20小时11分钟',
|
||||
// products: [
|
||||
// {
|
||||
// image: '/static/image/shopping/jingdong/product1.png',
|
||||
// title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
|
||||
// desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
|
||||
// tags: ['无理由退货政策'],
|
||||
// service: "无理由退货政策",
|
||||
// price: '69.00',
|
||||
// count: 1,
|
||||
// }
|
||||
// ],
|
||||
// promoType: 'text',
|
||||
// promoHighlight: '白条支付券0.5元优惠券',
|
||||
// },
|
||||
// {
|
||||
// id: 5504455,
|
||||
// shopType: 'none',
|
||||
// shopName: '甜小南旗舰店',
|
||||
// status: '正在出库',
|
||||
// trackingTitle: '仓库处理中',
|
||||
// trackingDesc: '预计 3月12日24:00 前发货,3月15日 24:00 前送达',
|
||||
// trackingTime: '2026-03-10 15:14:30',
|
||||
// products: [
|
||||
// {
|
||||
// image: '/static/image/shopping/jingdong/product1.png',
|
||||
// title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
|
||||
// desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
|
||||
// tags: ['无理由退货政策'],
|
||||
// service: "无理由退货政策",
|
||||
// price: '69.00',
|
||||
// count: 1,
|
||||
// }
|
||||
// ],
|
||||
// promoType: 'plus',
|
||||
// promoText: '告别凑单, 享免运优惠',
|
||||
// },
|
||||
// {
|
||||
// id: 585552,
|
||||
// shopType: 'self',
|
||||
// shopName: '甜小南旗舰店',
|
||||
// status: '完成',
|
||||
// statusColor: 'gray',
|
||||
// trackingTitle: '已签收',
|
||||
// trackingDesc: '您的订单已签收,可对快递员的服务进行评价或打赏哦~',
|
||||
// trackingTime: '2026-03-10 15:14:30',
|
||||
// products: [
|
||||
// {
|
||||
// image: '/static/image/shopping/jingdong/product1.png',
|
||||
// title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
|
||||
// desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
|
||||
// tags: ['无理由退货政策'],
|
||||
// service: "无理由退货政策",
|
||||
// price: '69.00',
|
||||
// count: 1,
|
||||
// }
|
||||
// ],
|
||||
// promoType: 'plus',
|
||||
// promoText: '告别凑单, 享免运优惠',
|
||||
// hasMore: true,
|
||||
// },
|
||||
// {
|
||||
// id: 4545451,
|
||||
// shopType: 'jd',
|
||||
// shopName: '甜小南旗舰店',
|
||||
// status: '完成',
|
||||
// statusColor: 'gray',
|
||||
// products: [
|
||||
// {
|
||||
// image: '/static/image/shopping/jingdong/product1.png',
|
||||
// title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
|
||||
// desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
|
||||
// tags: ['无理由退货政策'],
|
||||
// service: "无理由退货政策",
|
||||
// price: '1669.00',
|
||||
// count: 1,
|
||||
// }
|
||||
// ],
|
||||
// hasMore: true,
|
||||
// },
|
||||
// {
|
||||
// id: 1236524,
|
||||
// shopType: 'self',
|
||||
// shopName: '甜小南旗舰店',
|
||||
// status: '已取消',
|
||||
// statusColor: 'gray',
|
||||
// products: [
|
||||
// {
|
||||
// image: '/static/image/shopping/jingdong/product1.png',
|
||||
// title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
|
||||
// desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
|
||||
// tags: ['无理由退货政策'],
|
||||
// service: "无理由退货政策",
|
||||
// price: '1669.00',
|
||||
// count: 1,
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
]);
|
||||
</script>
|
||||
|
||||
|
|
@ -431,7 +581,7 @@ const mockOrderList = ref([
|
|||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1rpx solid #E5E5E5;
|
||||
border: 0.5px solid #E5E5E5;
|
||||
|
||||
.search-icon {
|
||||
width: 36rpx;
|
||||
|
|
@ -603,6 +753,12 @@ const mockOrderList = ref([
|
|||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
|
||||
.bottom-fixed {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.bottom-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -622,7 +778,8 @@ const mockOrderList = ref([
|
|||
|
||||
.upload-screenshot-box {
|
||||
width: 100%;
|
||||
height: 540rpx;
|
||||
flex: 1;
|
||||
min-height: 540rpx;
|
||||
background-color: #FFFFFF;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -647,4 +804,69 @@ const mockOrderList = ref([
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40rpx 0 64rpx;
|
||||
|
||||
.empty-icon {
|
||||
height: 220rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 22rpx;
|
||||
color: #999A9E;
|
||||
line-height: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.action-menu-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.action-menu-bubble {
|
||||
position: fixed;
|
||||
background-color: #3B3C3E;
|
||||
border-radius: 12rpx;
|
||||
width: 200rpx;
|
||||
transform: translate(-50%, calc(-100% - 15px));
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.2);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.menu-item {
|
||||
color: #FFFFFF;
|
||||
font-size: 26rpx;
|
||||
text-align: center;
|
||||
padding: 24rpx 0;
|
||||
line-height: 26rpx;
|
||||
}
|
||||
|
||||
.menu-line {
|
||||
height: 0.5px;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
margin: 0 24rpx;
|
||||
}
|
||||
|
||||
.bubble-arrow {
|
||||
position: absolute;
|
||||
bottom: -12rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 12rpx solid transparent;
|
||||
border-right: 12rpx solid transparent;
|
||||
border-top: 14rpx solid #3B3C3E;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
After Width: | Height: | Size: 212 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 530 B |
|
After Width: | Height: | Size: 802 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 256 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 45 KiB |