账单详情页展示,完成添加标签和备注字段
6
App.vue
|
|
@ -12,6 +12,6 @@ export default {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import './common/main.css';
|
||||
// @import './common/layouts.less';</style>
|
||||
<style>
|
||||
@import "./common/color.css";
|
||||
</style>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/* 常用颜色变量 */
|
||||
:root {
|
||||
--text-color: #1a1a1a;
|
||||
--primary-color: #007aff;
|
||||
--success-color: #4cd964;
|
||||
--warning-color: #ff9500;
|
||||
--error-color: #ff3b30;
|
||||
--text-primary: #333;
|
||||
--text-secondary: #969696;
|
||||
--text-tertiary: #999;
|
||||
--bg-primary: #ffffff;
|
||||
--bg-secondary: #f5f5f5;
|
||||
--border-color: #D8D8D8;
|
||||
--page-bg-color: #f0f3f8;
|
||||
--footer-text-color: #CBCED3;
|
||||
}
|
||||
|
||||
/* 重置样式 */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 基础样式 */
|
||||
page {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
"Helvetica Neue", Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: var(--text-color);
|
||||
background-color: var(--page-bg-color);
|
||||
}
|
||||
|
|
@ -1,22 +1,5 @@
|
|||
/* 公共CSS文件 */
|
||||
|
||||
/* 重置样式 */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
/* color: var(--text-color); */
|
||||
}
|
||||
|
||||
/* 基础样式 */
|
||||
body {
|
||||
/* font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
"Helvetica Neue", Arial, sans-serif; */
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: var(--text-color);
|
||||
background-color: var(--page-bg-color);
|
||||
}
|
||||
@import "./color.css";
|
||||
|
||||
.w100 {
|
||||
width: 100%
|
||||
|
|
@ -26,23 +9,6 @@ body {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
/* 常用颜色变量 */
|
||||
:root {
|
||||
--text-color: #1a1a1a;
|
||||
--primary-color: #007aff;
|
||||
--success-color: #4cd964;
|
||||
--warning-color: #ff9500;
|
||||
--error-color: #ff3b30;
|
||||
--text-primary: #333;
|
||||
--text-secondary: #969696;
|
||||
--text-tertiary: #999;
|
||||
--bg-primary: #ffffff;
|
||||
--bg-secondary: #f5f5f5;
|
||||
--border-color: #D8D8D8;
|
||||
--page-bg-color: #f0f3f8;
|
||||
--footer-text-color: #CBCED3;
|
||||
}
|
||||
|
||||
/* 文本样式 */
|
||||
.text-center {
|
||||
text-align: center;
|
||||
|
|
@ -371,6 +337,16 @@ body {
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.over-scroll {
|
||||
overflow: scroll;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 文本截断 */
|
||||
.text-ellipsis {
|
||||
overflow: hidden;
|
||||
|
|
@ -400,6 +376,11 @@ body {
|
|||
src: url("/static/font/WeChatSansStd-Medium.otf");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "wxNumberLight";
|
||||
src: url("/static/font/WeChatSansStd-Light.otf");
|
||||
}
|
||||
|
||||
.alipay-font {
|
||||
font-family: "alipayNumber";
|
||||
}
|
||||
|
|
@ -411,3 +392,7 @@ body {
|
|||
.wx-font-medium {
|
||||
font-family: "wxNumberMedium";
|
||||
}
|
||||
|
||||
.wx-font-light {
|
||||
font-family: "wxNumberLight";
|
||||
}
|
||||
|
|
@ -19,12 +19,18 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 50rpx;
|
||||
margin-bottom: 32rpx;
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: var(--font-color);
|
||||
|
||||
.text {
|
||||
color: #AAAAAA;
|
||||
font-size: 24rpx;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.close-image {
|
||||
|
|
|
|||
|
|
@ -2,28 +2,25 @@
|
|||
<view class="balance-list-container">
|
||||
<view>
|
||||
<view v-for="item in props.list" :key="item.name" class="balance-item"
|
||||
:class="{ 'flex-align-center': isBalance }">
|
||||
:class="{ 'flex-align-center': isBalance }" @click="onClick(item)"
|
||||
@touchstart="handleTouchStart($event, item)" @touchmove="handleTouchMove" @touchend="handleTouchEnd">
|
||||
<image class="img" :src="item.imgUrl" mode="aspectFill"></image>
|
||||
<view class="balance-item-text-container">
|
||||
<view class="balance-item-text">
|
||||
<view>
|
||||
<text class="name">{{ item.name }}</text>
|
||||
<view class="name" :class="{ 'line-height-51rpx': isBalance }">
|
||||
{{ item.name }}
|
||||
</view>
|
||||
<view v-if="item.classification">
|
||||
<text class="time secondary">{{ item.classification }}</text>
|
||||
</view>
|
||||
<view>
|
||||
<text v-if="item.classification" class="time secondary">{{ item.classification }}</text>
|
||||
<text class="time secondary">{{ item.time }}</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="balance-item-text text-right" :class="{ 'flex-between': isBalance }">
|
||||
<view class="money alipay-font"
|
||||
:class="item.isAdd ? (isBalance ? 'add-color' : 'red-add-color') : 'minus-color'">
|
||||
:class="item.isAdd ? (isBalance ? 'add-color' : 'red-add-color') : 'minus-color', { 'line-height-51rpx': isBalance }">
|
||||
{{ item.isAdd ? '+' : '-' }}{{ Number(item.money).toFixed(2) }}
|
||||
</view>
|
||||
<view v-if="item.isRefund" class="refund">已全额退款</view>
|
||||
<view v-if="isBalance" class="balance secondary">余额 <text class="balance-text">{{
|
||||
<view v-if="isBalance" class="balance secondary">余额 <text
|
||||
class="balance-text wx-font-regular">{{
|
||||
Number(item.balance).toFixed(2)
|
||||
}}</text>元</view>
|
||||
</view>
|
||||
|
|
@ -53,15 +50,59 @@ const props = defineProps({
|
|||
})
|
||||
|
||||
// 定义事件
|
||||
const emit = defineEmits(['onBill'])
|
||||
const emit = defineEmits(['onBill', 'longPress'])
|
||||
|
||||
const data = reactive({})
|
||||
|
||||
let timer = null
|
||||
let isLongPressTriggered = false
|
||||
let touchStartX = 0
|
||||
let touchStartY = 0
|
||||
|
||||
|
||||
const handleTouchStart = (e, item) => {
|
||||
isLongPressTriggered = false
|
||||
if (e.touches && e.touches.length > 0) {
|
||||
touchStartX = e.touches[0].clientX
|
||||
touchStartY = e.touches[0].clientY
|
||||
}
|
||||
|
||||
timer = setTimeout(() => {
|
||||
isLongPressTriggered = true
|
||||
emit('longPress', {
|
||||
event: e,
|
||||
item
|
||||
})
|
||||
}, 1500)
|
||||
}
|
||||
|
||||
const handleTouchMove = (e) => {
|
||||
if (e.touches && e.touches.length > 0) {
|
||||
const moveX = e.touches[0].clientX
|
||||
const moveY = e.touches[0].clientY
|
||||
// If moved significantly, cancel long press
|
||||
if (Math.abs(moveX - touchStartX) > 10 || Math.abs(moveY - touchStartY) > 10) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
} else {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
}
|
||||
|
||||
const handleTouchEnd = () => {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
|
||||
const onClick = (item) => {
|
||||
if (isLongPressTriggered) return
|
||||
emit('onBill', item)
|
||||
}
|
||||
|
||||
onMounted(() => { })
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* @import '../../common/main.css'; */
|
||||
@import '../../common/main.css';
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
|
|
@ -80,8 +121,20 @@ onMounted(() => { })
|
|||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-left: 12px;
|
||||
box-shadow: 0 0.3px 0 0 #F0F0EE;
|
||||
position: relative;
|
||||
padding: 12px 12px 12px 0;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background-color: #F0F0EE;
|
||||
transform: scaleY(0.1);
|
||||
transform-origin: 0 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.img {
|
||||
|
|
@ -98,17 +151,26 @@ onMounted(() => { })
|
|||
// justify-content: space-between;
|
||||
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
color: #343434;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.line-height-51rpx {
|
||||
line-height: 51rpx;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
color: var(--text-secondary);
|
||||
font-size: 12px;
|
||||
font-size: 24rpx;
|
||||
margin-top: 14rpx;
|
||||
|
||||
}
|
||||
|
||||
.money {
|
||||
font-size: 17px;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.add-color {
|
||||
|
|
@ -132,6 +194,7 @@ onMounted(() => { })
|
|||
|
||||
.refund {
|
||||
color: #EA6B48;
|
||||
margin-top: 14rpx;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -120,6 +120,8 @@ const buttonClick = (button) => {
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import "/common/main.css";
|
||||
|
||||
.nav-bar-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -201,5 +203,6 @@ const buttonClick = (button) => {
|
|||
border-radius: 8px;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name" : "alipay-emulator",
|
||||
"appid" : "__UNI__B05EDBF",
|
||||
"appid" : "__UNI__D535736",
|
||||
"description" : "",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
|
|
@ -17,7 +17,9 @@
|
|||
"delay" : 0
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {},
|
||||
"modules" : {
|
||||
"Camera" : {}
|
||||
},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
/* android打包配置 */
|
||||
|
|
@ -46,7 +48,8 @@
|
|||
},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs" : {}
|
||||
}
|
||||
},
|
||||
"nvueLaunchMode" : ""
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
"quickapp" : {},
|
||||
|
|
|
|||
17
pages.json
|
|
@ -5,7 +5,8 @@
|
|||
"path": "pages/balance/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "余额页面",
|
||||
"navigationStyle": "custom"
|
||||
"navigationStyle": "custom",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -35,6 +36,20 @@
|
|||
"navigationBarTitleText": "热门图标",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/balance/fast-entrance-management/fast-entrance-management",
|
||||
"style": {
|
||||
"navigationBarTitleText": "快速入口页面",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/bill/bill-detail/bill-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "账单详情页",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,271 @@
|
|||
<template>
|
||||
<view class="container">
|
||||
<NavBar class="nav-bar" title="快捷入口" :bgColor="data.navBar.bgColor" isRightButton @right-click="onRightClick">
|
||||
</NavBar>
|
||||
<view class="content">
|
||||
<view class="grid-card">
|
||||
<view class="grid-list">
|
||||
<!-- 遍历显示网格项,绑定触摸事件以支持拖拽 -->
|
||||
<view class="grid-item" v-for="(item, index) in data.list" :key="item.id"
|
||||
:class="{ 'dragging-placeholder': draggingItem && draggingItem.id === item.id }"
|
||||
@touchstart="handleTouchStart($event, item, index)" @touchmove.stop.prevent="handleTouchMove"
|
||||
@touchend="handleTouchEnd">
|
||||
<view class="icon-box">
|
||||
<image class="icon" :src="`/static/image/balance/menu-icon/${item.label}.png`"
|
||||
mode="aspectFit"></image>
|
||||
</view>
|
||||
<text class="name">{{ item.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="footer-tip">*长按可以排序哟</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 拖拽时显示的浮动项(跟随手指) -->
|
||||
<view v-if="draggingItem" class="grid-item floating-item" :style="dragStyle">
|
||||
<view class="icon-box">
|
||||
<image class="icon" :src="`/static/image/balance/menu-icon/${draggingItem.label}.png`" mode="aspectFit">
|
||||
</image>
|
||||
</view>
|
||||
<text class="name">{{ draggingItem.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import NavBar from '@/components/nav-bar/nav-bar.vue'
|
||||
import { fastEntranceList } from '@/static/json/initial.json'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { storage } from '@/utils/storage'
|
||||
import {
|
||||
reactive,
|
||||
toRefs,
|
||||
ref,
|
||||
nextTick
|
||||
} from 'vue'
|
||||
|
||||
const data = reactive({
|
||||
navBar: {
|
||||
bgColor: "#F5F5F5"
|
||||
},
|
||||
list: []
|
||||
})
|
||||
|
||||
let { list } = toRefs(data)
|
||||
|
||||
// 拖拽相关状态
|
||||
const draggingItem = ref(null) // 当前正在拖拽的项
|
||||
const dragStyle = ref({ top: '0px', left: '0px' }) // 拖拽项的样式(位置)
|
||||
let startX = 0 // 触摸开始X坐标
|
||||
let startY = 0 // 触摸开始Y坐标
|
||||
let longPressTimer = null // 长按定时器
|
||||
let itemRects = [] // 所有网格项的位置信息
|
||||
let containerTop = 0 // 容器顶部偏移
|
||||
|
||||
onShow(() => {
|
||||
// 优先从缓存读取
|
||||
const cachedList = storage.get('fastEntranceList')
|
||||
if (cachedList && cachedList.length > 0) {
|
||||
data.list = cachedList
|
||||
} else {
|
||||
// 深拷贝数据,防止直接修改原引用的json数据,允许页面内重新排序
|
||||
data.list = JSON.parse(JSON.stringify(fastEntranceList))
|
||||
}
|
||||
|
||||
// 渲染完成后测量位置
|
||||
nextTick(() => {
|
||||
measureItems()
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* 测量所有网格项的位置,用于后续碰撞检测
|
||||
*/
|
||||
const measureItems = () => {
|
||||
uni.createSelectorQuery().select('.grid-list').boundingClientRect(res => {
|
||||
if (res) {
|
||||
containerTop = res.top
|
||||
}
|
||||
}).exec()
|
||||
|
||||
uni.createSelectorQuery().selectAll('.grid-item').boundingClientRect(rects => {
|
||||
itemRects = rects
|
||||
}).exec()
|
||||
}
|
||||
|
||||
/**
|
||||
* 触摸开始:启动长按定时器
|
||||
*/
|
||||
const handleTouchStart = (e, item, index) => {
|
||||
if (e.touches.length !== 1) return
|
||||
|
||||
startX = e.touches[0].clientX
|
||||
startY = e.touches[0].clientY
|
||||
|
||||
longPressTimer = setTimeout(() => {
|
||||
// 长按触发拖拽
|
||||
draggingItem.value = item
|
||||
// 更新拖拽项位置使其出现在手指中心
|
||||
updateDragPosition(startX, startY)
|
||||
|
||||
// 震动反馈
|
||||
uni.vibrateShort()
|
||||
}, 500) // 500ms 长按触发
|
||||
}
|
||||
|
||||
/**
|
||||
* 触摸移动:更新拖拽位置并检测排序
|
||||
*/
|
||||
const handleTouchMove = (e) => {
|
||||
if (!draggingItem.value) {
|
||||
// 如果还没触发拖拽,检测手指移动距离,如果移动过多则取消长按定时器(由点击变为滑动)
|
||||
const moveX = e.touches[0].clientX
|
||||
const moveY = e.touches[0].clientY
|
||||
if (Math.abs(moveX - startX) > 10 || Math.abs(moveY - startY) > 10) {
|
||||
clearTimeout(longPressTimer)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const x = e.touches[0].clientX
|
||||
const y = e.touches[0].clientY
|
||||
|
||||
updateDragPosition(x, y)
|
||||
checkReorder(x, y)
|
||||
}
|
||||
|
||||
/**
|
||||
* 触摸结束:重置状态
|
||||
*/
|
||||
const handleTouchEnd = () => {
|
||||
clearTimeout(longPressTimer)
|
||||
draggingItem.value = null
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新拖拽浮层的位置
|
||||
*/
|
||||
const updateDragPosition = (x, y) => {
|
||||
// 将项目中心定位到手指位置
|
||||
// 假设项目宽度大约占屏幕宽度的20% (例如75px) -> 中心偏移约37px
|
||||
// 仅用于视觉更新
|
||||
dragStyle.value = {
|
||||
top: (y - 40) + 'px',
|
||||
left: (x - 37) + 'px',
|
||||
position: 'fixed',
|
||||
zIndex: 999,
|
||||
opacity: 0.8,
|
||||
width: itemRects[0] ? itemRects[0].width + 'px' : '20%' // 匹配实际宽度
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测是否需要重新排序
|
||||
*/
|
||||
const checkReorder = (x, y) => {
|
||||
// 查找当前手指位置所在的网格项索引
|
||||
const targetIndex = itemRects.findIndex(rect =>
|
||||
x >= rect.left && x <= rect.right &&
|
||||
y >= rect.top && y <= rect.bottom
|
||||
)
|
||||
|
||||
if (targetIndex !== -1) {
|
||||
const draggedIndex = data.list.findIndex(item => item.id === draggingItem.value.id)
|
||||
if (draggedIndex !== -1 && draggedIndex !== targetIndex) {
|
||||
// 交换逻辑:将原位置删掉,插入新位置
|
||||
const item = data.list.splice(draggedIndex, 1)[0]
|
||||
data.list.splice(targetIndex, 0, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const onRightClick = () => {
|
||||
// 保存到缓存
|
||||
storage.set('fastEntranceList', data.list)
|
||||
|
||||
uni.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success',
|
||||
duration: 500
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 500)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page {
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.grid-card {
|
||||
background-color: #FFFFFF;
|
||||
border-radius: 12px;
|
||||
padding: 20px 0;
|
||||
padding-bottom: 12px;
|
||||
|
||||
.footer-tip {
|
||||
text-align: right;
|
||||
font-size: 20rpx;
|
||||
color: #767676;
|
||||
padding: 0 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.grid-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
width: 20%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.icon-box {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: 1px dashed #cccccc;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 20px;
|
||||
/* Adjusted based on visual ratio in screenshot inside the box */
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 12px;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.dragging-placeholder {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.floating-item {
|
||||
pointer-events: none;
|
||||
/* Let touches pass through to underlying elements for detection */
|
||||
}
|
||||
</style>
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
<text>可用余额(元)</text>
|
||||
<image class="img" src="/static/image/balance/eye.png" mode=""></image>
|
||||
</view>
|
||||
<view class="balance flex-cneter">
|
||||
<view class="balance flex-cneter" @click="editBalance">
|
||||
<text class="text alipay-font">{{ Number(balance).toFixed(2) }}</text>
|
||||
</view>
|
||||
<view class="button-group">
|
||||
|
|
@ -48,9 +48,8 @@
|
|||
</view>
|
||||
</view>
|
||||
<view class="menu-box">
|
||||
<view class="item" v-for="item in menuList">
|
||||
<image class="menu-icon" :src="`/static/image/balance/menu-icon/${item.imgLabel}.png`"
|
||||
mode="">
|
||||
<view class="item menu-icon-box" v-for="item in menuList">
|
||||
<image class="menu-icon" :src="`/static/image/balance/menu-icon/${item.label}.png`" mode="">
|
||||
</image>
|
||||
<text class="icon-name">{{ item.name }}</text>
|
||||
</view>
|
||||
|
|
@ -64,7 +63,7 @@
|
|||
</view>
|
||||
</view>
|
||||
<view class="item">
|
||||
<BalanceList :list="changeDetailList" />
|
||||
<BalanceList :list="changeDetailList" @longPress="onLongPress" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -74,6 +73,15 @@
|
|||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- Custom Context Menu (Positioned at touch point) -->
|
||||
<view v-if="contextMenu.visible" class="context-menu-mask" @touchstart="closeContextMenu">
|
||||
<view class="context-menu" :style="{ top: contextMenu.y + 'px', left: contextMenu.x + 'px' }"
|
||||
@touchstart.stop>
|
||||
<view class="menu-item" @click="handleEdit">编辑</view>
|
||||
<view class="menu-item delete" @click="handleDelete">删除</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 输入框示例 -->
|
||||
<uni-popup ref="inputDialog" type="dialog">
|
||||
|
|
@ -87,6 +95,7 @@
|
|||
<script setup>
|
||||
import NavBar from '@/components/nav-bar/nav-bar'
|
||||
import BalanceList from '@/components/balance-list/balance-list.vue'
|
||||
import { fastEntranceList } from '@/static/json/initial.json'
|
||||
|
||||
import {
|
||||
util,
|
||||
|
|
@ -114,48 +123,35 @@ import {
|
|||
useStore,
|
||||
} from '@/store'
|
||||
|
||||
import {
|
||||
dateUtil
|
||||
} from '@/utils/common.js'
|
||||
|
||||
// 获取store
|
||||
const {
|
||||
store
|
||||
store,
|
||||
getBillList,
|
||||
deleteBill
|
||||
} = useStore()
|
||||
|
||||
const inputDialog = ref(null)
|
||||
|
||||
const menuList = [{
|
||||
imgLabel: "zhuanzhang",
|
||||
name: "转账"
|
||||
}, {
|
||||
imgLabel: "yinhangka",
|
||||
name: "银行卡"
|
||||
}, {
|
||||
imgLabel: "qinqingka",
|
||||
name: "亲情卡"
|
||||
}, {
|
||||
imgLabel: "xiaohebao",
|
||||
name: "小荷包"
|
||||
}, {
|
||||
imgLabel: "zhuanyongjin",
|
||||
name: "专用金"
|
||||
}]
|
||||
|
||||
const buttonGroup = [{
|
||||
name: "编辑模式",
|
||||
click: () => {
|
||||
console.log("编辑模式")
|
||||
}
|
||||
},
|
||||
const buttonGroup = [
|
||||
{
|
||||
name: "修改余额",
|
||||
click: () => {
|
||||
console.log("修改余额")
|
||||
data.balance = Number(data.balance).toFixed(2)
|
||||
inputDialog.value.open()
|
||||
editBalance()
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "快捷入口管理",
|
||||
click: () => {
|
||||
console.log("快捷入口管理")
|
||||
util.goPage('/pages/balance/fast-entrance-management/fast-entrance-management')
|
||||
}
|
||||
}, {
|
||||
name: "添加余额变动明细",
|
||||
click: () => {
|
||||
util.goPage(`/pages/bill/add-bill/add-bill?type=${1}&payMethod=余额`)
|
||||
}
|
||||
}, {
|
||||
name: "账单列表",
|
||||
|
|
@ -172,36 +168,14 @@ const data = reactive({
|
|||
statusBarHeight: 0,
|
||||
balance: 0,
|
||||
windowHeight: 0,
|
||||
changeDetailList: [{
|
||||
time: "2023-08-15 10:00:00",
|
||||
type: "充值",
|
||||
money: "1000.00",
|
||||
isAdd: true,
|
||||
name: "充值",
|
||||
balance: 1000.00,
|
||||
imgUrl: "https://picsum.photos/200/200?random=1"
|
||||
}, {
|
||||
time: "2023-08-15 10:00:00",
|
||||
type: "充值",
|
||||
money: "1000.00",
|
||||
isAdd: false,
|
||||
name: "充值",
|
||||
balance: 1000.00,
|
||||
imgUrl: "https://picsum.photos/200/200?random=1"
|
||||
}, {
|
||||
time: "2023-08-15 10:00:00",
|
||||
type: "充值",
|
||||
money: "1000.00",
|
||||
isAdd: true,
|
||||
name: "充值",
|
||||
balance: 1000.00,
|
||||
imgUrl: "https://picsum.photos/200/200?random=1"
|
||||
}]
|
||||
changeDetailList: [],
|
||||
menuList: []
|
||||
})
|
||||
|
||||
let {
|
||||
balance,
|
||||
changeDetailList
|
||||
changeDetailList,
|
||||
menuList
|
||||
} = toRefs(data)
|
||||
|
||||
onLoad(async () => {
|
||||
|
|
@ -216,11 +190,56 @@ onLoad(async () => {
|
|||
})
|
||||
|
||||
onShow(() => {
|
||||
// #ifdef APP-PLUS
|
||||
util.setAndroidSystemBarColor('#F0F3F8')
|
||||
// #endif
|
||||
|
||||
// 获取快速入口配置
|
||||
data.menuList = fastEntranceData()
|
||||
|
||||
getRecentBills()
|
||||
})
|
||||
|
||||
const fastEntranceData = () => {
|
||||
// 优先从缓存读取
|
||||
const cachedList = storage.get('fastEntranceList')
|
||||
if (cachedList && cachedList.length > 0) {
|
||||
return cachedList
|
||||
} else {
|
||||
return JSON.parse(JSON.stringify(fastEntranceList))
|
||||
}
|
||||
}
|
||||
|
||||
// 获取账单最新的三条余额相关的数据
|
||||
const getRecentBills = () => {
|
||||
const allBillList = getBillList()
|
||||
// 按时间降序排序
|
||||
const sortedList = [...allBillList].sort((a, b) => {
|
||||
const timeA = a.itemInfoList.find(info => info.key == 'createTime')?.value || 0
|
||||
const timeB = b.itemInfoList.find(info => info.key == 'createTime')?.value || 0
|
||||
return new Date(timeB) - new Date(timeA)
|
||||
})
|
||||
|
||||
// 获取前3条
|
||||
const recentBills = sortedList.filter(item => item.payMethod == '余额').slice(0, 3)
|
||||
|
||||
// 转换数据
|
||||
data.changeDetailList = recentBills.map(item => {
|
||||
const createTime = item.itemInfoList.find(info => info.key == 'createTime')?.value || new Date()
|
||||
return {
|
||||
time: dateUtil.format(createTime),
|
||||
type: item.itemInfoList.find(info => info.key == 'billCategory')?.value || '消费',
|
||||
money: parseFloat(item.money).toFixed(2),
|
||||
isAdd: item.isAdd,
|
||||
name: item.name,
|
||||
balance: item.balance,
|
||||
imgUrl: item.imgUrl,
|
||||
id: item.id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 组件挂载后再次获取,确保信息已更新
|
||||
updateStatusBarHeight()
|
||||
})
|
||||
|
||||
|
|
@ -250,9 +269,13 @@ const clickTitlePopupButton = (button) => {
|
|||
button.click()
|
||||
}
|
||||
|
||||
/**
|
||||
* 输入框确认事件
|
||||
*/
|
||||
//修改余额
|
||||
const editBalance = () => {
|
||||
data.balance = Number(data.balance).toFixed(2)
|
||||
inputDialog.value.open()
|
||||
}
|
||||
|
||||
//输入框确认事件
|
||||
const dialogInputConfirm = () => {
|
||||
if (data.balance > 999999999) {
|
||||
uni.showToast({
|
||||
|
|
@ -272,14 +295,110 @@ const dialogInputCancle = () => {
|
|||
data.balance = storage.get('balance')
|
||||
inputDialog.value.close()
|
||||
}
|
||||
|
||||
|
||||
const contextMenu = reactive({
|
||||
visible: false,
|
||||
x: 0,
|
||||
y: 0,
|
||||
item: null
|
||||
})
|
||||
|
||||
const onLongPress = ({
|
||||
event,
|
||||
item
|
||||
}) => {
|
||||
// 根据触摸事件计算位置
|
||||
let touchX = 0
|
||||
let touchY = 0
|
||||
|
||||
if (event.touches && event.touches.length > 0) {
|
||||
touchX = event.touches[0].clientX
|
||||
touchY = event.touches[0].clientY
|
||||
} else if (event.changedTouches && event.changedTouches.length > 0) {
|
||||
touchX = event.changedTouches[0].clientX
|
||||
touchY = event.changedTouches[0].clientY
|
||||
} else {
|
||||
// 如果没有触摸信息,使用默认位置
|
||||
touchX = 100
|
||||
touchY = 100
|
||||
}
|
||||
|
||||
// 边界检查确保菜单显示在屏幕内
|
||||
const screenWidth = data.windowWidth || 375
|
||||
const screenHeight = data.windowHeight || 667
|
||||
|
||||
if (touchX + 100 > screenWidth) {
|
||||
touchX = screenWidth - 110
|
||||
}
|
||||
if (touchY + 90 > screenHeight) {
|
||||
touchY = screenHeight - 100
|
||||
}
|
||||
|
||||
contextMenu.x = touchX
|
||||
contextMenu.y = touchY
|
||||
contextMenu.item = item
|
||||
contextMenu.visible = true
|
||||
|
||||
// 震动反馈
|
||||
uni.vibrateShort()
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭上下文菜单
|
||||
*/
|
||||
const closeContextMenu = () => {
|
||||
contextMenu.visible = false
|
||||
contextMenu.item = null
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改明细
|
||||
*/
|
||||
const handleEdit = () => {
|
||||
if (contextMenu.item) {
|
||||
util.goPage(`/pages/bill/add-bill/add-bill?id=${contextMenu.item.id}&type=${1}&isEdit=${true}`)
|
||||
}
|
||||
closeContextMenu()
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除明细
|
||||
*/
|
||||
const handleDelete = () => {
|
||||
const itemToDelete = contextMenu.item
|
||||
if (itemToDelete) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定要删除这条账单吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
console.log('Deleting item:', itemToDelete)
|
||||
const success = deleteBill(itemToDelete.id)
|
||||
if (success) {
|
||||
uni.showToast({
|
||||
title: '删除成功',
|
||||
icon: 'success'
|
||||
})
|
||||
getRecentBills()
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '删除失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
closeContextMenu()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style lang="less" scoped>
|
||||
/* 直接在页面导入公共样式 */
|
||||
@import '../../common/main.css';
|
||||
</style>
|
||||
@import '/common/main.css';
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
background-color: #F0F3F8;
|
||||
overflow: hidden;
|
||||
|
|
@ -451,9 +570,22 @@ const dialogInputCancle = () => {
|
|||
margin-top: 8px;
|
||||
border-radius: 12px;
|
||||
background-color: #FFFFFF;
|
||||
padding: 20px;
|
||||
padding: 20px 0;
|
||||
margin-left: 12px;
|
||||
margin-right: 12px;
|
||||
overflow: hidden;
|
||||
overflow-x: scroll;
|
||||
|
||||
.menu-icon-box {
|
||||
width: 20%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.item {
|
||||
|
|
@ -526,4 +658,46 @@ const dialogInputCancle = () => {
|
|||
color: var(--footer-text-color);
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
/* Context Menu Styles */
|
||||
.context-menu-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 999;
|
||||
/* transparent mask to catch clicks */
|
||||
}
|
||||
|
||||
.context-menu {
|
||||
position: fixed;
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
padding: 4px 0;
|
||||
min-width: 100px;
|
||||
z-index: 1000;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
padding: 10px 16px;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
border-bottom: 0.5px solid rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.menu-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.menu-item:active {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.menu-item.delete {
|
||||
color: #ff3b30;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,730 @@
|
|||
<template>
|
||||
<view style="overflow: hidden;overflow-y: scroll; height: 100vh;">
|
||||
<navBar :title="data.navBar.title" :bgColor="data.navBar.bgColor" :buttonGroup="data.navBar.buttonGroup"
|
||||
@button-click="util.clickTitlePopupButton"></navBar>
|
||||
<!-- 账单信息容器 -->
|
||||
<view class=" add-bill-container">
|
||||
<!-- 头像 -->
|
||||
<view class="avatar-box">
|
||||
<image class="avatar-image" :src="billData.imgUrl || defaultImage" @click="changeAvatar"></image>
|
||||
</view>
|
||||
<!-- 主要信息 -->
|
||||
<view class="main-info flex-align-center flex-column">
|
||||
<!-- 名称 -->
|
||||
<view class="name info-item-input">
|
||||
<!-- 隐藏的text用于测量宽度 -->
|
||||
<text class="text-measure">{{ billData.name }}</text>
|
||||
</view>
|
||||
<!-- 金额 -->
|
||||
<view class="money-box flex-align-center">
|
||||
<view class="add money alipay-font">{{ billData.isAdd ? '+' : '-' }}</view>
|
||||
<!-- 金额 -->
|
||||
<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>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 订单状态 -->
|
||||
<view class="order-status-info" :class="{ isRefund: billData.merchantOption.refund }">
|
||||
{{ billData.orderStatus }}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 详情信息列表 -->
|
||||
<view class="detail-info-container">
|
||||
<template v-for="item in billData.itemInfoList" :key="item.id">
|
||||
<view class="info-item-box" :class="{ 'bottom-border': item.key == 'relatedRecord' }"
|
||||
v-if="item.key != 'paymentReward' || (item.key == 'paymentReward' && billData.merchantOption.payReward)">
|
||||
<view class="item-label">
|
||||
{{ item.label }}
|
||||
</view>
|
||||
<view v-if="item.type != 'link' && item.key != 'paymentReward'" class="info-item-input">
|
||||
<!-- 隐藏的text用于测量宽度 -->
|
||||
<text class="text-measure">{{ item.value }}</text>
|
||||
</view>
|
||||
<view v-if="item.key == 'paymentReward'" class="payment-reward-box">
|
||||
<view class="payment-reward flex-align-center">
|
||||
<image class="payment-reward-image"
|
||||
src="/static/image/bill/add-bill/payment-reward.png"></image>
|
||||
<text>立即领取{{ item.value }}积分</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="item.type == 'link'" class="info-item-link">
|
||||
<view class="img-box">
|
||||
<image class="img w100 h100" :src="item.value.imgUrl || defaultImage"></image>
|
||||
</view>
|
||||
<view class="textarea-box flex-1">
|
||||
{{ item.value.text }}
|
||||
</view>
|
||||
<view class="quantity">
|
||||
{{ item.value.quantity }}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 服务详情 -->
|
||||
<view v-if="billData.merchantOption.serviceDetail || billData.selectId == 8">
|
||||
<view class="info-item-box">
|
||||
<view class="item-label">
|
||||
服务详情
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-item-box w100">
|
||||
<view v-if="billData.merchantOption.serviceDetail"
|
||||
class="service-detail-box w100 flex-align-center flex-between">
|
||||
<view class="info flex-align-center">
|
||||
<image class="service-detail-image"
|
||||
:src="billData.merchantOption.serviceDetailInfo.imgUrl">
|
||||
</image>
|
||||
<text class="text">{{ billData.merchantOption.serviceDetailInfo.text }}</text>
|
||||
</view>
|
||||
<view class="right-box flex-align-center">
|
||||
<text class="text-right">{{
|
||||
getServiceDetailRightText(billData.merchantOption.serviceDetailInfo.rightText
|
||||
) }}</text>
|
||||
<image class="icon" src="/static/image/common/right-grey.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 商家码收款服务详情 -->
|
||||
<view v-if="billData.selectId == 8"
|
||||
class="service-detail-box select-id-8 w100 flex-align-center">
|
||||
<image class="alipay-merchant-img"
|
||||
src="/static/image/bill/bill-detail/alipay-merchant-img.png"></image>
|
||||
<view class="center-box flex-1">
|
||||
<view class="title">支付宝商家服务-收款记录</view>
|
||||
<view class="flex-align-center">
|
||||
<text class="text-option-item">收款明细</text>
|
||||
<view class="line"></view>
|
||||
<text class="text-option-item">顾客画像</text>
|
||||
<view class="line"></view>
|
||||
<text class="text-option-item">有奖励</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="right-btn">查看详情</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 推荐服务 -->
|
||||
<view v-if="billData.merchantOption.recommendService">
|
||||
<view class="info-item-box">
|
||||
<view class="item-label">
|
||||
推荐服务
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-item-box w100">
|
||||
<view class="service-detail-box recommend-service-box w100 flex-align-center flex-between">
|
||||
<view class="info flex-align-center">
|
||||
<text class="text">{{ billData.merchantOption.recommendServiceInfo.text }}</text>
|
||||
</view>
|
||||
<view class="right-box flex-align-center">
|
||||
<text class="text-right">去看看</text>
|
||||
<image class="icon" src="/static/image/common/right-blue.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 服务推荐 -->
|
||||
<view v-if="billData.merchantOption.serviceRecommend">
|
||||
<view class="info-item-box">
|
||||
<view class="item-label">
|
||||
服务推荐
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-item-box w100">
|
||||
<view class="service-detail-box service-recommend-box w100 flex-align-center flex-between">
|
||||
<text class="text">{{ billData.merchantOption.serviceRecommendInfo.text }}</text>
|
||||
<image class="icon" src="/static/image/common/right-blue.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
<view class="more-box">
|
||||
<text>更多</text>
|
||||
<image class="icon" src="/static/image/common/down-grey.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bill-management">
|
||||
<view class="title">账单管理</view>
|
||||
<view class="top-box" style="background-color: #FBF8F1;">
|
||||
<text style="font-size: 24rpx;color: #B7971B;">本笔登上月收入榜,看看分析吧</text>
|
||||
<uni-icons type="right" size="10" color="#B7971B"></uni-icons>
|
||||
</view>
|
||||
<view class="bill-classification bill-management-item">
|
||||
<text class="label">账单分类</text>
|
||||
<view class="right-box flex-align-center">
|
||||
<text>{{ billData.merchantOption.billClassify }}</text>
|
||||
<uni-icons style="margin-left: 8rpx;" type="right" size="12" color="#969696"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bill-management-item">
|
||||
<text v-if="billData.merchantOption.note.text || billData.merchantOption.note.isImage"
|
||||
class="label">标签</text>
|
||||
<text v-else class="label">标签和备注</text>
|
||||
<view class="tag-box right-box flex-1 flex-align-center">
|
||||
<text v-if="billData.merchantOption.tag.length == 0 || !billData.merchantOption.tag">添加</text>
|
||||
<view v-else v-for="(tag, index) in billData.merchantOption.tag.slice(0, 3)" :key="tag"
|
||||
class="tag-item">
|
||||
<text>{{ index === 2 ? (tag.substring(0, 1) + (tag.length > 1 ? '...' : '')) :
|
||||
tag }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="right-box flex-align-center">
|
||||
<uni-icons style="margin-left: 8rpx;" type="right" size="12" color="#969696"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bill-management-item"
|
||||
v-if="billData.merchantOption.note.text || billData.merchantOption.note.isImage">
|
||||
<text class="label">备注</text>
|
||||
<view class="tag-box right-box flex-1 flex-align-center">
|
||||
<view class="remark-box flex-align-center text-align-right flex-1">
|
||||
<image v-if="billData.merchantOption.note.isImage" class="remark-img"
|
||||
src="/static/image/bill/bill-detail/bill-remark-img.png">
|
||||
</image>
|
||||
<view class="text">
|
||||
{{ billData.merchantOption.note.text }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="right-box flex-align-center">
|
||||
<uni-icons style="margin-left: 8rpx;" type="right" size="12" color="#969696"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bill-management-item" style="margin-top: 32rpx;">
|
||||
<text class="label">计入收支</text>
|
||||
<view class="right-box flex-align-center" style="transform:scale(0.6); width: 100rpx;">
|
||||
<switch color="#1676FE" :checked="billData.merchantOption.countInAndOut" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="bottom-icon-box">
|
||||
<view class="line"></view>
|
||||
<view class="icon-list flex flex-wrap">
|
||||
<template v-for="(item, index) in billBottomIconList" :key="index">
|
||||
<view v-if="billData.bottomIcons.includes(item.id)" class="icon-item flex-align-center">
|
||||
<image class="bottom-icon" :src="`/static/image/bill/blue-icon/${item.icon}.png`"></image>
|
||||
<text>{{ item.name }}</text>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import navBar from '@/components/nav-bar/nav-bar.vue'
|
||||
import {
|
||||
billBottomIconList
|
||||
} from '@/static/json/add-bill.json'
|
||||
import {
|
||||
util
|
||||
} from '@/utils/common.js'
|
||||
|
||||
import {
|
||||
reactive,
|
||||
toRefs,
|
||||
ref,
|
||||
nextTick
|
||||
} from 'vue'
|
||||
import {
|
||||
onLoad,
|
||||
onShow,
|
||||
} from '@dcloudio/uni-app'
|
||||
import {
|
||||
useStore
|
||||
} from '@/store/index.js'
|
||||
|
||||
|
||||
const {
|
||||
getBillList,
|
||||
updateBill
|
||||
} = useStore()
|
||||
|
||||
const buttonGroup = [{
|
||||
name: "编辑账单",
|
||||
click: () => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/bill/add-bill/add-bill?id=${billData.value.id}&isEdit=${true}`
|
||||
})
|
||||
}
|
||||
}]
|
||||
|
||||
const defaultImage = "/static/image/bill/add-bill/add-avatar.png"
|
||||
const data = reactive({
|
||||
navBar: {
|
||||
title: '账单详情',
|
||||
bgColor: '#F5F5F5',
|
||||
buttonGroup: buttonGroup
|
||||
},
|
||||
billId: "",
|
||||
// 账单数据
|
||||
billData: {
|
||||
id: "",
|
||||
selectId: -1,
|
||||
imgUrl: "",
|
||||
name: '',
|
||||
isAdd: false,
|
||||
money: "",
|
||||
balance: 0,
|
||||
payMethod: "",
|
||||
orderStatus: '交易成功',
|
||||
itemInfoList: [],
|
||||
bottomIcons: [0, 1, 2, 3],
|
||||
merchantOption: {
|
||||
serviceDetail: false,
|
||||
serviceDetailInfo: {
|
||||
imgUrl: '',
|
||||
rightText: 0,
|
||||
text: '收钱吧'
|
||||
},
|
||||
recommendService: false,
|
||||
recommendServiceInfo: {
|
||||
text: '你有一个免费取现机会'
|
||||
},
|
||||
serviceRecommend: false,
|
||||
serviceRecommendInfo: {
|
||||
text: '恭喜你有6元转账保障福利待领取!'
|
||||
},
|
||||
refund: false,
|
||||
countInAndOut: false,
|
||||
payReward: false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let {
|
||||
billData
|
||||
} = toRefs(data)
|
||||
|
||||
onShow(() => {
|
||||
getBillData(data.billId)
|
||||
})
|
||||
|
||||
onLoad((option) => {
|
||||
console.log(option)
|
||||
if (option.id) {
|
||||
data.billId = option.id
|
||||
}
|
||||
})
|
||||
|
||||
function getBillData(id) {
|
||||
// 获取当前id账单
|
||||
const existingBill = getBillList().find(b => b.id === id)
|
||||
if (existingBill) {
|
||||
//表单赋值
|
||||
billData.value.id = existingBill.id
|
||||
billData.value.selectId = existingBill.selectId
|
||||
billData.value.name = existingBill.name
|
||||
billData.value.money = existingBill.money
|
||||
billData.value.imgUrl = existingBill.imgUrl
|
||||
billData.value.isAdd = existingBill.isAdd
|
||||
billData.value.orderStatus = existingBill.orderStatus
|
||||
billData.value.balance = existingBill.balance
|
||||
billData.value.payMethod = existingBill.payMethod
|
||||
billData.value.bottomIcons = existingBill.bottomIcons
|
||||
billData.value.merchantOption = JSON.parse(JSON.stringify(existingBill.merchantOption))
|
||||
|
||||
// 等待监听处理selectId更改,然后覆盖itemInfoList
|
||||
nextTick(() => {
|
||||
billData.value.itemInfoList = JSON.parse(JSON.stringify(existingBill.itemInfoList))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 获取服务详情右侧选项
|
||||
const getServiceDetailRightText = (value) => {
|
||||
// 服务详情右侧选项
|
||||
const serviceDetailRightTextList = [
|
||||
{
|
||||
"value": 0,
|
||||
"text": "进入小程序"
|
||||
},
|
||||
{
|
||||
"value": 1,
|
||||
"text": "查看详情"
|
||||
}
|
||||
]
|
||||
const item = serviceDetailRightTextList.find(item => item.value === Number(value))
|
||||
return item?.text || ""
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import "@/common/main.css";
|
||||
|
||||
page {
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
.add-bill-container {
|
||||
background-color: #ffffff;
|
||||
margin: 24rpx;
|
||||
margin-top: 34rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx 16rpx 16rpx 16rpx;
|
||||
|
||||
.random-dice {
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
|
||||
.random-dice-image {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.avatar-box {
|
||||
margin-top: 12rpx;
|
||||
text-align: center;
|
||||
margin-bottom: 26rpx;
|
||||
|
||||
.avatar-image {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.main-info {
|
||||
color: #1a1a1a;
|
||||
font-size: 64rpx;
|
||||
|
||||
.order-status-info {
|
||||
font-size: 28rpx;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.isRefund {
|
||||
color: #EA6B48;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-info-container {
|
||||
padding-top: 36rpx;
|
||||
|
||||
.info-item-input {
|
||||
font-size: 26rpx;
|
||||
|
||||
.text-measure {
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.text-input {
|
||||
font-size: 26rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.payment-reward-box {
|
||||
background-color: #FFEFDB;
|
||||
border-radius: 26rpx 26rpx 26rpx 26rpx;
|
||||
padding: 10rpx 16rpx;
|
||||
line-height: 32rpx;
|
||||
color: #EC670C;
|
||||
font-size: 26rpx;
|
||||
|
||||
.payment-reward-image {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.info-item-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12rpx 16rpx;
|
||||
background-color: #F6F7FB;
|
||||
border-radius: 20rpx 20rpx 20rpx 20rpx;
|
||||
|
||||
.img-box {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 8rpx;
|
||||
margin-right: 22rpx;
|
||||
background-color: #E8EDF2;
|
||||
|
||||
.img {
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.textarea-box {
|
||||
height: 40px;
|
||||
font-size: 26rpx;
|
||||
color: #1a1a1a;
|
||||
font-weight: 500;
|
||||
margin-right: 10rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.quantity {
|
||||
font-size: 22rpx;
|
||||
color: #969696;
|
||||
text-align: right;
|
||||
min-width: 100rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.service-detail-box {
|
||||
padding: 22rpx 24rpx;
|
||||
border-radius: 16rpx 16rpx 16rpx 16rpx;
|
||||
background-color: #F6F7FB;
|
||||
|
||||
.service-detail-image {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 22rpx;
|
||||
line-height: 22rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
font-size: 22rpx;
|
||||
color: #969696;
|
||||
line-height: 22rpx;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.select-id-8 {
|
||||
padding: 24rpx 16rpx;
|
||||
|
||||
.alipay-merchant-img {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
margin-right: 30rpx;
|
||||
}
|
||||
|
||||
.center-box {
|
||||
.title {
|
||||
font-size: 26rpx;
|
||||
line-height: 32rpx;
|
||||
color: #1A1A1A;
|
||||
font-weight: 500;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.line {
|
||||
width: 1rpx;
|
||||
background-color: #969696;
|
||||
margin: 0 10rpx;
|
||||
height: 18rpx;
|
||||
}
|
||||
|
||||
.text-option-item {
|
||||
font-size: 22rpx;
|
||||
color: #969696;
|
||||
}
|
||||
}
|
||||
|
||||
.right-btn {
|
||||
border-radius: 25rpx;
|
||||
border: 1rpx solid #043E77;
|
||||
color: #043E77;
|
||||
font-size: 22rpx;
|
||||
padding: 10rpx 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.recommend-service-box {
|
||||
padding: 22rpx 16rpx;
|
||||
background-color: #FFF5F6;
|
||||
|
||||
.text {
|
||||
font-size: 26rpx;
|
||||
line-height: 32rpx;
|
||||
color: #9E2036;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
font-size: 24rpx;
|
||||
line-height: 32rpx;
|
||||
color: #9E2036;
|
||||
}
|
||||
}
|
||||
|
||||
.service-recommend-box {
|
||||
background-color: #F6F7FB;
|
||||
font-weight: 500;
|
||||
|
||||
.text {
|
||||
color: #123D72;
|
||||
font-size: 26rpx;
|
||||
line-height: 32rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info-item-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 20rpx 0;
|
||||
|
||||
.item-label {
|
||||
min-width: 160rpx;
|
||||
margin-right: 40rpx;
|
||||
font-size: 26rpx;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-border {
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 0.5px solid #EDEDED;
|
||||
}
|
||||
|
||||
.info-item-input {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
min-width: 20px;
|
||||
max-width: 100%;
|
||||
width: auto;
|
||||
overflow: hidden;
|
||||
min-height: 20px;
|
||||
|
||||
/* 隐藏的测量元素 */
|
||||
.text-measure {
|
||||
white-space: nowrap;
|
||||
color: var(--text-color);
|
||||
font-family: inherit;
|
||||
font-size: 28rpx;
|
||||
width: auto;
|
||||
min-width: 20px;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.more-box {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 26rpx;
|
||||
color: #969696;
|
||||
|
||||
.icon {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
margin: 28rpx 0;
|
||||
}
|
||||
|
||||
.bill-management {
|
||||
margin: 16rpx 24rpx;
|
||||
background-color: #ffffff;
|
||||
padding: 24rpx;
|
||||
border-radius: 24rpx;
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.bill-management-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 40rpx;
|
||||
font-size: 26rpx;
|
||||
color: #1a1a1a;
|
||||
|
||||
.tag-box {
|
||||
justify-content: flex-end;
|
||||
|
||||
.tag-item {
|
||||
background-color: #E6F2FF;
|
||||
color: #2788D1;
|
||||
font-size: 24rpx;
|
||||
padding: 0 16rpx;
|
||||
border-radius: 4rpx;
|
||||
height: 52rpx;
|
||||
line-height: 52rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.remark-box {
|
||||
justify-content: flex-end;
|
||||
color: #969696;
|
||||
font-size: 26rpx;
|
||||
|
||||
.text {
|
||||
max-width: 280rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.remark-img {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.right-box {
|
||||
color: #969696;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-icon-box {
|
||||
margin-top: 8rpx;
|
||||
|
||||
.icon-item {
|
||||
margin-top: 36rpx;
|
||||
width: 50%;
|
||||
font-size: 26rpx;
|
||||
color: #12447A;
|
||||
margin-bottom: 14rpx;
|
||||
}
|
||||
|
||||
.bottom-icon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
background-color: #EDEDED;
|
||||
transform: scaleY(0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.top-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-radius: 16rpx;
|
||||
padding: 22rpx 24rpx;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -88,12 +88,20 @@
|
|||
</view>
|
||||
</view>
|
||||
<view class="bill-list">
|
||||
<BalanceList :isBalance="false" :list="item.list" />
|
||||
<BalanceList :isBalance="false" :list="item.list" @longPress="onLongPress" @onBill="billClick" />
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
</view>
|
||||
|
||||
<!-- Custom Context Menu -->
|
||||
<view class="context-menu-mask" v-if="contextMenu.visible" @click="closeContextMenu" @touchmove.stop.prevent></view>
|
||||
<view class="context-menu" v-if="contextMenu.visible"
|
||||
:style="{ top: contextMenu.y + 'px', left: contextMenu.x + 'px' }">
|
||||
<view class="menu-item border-bottom" @click="handleEdit">编辑</view>
|
||||
<view class="menu-item" @click="handleDelete">删除</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
@ -103,9 +111,13 @@ import BalanceList from '@/components/balance-list/balance-list.vue'
|
|||
import {
|
||||
reactive,
|
||||
toRefs,
|
||||
onMounted,
|
||||
ref,
|
||||
onMounted
|
||||
computed
|
||||
} from 'vue'
|
||||
import {
|
||||
useStore
|
||||
} from '@/store/index.js'
|
||||
import {
|
||||
onShow,
|
||||
} from '@dcloudio/uni-app'
|
||||
|
|
@ -174,151 +186,7 @@ const data = reactive({
|
|||
outCome: 0,
|
||||
}, // 当前滚动到的月份
|
||||
cardPositions: [], // 存储每个卡片距离 scroll-view 顶部的距离
|
||||
billList: [{
|
||||
year: '2025',
|
||||
month: '12',
|
||||
inCome: 999999999.00,
|
||||
outCome: 999999999.00,
|
||||
list: [{
|
||||
orderId: '1234567890',
|
||||
imgUrl: 'https://picsum.photos/200/200?random=1',
|
||||
name: '测试',
|
||||
amount: 999999999.00,
|
||||
classification: '日荣百货',
|
||||
isRefund: false,
|
||||
isAdd: false,
|
||||
money: "200",
|
||||
time: '2025-12-27 18:18:18'
|
||||
}, {
|
||||
orderId: '1234567890',
|
||||
imgUrl: 'https://picsum.photos/200/200?random=1',
|
||||
name: '测试',
|
||||
amount: 999999999.00,
|
||||
classification: '日荣百货',
|
||||
isRefund: true,
|
||||
isAdd: false,
|
||||
money: "200",
|
||||
time: '2025-12-27 18:18:18'
|
||||
}, {
|
||||
orderId: '1234567890',
|
||||
imgUrl: 'https://picsum.photos/200/200?random=1',
|
||||
name: '测试',
|
||||
amount: 999999999.00,
|
||||
classification: '日荣百货',
|
||||
isRefund: false,
|
||||
isAdd: true,
|
||||
money: "200",
|
||||
time: '2025-12-27 18:18:18'
|
||||
}]
|
||||
}, {
|
||||
year: '2025',
|
||||
month: '11',
|
||||
inCome: 999999999.00,
|
||||
outCome: 999999999.00,
|
||||
list: [{
|
||||
orderId: '1234567890',
|
||||
imgUrl: 'https://picsum.photos/200/200?random=1',
|
||||
name: '测试',
|
||||
amount: 999999999.00,
|
||||
classification: '日荣百货',
|
||||
isRefund: false,
|
||||
isAdd: false,
|
||||
money: "200",
|
||||
time: '2025-12-27 18:18:18'
|
||||
}, {
|
||||
orderId: '1234567890',
|
||||
imgUrl: 'https://picsum.photos/200/200?random=1',
|
||||
name: '测试',
|
||||
amount: 999999999.00,
|
||||
classification: '日荣百货',
|
||||
isRefund: true,
|
||||
isAdd: false,
|
||||
money: "200",
|
||||
time: '2025-12-27 18:18:18'
|
||||
}, {
|
||||
orderId: '1234567890',
|
||||
imgUrl: 'https://picsum.photos/200/200?random=1',
|
||||
name: '测试',
|
||||
amount: 999999999.00,
|
||||
classification: '日荣百货',
|
||||
isRefund: false,
|
||||
isAdd: true,
|
||||
money: "200",
|
||||
time: '2025-12-27 18:18:18'
|
||||
}]
|
||||
}, {
|
||||
year: '2025',
|
||||
month: '10',
|
||||
inCome: 999999999.00,
|
||||
outCome: 999999999.00,
|
||||
list: [{
|
||||
orderId: '1234567890',
|
||||
imgUrl: 'https://picsum.photos/200/200?random=1',
|
||||
name: '测试',
|
||||
amount: 999999999.00,
|
||||
classification: '日荣百货',
|
||||
isRefund: false,
|
||||
isAdd: false,
|
||||
money: "200",
|
||||
time: '2025-12-27 18:18:18'
|
||||
}, {
|
||||
orderId: '1234567890',
|
||||
imgUrl: 'https://picsum.photos/200/200?random=1',
|
||||
name: '测试',
|
||||
amount: 999999999.00,
|
||||
classification: '日荣百货',
|
||||
isRefund: true,
|
||||
isAdd: false,
|
||||
money: "200",
|
||||
time: '2025-12-27 18:18:18'
|
||||
}, {
|
||||
orderId: '1234567890',
|
||||
imgUrl: 'https://picsum.photos/200/200?random=1',
|
||||
name: '测试',
|
||||
amount: 999999999.00,
|
||||
classification: '日荣百货',
|
||||
isRefund: false,
|
||||
isAdd: true,
|
||||
money: "200",
|
||||
time: '2025-12-27 18:18:18'
|
||||
}]
|
||||
}, {
|
||||
year: '2025',
|
||||
month: '9',
|
||||
inCome: 999999999.00,
|
||||
outCome: 999999999.00,
|
||||
list: [{
|
||||
orderId: '1234567890',
|
||||
imgUrl: 'https://picsum.photos/200/200?random=1',
|
||||
name: '测试',
|
||||
amount: 999999999.00,
|
||||
classification: '日荣百货',
|
||||
isRefund: false,
|
||||
isAdd: false,
|
||||
money: "200",
|
||||
time: '2025-12-27 18:18:18'
|
||||
}, {
|
||||
orderId: '1234567890',
|
||||
imgUrl: 'https://picsum.photos/200/200?random=1',
|
||||
name: '测试',
|
||||
amount: 999999999.00,
|
||||
classification: '日荣百货',
|
||||
isRefund: true,
|
||||
isAdd: false,
|
||||
money: "200",
|
||||
time: '2025-12-27 18:18:18'
|
||||
}, {
|
||||
orderId: '1234567890',
|
||||
imgUrl: 'https://picsum.photos/200/200?random=1',
|
||||
name: '测试',
|
||||
amount: 999999999.00,
|
||||
classification: '日荣百货',
|
||||
isRefund: false,
|
||||
isAdd: true,
|
||||
money: "200",
|
||||
time: '2025-12-27 18:18:18'
|
||||
}]
|
||||
}]
|
||||
billList: []
|
||||
})
|
||||
|
||||
let {
|
||||
|
|
@ -327,11 +195,101 @@ let {
|
|||
currentFilterType
|
||||
} = toRefs(data)
|
||||
|
||||
const {
|
||||
getBillList,
|
||||
deleteBill
|
||||
} = useStore()
|
||||
|
||||
const contextMenu = reactive({
|
||||
visible: false,
|
||||
x: 0,
|
||||
y: 0,
|
||||
item: null
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
// 获取最新账单列表
|
||||
getBillDataList()
|
||||
// Close menu if open
|
||||
closeContextMenu()
|
||||
// 初始获取状态栏高度和屏幕高度
|
||||
updateStatusBarHeight()
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取账单列表
|
||||
*/
|
||||
const getBillDataList = () => {
|
||||
const allBillList = getBillList()
|
||||
// 按月份分组
|
||||
const groupList = []
|
||||
allBillList.forEach(item => {
|
||||
// 查找itemInfoList中的createTime
|
||||
const createTimeItem = item.itemInfoList.find(info => info.key == 'createTime')
|
||||
const createTime = createTimeItem ? createTimeItem.value : new Date()
|
||||
|
||||
const date = new Date(createTime)
|
||||
const year = date.getFullYear() + ''
|
||||
const month = (date.getMonth() + 1) + ''
|
||||
|
||||
// 查找该月份是否已存在
|
||||
let monthGroup = groupList.find(g => g.year == year && g.month == month)
|
||||
if (!monthGroup) {
|
||||
monthGroup = {
|
||||
year,
|
||||
month,
|
||||
inCome: 0,
|
||||
outCome: 0,
|
||||
list: []
|
||||
}
|
||||
groupList.push(monthGroup)
|
||||
}
|
||||
|
||||
// 处理单个账单数据格式
|
||||
const billItem = {
|
||||
id: item.id,
|
||||
orderId: item.itemInfoList.find(info => info.key == 'orderNumber')?.value || '',
|
||||
imgUrl: item.imgUrl,
|
||||
name: item.name,
|
||||
amount: item.money,
|
||||
classification: item.merchantOption.billClassify || '',
|
||||
isRefund: item.merchantOption.refund,
|
||||
isAdd: item.isAdd,
|
||||
money: item.money,
|
||||
time: createTime
|
||||
}
|
||||
|
||||
monthGroup.list.push(billItem)
|
||||
|
||||
// 计算收支
|
||||
const money = parseFloat(item.money || 0)
|
||||
if (item.isAdd) {
|
||||
monthGroup.inCome += money
|
||||
} else {
|
||||
if (item.orderStatus.includes('退款')) {
|
||||
// 退款算收入还是支出减少?通常退款在列表显示为绿色(收入),这里简单处理为收入
|
||||
// 如果是支出类型的单子的退款,实际上是钱回流
|
||||
monthGroup.inCome += money
|
||||
} else {
|
||||
monthGroup.outCome += money
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 排序:年份倒序,月份倒序
|
||||
groupList.sort((a, b) => {
|
||||
if (a.year != b.year) return b.year - a.year
|
||||
return b.month - a.month
|
||||
})
|
||||
|
||||
//每个月内的账单按时间倒序
|
||||
groupList.forEach(group => {
|
||||
group.list.sort((a, b) => new Date(b.time) - new Date(a.time))
|
||||
})
|
||||
|
||||
data.billList = groupList
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 在组件挂载后获取卡片位置
|
||||
getCardPositions()
|
||||
|
|
@ -347,6 +305,12 @@ const updateStatusBarHeight = () => {
|
|||
})
|
||||
}
|
||||
|
||||
const billClick = (item) => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/bill/bill-detail/bill-detail?id=' + item.id
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有卡片相对于 scroll-view 顶部的距离
|
||||
*/
|
||||
|
|
@ -415,6 +379,71 @@ const scrollList = (e) => {
|
|||
const clickTitlePopupButton = (button) => {
|
||||
button.click()
|
||||
}
|
||||
|
||||
/**
|
||||
* 长按编辑/删除 - Custom Menu
|
||||
*/
|
||||
const onLongPress = ({ event, item }) => {
|
||||
console.log('Long press', event)
|
||||
// Calculate position
|
||||
// Use clientX/Y from touches if available
|
||||
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.detail && event.detail.x) {
|
||||
x = event.detail.x
|
||||
y = event.detail.y
|
||||
}
|
||||
|
||||
// Adjust position to not go off screen (simple heuristic)
|
||||
const screenWidth = uni.getSystemInfoSync().windowWidth
|
||||
const screenHeight = uni.getSystemInfoSync().windowHeight
|
||||
|
||||
if (x + 100 > screenWidth) x = screenWidth - 110
|
||||
if (y + 100 > screenHeight) y = y - 100 // show above if too low
|
||||
|
||||
contextMenu.x = x
|
||||
contextMenu.y = y
|
||||
contextMenu.item = item
|
||||
contextMenu.visible = true
|
||||
}
|
||||
|
||||
const closeContextMenu = () => {
|
||||
contextMenu.visible = false
|
||||
contextMenu.item = null
|
||||
}
|
||||
|
||||
const handleEdit = () => {
|
||||
if (contextMenu.item) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/bill/add-bill/add-bill?id=${contextMenu.item.id}&isEdit=${true}`
|
||||
})
|
||||
}
|
||||
closeContextMenu()
|
||||
}
|
||||
|
||||
const handleDelete = () => {
|
||||
if (contextMenu.item) {
|
||||
const id = contextMenu.item.id
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定要删除该账单吗?',
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
deleteBill(id)
|
||||
getBillDataList()
|
||||
uni.showToast({
|
||||
title: '删除成功',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
closeContextMenu()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
|
@ -424,6 +453,39 @@ page {
|
|||
background-color: #F5F5F5;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.context-menu-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 998;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.context-menu {
|
||||
position: fixed;
|
||||
z-index: 999;
|
||||
background-color: #4c4c4c;
|
||||
border-radius: 4px;
|
||||
padding: 0;
|
||||
min-width: 80px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
padding: 10px 15px;
|
||||
font-size: 14px;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.border-bottom {
|
||||
border-bottom: 1rpx solid #5d5d5d;
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
.nav-bar-search {
|
||||
background-color: #ffffff;
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 788 B |
|
Before Width: | Height: | Size: 881 B After Width: | Height: | Size: 788 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 1009 B |
|
After Width: | Height: | Size: 287 B |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 286 B |
|
|
@ -32,6 +32,14 @@
|
|||
"key": "productDescription",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "支付奖励",
|
||||
"value": 10,
|
||||
"type": "number",
|
||||
"focus": false,
|
||||
"key": "paymentReward",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "收单机构",
|
||||
"value": "支付宝支付科技有限公司",
|
||||
|
|
@ -47,22 +55,6 @@
|
|||
"focus": false,
|
||||
"key": "receiverFullName",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "账单分类",
|
||||
"value": "日用百货",
|
||||
"type": "select",
|
||||
"focus": false,
|
||||
"key": "billCategory",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "标签和备注",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "tagAndNote",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"defaultBottomIcons": [
|
||||
|
|
@ -96,6 +88,14 @@
|
|||
"key": "payMethod",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "支付奖励",
|
||||
"value": 10,
|
||||
"type": "number",
|
||||
"focus": false,
|
||||
"key": "paymentReward",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "商品说明",
|
||||
"value": "",
|
||||
|
|
@ -111,22 +111,6 @@
|
|||
"focus": false,
|
||||
"key": "receiverFullName",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "账单分类",
|
||||
"value": "日用百货",
|
||||
"type": "select",
|
||||
"focus": false,
|
||||
"key": "billCategory",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "标签和备注",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "tagAndNote",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"defaultBottomIcons": [
|
||||
|
|
@ -169,6 +153,14 @@
|
|||
"key": "productDescription",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "支付奖励",
|
||||
"value": 10,
|
||||
"type": "number",
|
||||
"focus": false,
|
||||
"key": "paymentReward",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "收单机构",
|
||||
"value": "支付宝支付科技有限公司",
|
||||
|
|
@ -184,22 +176,6 @@
|
|||
"focus": false,
|
||||
"key": "clearingOrganization",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "账单分类",
|
||||
"value": "餐饮美食",
|
||||
"type": "select",
|
||||
"focus": false,
|
||||
"key": "billCategory",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "标签和备注",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "tagAndNote",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"defaultBottomIcons": [
|
||||
|
|
@ -241,20 +217,12 @@
|
|||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "账单分类",
|
||||
"value": "信用借还",
|
||||
"type": "select",
|
||||
"label": "支付奖励",
|
||||
"value": 10,
|
||||
"type": "number",
|
||||
"focus": false,
|
||||
"key": "billCategory",
|
||||
"key": "paymentReward",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "标签和备注",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "tagAndNote",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"defaultBottomIcons": [
|
||||
|
|
@ -279,7 +247,7 @@
|
|||
},
|
||||
{
|
||||
"label": "转账备注",
|
||||
"value": "",
|
||||
"value": "报销",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "transferNote",
|
||||
|
|
@ -300,22 +268,6 @@
|
|||
"focus": false,
|
||||
"key": "orderNumber",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "账单分类",
|
||||
"value": "转账红包",
|
||||
"type": "select",
|
||||
"focus": false,
|
||||
"key": "billCategory",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "标签和备注",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "tagAndNote",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"defaultBottomIcons": [
|
||||
|
|
@ -342,7 +294,7 @@
|
|||
},
|
||||
{
|
||||
"label": "转账备注",
|
||||
"value": "",
|
||||
"value": "转账",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "transferNote",
|
||||
|
|
@ -355,22 +307,6 @@
|
|||
"focus": false,
|
||||
"key": "counterAccount",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "账单分类",
|
||||
"value": "转账红包",
|
||||
"type": "select",
|
||||
"focus": false,
|
||||
"key": "billCategory",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "标签和备注",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "tagAndNote",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"defaultBottomIcons": [
|
||||
|
|
@ -411,22 +347,6 @@
|
|||
"focus": false,
|
||||
"key": "counterAccount",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "账单分类",
|
||||
"value": "转账红包",
|
||||
"type": "select",
|
||||
"focus": false,
|
||||
"key": "billCategory",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "标签和备注",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "tagAndNote",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"defaultBottomIcons": [
|
||||
|
|
@ -469,22 +389,6 @@
|
|||
"focus": false,
|
||||
"key": "productDescription",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "账单分类",
|
||||
"value": "收入",
|
||||
"type": "select",
|
||||
"focus": false,
|
||||
"key": "billCategory",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "标签和备注",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "tagAndNote",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"defaultBottomIcons": [
|
||||
|
|
@ -525,7 +429,7 @@
|
|||
"value": "",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "refundMethod",
|
||||
"key": "payMethod",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
|
|
@ -535,22 +439,6 @@
|
|||
"focus": false,
|
||||
"key": "productDescription",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "账单分类",
|
||||
"value": "退款",
|
||||
"type": "select",
|
||||
"focus": false,
|
||||
"key": "billCategory",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "标签和备注",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "tagAndNote",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"defaultBottomIcons": [
|
||||
|
|
@ -599,22 +487,6 @@
|
|||
"focus": false,
|
||||
"key": "receiverFullName",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "账单分类",
|
||||
"value": "充值缴费",
|
||||
"type": "select",
|
||||
"focus": false,
|
||||
"key": "billCategory",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "标签和备注",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "tagAndNote",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"defaultBottomIcons": [
|
||||
|
|
@ -673,22 +545,6 @@
|
|||
"focus": false,
|
||||
"key": "orderNumber",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "账单分类",
|
||||
"value": "充值缴费",
|
||||
"type": "select",
|
||||
"focus": false,
|
||||
"key": "billCategory",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "标签和备注",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "tagAndNote",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"defaultBottomIcons": [
|
||||
|
|
@ -729,22 +585,6 @@
|
|||
"key": "payMethod",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "账单分类",
|
||||
"value": "日用百货",
|
||||
"type": "select",
|
||||
"focus": false,
|
||||
"key": "billCategory",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "标签和备注",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "tagAndNote",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"label": "交易详情",
|
||||
"value": {
|
||||
|
|
@ -797,6 +637,14 @@
|
|||
"key": "productDescription",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "支付奖励",
|
||||
"value": 10,
|
||||
"type": "number",
|
||||
"focus": false,
|
||||
"key": "paymentReward",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "收款方全称",
|
||||
"value": "",
|
||||
|
|
@ -804,22 +652,6 @@
|
|||
"focus": false,
|
||||
"key": "receiverFullName",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "账单分类",
|
||||
"value": "日用百货",
|
||||
"type": "select",
|
||||
"focus": false,
|
||||
"key": "billCategory",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "标签和备注",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"focus": false,
|
||||
"key": "tagAndNote",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"defaultBottomIcons": [
|
||||
|
|
@ -959,11 +791,33 @@
|
|||
}
|
||||
],
|
||||
"billBottomIconList": [
|
||||
{
|
||||
"id": 4,
|
||||
"icon": "lianxishoukuanfang",
|
||||
"name": "联系收款方",
|
||||
"hideIncloudId": 8
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"icon": "lianxishangjia",
|
||||
"name": "联系商家",
|
||||
"hideIncloudId": 4
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"icon": "chakanjiaofeijindu",
|
||||
"name": "查看缴费进度"
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"icon": "chakanwanglaijilu",
|
||||
"name": "查看往来记录"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"icon": "AAshoukuan",
|
||||
"name": "AA收款"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"icon": "wanglailiushuizhengming",
|
||||
|
|
@ -974,40 +828,20 @@
|
|||
"icon": "shenqingdianzihuidan",
|
||||
"name": "申请电子回单"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"icon": "duidingdanyouyiwen",
|
||||
"name": "对订单有疑问"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"icon": "chakanjiaofeijindu",
|
||||
"name": "查看缴费进度"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"icon": "lianxishoukuanfang",
|
||||
"name": "联系收款方"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"icon": "lianxifukuanfang",
|
||||
"name": "联系付款方"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"icon": "duidingdanyouyiwen",
|
||||
"name": "对订单有疑问"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"icon": "zhuanzhangpingzheng",
|
||||
"name": "转账凭证"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"icon": "lianxishangjia",
|
||||
"name": "联系商家"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"icon": "AAshoukuan",
|
||||
"name": "AA收款"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
{
|
||||
"fastEntranceList": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "转账",
|
||||
"label": "zhuanzhang"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "银行卡",
|
||||
"label": "yinhangka"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "亲情卡",
|
||||
"label": "qinqingka"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "搭搭哒",
|
||||
"label": "dadada"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "小荷包",
|
||||
"label": "xiaohebao"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "专用金",
|
||||
"label": "zhuanyongjin"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "定时充值",
|
||||
"label": "dingshichongzhi"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "红包",
|
||||
"label": "hongbao"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "零花钱",
|
||||
"label": "linghuaqian"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "免费额度",
|
||||
"label": "mianfeiedu"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"name": "专用资金",
|
||||
"label": "zhuanyongzijin"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "备用余额",
|
||||
"label": "beiyongyue"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"name": "信用卡还款",
|
||||
"label": "xinyongkahuankuan"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -22,12 +22,8 @@ export const store = reactive({
|
|||
windowWidth: 0
|
||||
},
|
||||
|
||||
// 示例数据:待办事项
|
||||
todos: storage.get('todos') || [],
|
||||
|
||||
// 示例数据:商品列表
|
||||
products: storage.get('products') || [],
|
||||
|
||||
// 账单列表
|
||||
billList: storage.get('bill_list') || [],
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -47,66 +43,33 @@ export const useStore = () => {
|
|||
store.settings = { ...store.settings, ...settings };
|
||||
};
|
||||
|
||||
// 待办事项相关操作
|
||||
const addTodo = (todo) => {
|
||||
const newTodo = {
|
||||
id: Date.now(),
|
||||
...todo,
|
||||
completed: false,
|
||||
createdAt: new Date().toISOString()
|
||||
};
|
||||
store.todos.push(newTodo);
|
||||
return newTodo;
|
||||
// 账单相关操作
|
||||
const addBill = (bill) => {
|
||||
store.billList.unshift(bill);
|
||||
return bill;
|
||||
};
|
||||
|
||||
const updateTodo = (id, updates) => {
|
||||
const index = store.todos.findIndex(todo => todo.id === id);
|
||||
const updateBill = (id, updates) => {
|
||||
const index = store.billList.findIndex(bill => bill.id === id);
|
||||
if (index !== -1) {
|
||||
store.todos[index] = { ...store.todos[index], ...updates };
|
||||
return store.todos[index];
|
||||
store.billList[index] = { ...store.billList[index], ...updates };
|
||||
return store.billList[index];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const deleteTodo = (id) => {
|
||||
const index = store.todos.findIndex(todo => todo.id === id);
|
||||
const deleteBill = (id) => {
|
||||
const index = store.billList.findIndex(bill => bill.id === id);
|
||||
if (index !== -1) {
|
||||
store.todos.splice(index, 1);
|
||||
store.billList.splice(index, 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// 商品相关操作
|
||||
const addProduct = (product) => {
|
||||
const newProduct = {
|
||||
id: Date.now(),
|
||||
...product,
|
||||
createdAt: new Date().toISOString()
|
||||
};
|
||||
store.products.push(newProduct);
|
||||
return newProduct;
|
||||
};
|
||||
|
||||
const updateProduct = (id, updates) => {
|
||||
const index = store.products.findIndex(product => product.id === id);
|
||||
if (index !== -1) {
|
||||
store.products[index] = { ...store.products[index], ...updates };
|
||||
return store.products[index];
|
||||
const getBillList = () => {
|
||||
return store.billList
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const deleteProduct = (id) => {
|
||||
const index = store.products.findIndex(product => product.id === id);
|
||||
if (index !== -1) {
|
||||
store.products.splice(index, 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 数据持久化
|
||||
// 监听store变化,自动保存到本地存储
|
||||
|
|
@ -123,19 +86,11 @@ export const useStore = () => {
|
|||
);
|
||||
|
||||
watch(
|
||||
() => store.todos,
|
||||
(newValue) => storage.set('todos', newValue),
|
||||
() => store.billList,
|
||||
(newValue) => storage.set('bill_list', newValue),
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
() => store.products,
|
||||
(newValue) => storage.set('products', newValue),
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
|
||||
|
||||
// 获取系统信息
|
||||
const getSystemInfo = () => {
|
||||
uni.getSystemInfo({
|
||||
|
|
@ -155,12 +110,10 @@ export const useStore = () => {
|
|||
setUserInfo,
|
||||
clearUserInfo,
|
||||
updateSettings,
|
||||
addTodo,
|
||||
updateTodo,
|
||||
deleteTodo,
|
||||
addProduct,
|
||||
updateProduct,
|
||||
deleteProduct,
|
||||
addBill,
|
||||
updateBill,
|
||||
deleteBill,
|
||||
getBillList,
|
||||
getSystemInfo
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -378,6 +378,15 @@ export const util = {
|
|||
uni.navigateTo({
|
||||
url
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 点击标题弹出按钮
|
||||
* @param e
|
||||
*/
|
||||
clickTitlePopupButton(button) {
|
||||
button.click()
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -52,32 +52,5 @@ export const storage = {
|
|||
console.error('清空数据失败:', error);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// 批量保存
|
||||
setMultiple(dataObj) {
|
||||
try {
|
||||
Object.keys(dataObj).forEach(key => {
|
||||
this.set(key, dataObj[key]);
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('批量存储失败:', error);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// 批量获取
|
||||
getMultiple(keys) {
|
||||
try {
|
||||
const result = {};
|
||||
keys.forEach(key => {
|
||||
result[key] = this.get(key);
|
||||
});
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('批量获取失败:', error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||