支付包第一期完成
63
App.vue
|
|
@ -10,9 +10,6 @@ export default {
|
||||||
// 1. 同步初始化配置(必须完成)
|
// 1. 同步初始化配置(必须完成)
|
||||||
this.initConfig(options)
|
this.initConfig(options)
|
||||||
|
|
||||||
// 2. 异步获取用户数据(不阻塞启动)
|
|
||||||
this.fetchUserDataAsync()
|
|
||||||
|
|
||||||
// 启动完成
|
// 启动完成
|
||||||
console.log(`App 启动耗时: ${Date.now() - startTime}ms`)
|
console.log(`App 启动耗时: ${Date.now() - startTime}ms`)
|
||||||
},
|
},
|
||||||
|
|
@ -119,66 +116,6 @@ export default {
|
||||||
// #endif
|
// #endif
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 异步获取用户数据(不阻塞启动)
|
|
||||||
*/
|
|
||||||
fetchUserDataAsync() {
|
|
||||||
// 延迟到下一个事件循环,确保不阻塞启动
|
|
||||||
setTimeout(async () => {
|
|
||||||
const fetchStart = Date.now()
|
|
||||||
try {
|
|
||||||
// 并行获取用户信息和配置
|
|
||||||
const [userResult, configResult] = await Promise.allSettled([
|
|
||||||
this.fetchUserInfo(),
|
|
||||||
this.fetchUserConfig()
|
|
||||||
])
|
|
||||||
|
|
||||||
// 处理用户信息结果
|
|
||||||
if (userResult.status === 'rejected') {
|
|
||||||
console.error('获取用户信息失败:', userResult.reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理用户配置结果
|
|
||||||
if (configResult.status === 'rejected') {
|
|
||||||
console.error('获取用户配置失败:', configResult.reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`用户数据获取耗时: ${Date.now() - fetchStart}ms`)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取用户数据异常:', error)
|
|
||||||
// 不显示错误提示,避免打断用户
|
|
||||||
}
|
|
||||||
}, 0)
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户信息
|
|
||||||
*/
|
|
||||||
async fetchUserInfo() {
|
|
||||||
const data = await get('', 'api/user', {})
|
|
||||||
if (data.code === 0) {
|
|
||||||
uni.setStorageSync('userInfo', data.data)
|
|
||||||
console.log('用户信息获取成功')
|
|
||||||
return data.data
|
|
||||||
} else {
|
|
||||||
throw new Error(data.message || '获取用户信息失败')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户配置
|
|
||||||
*/
|
|
||||||
async fetchUserConfig() {
|
|
||||||
const data = await get('', 'api/user/config', {})
|
|
||||||
if (data.code === 0) {
|
|
||||||
uni.setStorageSync('config', data.data)
|
|
||||||
console.log('用户配置获取成功')
|
|
||||||
return data.data
|
|
||||||
} else {
|
|
||||||
throw new Error(data.message || '获取用户配置失败')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,293 @@
|
||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<!-- 底部弹出层 -->
|
||||||
|
<uni-popup ref="timepopup" type="bottom">
|
||||||
|
<!-- 账单分类 -->
|
||||||
|
<view v-if="data.popupType == 'billClassify'" class="bill-classify-box">
|
||||||
|
<view class="title-box">
|
||||||
|
<view class="title">
|
||||||
|
账单分类
|
||||||
|
</view>
|
||||||
|
<view class="btn" @click="closeTimePicker">
|
||||||
|
<image class="close-image" src="/static/image/common/close.png"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="bill-classify-content">
|
||||||
|
<view class="bill-classify-item" v-for="item in billClassifyOptions" :key="item.id"
|
||||||
|
@click="data.currentClassifyName = item.name">
|
||||||
|
<view class="bill-classify-item-text"
|
||||||
|
:class="{ 'active-item': data.currentClassifyName == item.name }">
|
||||||
|
{{ item.name }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="confirm-btn" @click="confirmClassify">
|
||||||
|
确定
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 标签和备注 -->
|
||||||
|
<view v-if="data.popupType == 'tagAndNote'" class="bill-classify-box">
|
||||||
|
<view class="title-box">
|
||||||
|
<view class="title">
|
||||||
|
标签
|
||||||
|
<text class="text">(最多10个标签)</text>
|
||||||
|
</view>
|
||||||
|
<view class="btn" @click="closeTimePicker">
|
||||||
|
<image class="close-image" src="/static/image/common/close.png"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="bill-classify-content tag-content flex-wrap">
|
||||||
|
<view class="tag-item" v-for="(tag, index) in data.tempTags" :key="index">
|
||||||
|
<text>{{ tag }}</text>
|
||||||
|
<view class="delete-tag" @click="deleteTag(index)">
|
||||||
|
<image src="/static/image/common/close.png" mode="widthFix" class="close-icon-img">
|
||||||
|
</image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="add-tag-box" v-if="!data.showTagInput && data.tempTags.length < 10"
|
||||||
|
@click="showTagInputFunc">
|
||||||
|
<text class="add-symbol">+</text>
|
||||||
|
</view>
|
||||||
|
<view class="input-box" v-if="data.showTagInput">
|
||||||
|
<input class="tag-input-field" v-model="data.tagInputValue" :focus="data.showTagInput"
|
||||||
|
@confirm="confirmAddTag" @blur="confirmAddTag" placeholder="请输入标签" maxlength="5" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="title-box">
|
||||||
|
<view class="title">
|
||||||
|
备注
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="bill-classify-content note-content">
|
||||||
|
<textarea class="note-textarea" auto-height v-model="data.tempNote.text" placeholder="随便说点什么..."
|
||||||
|
maxlength="50" disable-default-padding></textarea>
|
||||||
|
</view>
|
||||||
|
<view class="title-box">
|
||||||
|
<view class="title">
|
||||||
|
备注图片
|
||||||
|
</view>
|
||||||
|
<switch :checked="data.tempNote.isImage" color="#1676FE" style="transform: scale(0.7);"
|
||||||
|
@change="(e) => data.tempNote.isImage = e.detail.value"></switch>
|
||||||
|
</view>
|
||||||
|
<!-- <view class="bill-classify-content" v-if="data.tempNote.isImage"> -->
|
||||||
|
<!-- 此处展示图片上传或其他逻辑,暂时留空或添加提示 -->
|
||||||
|
<!-- </view> -->
|
||||||
|
<view class="confirm-btn" @click="confirmClassify">
|
||||||
|
确定
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</uni-popup>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
reactive,
|
||||||
|
toRefs,
|
||||||
|
ref,
|
||||||
|
defineExpose,
|
||||||
|
defineProps,
|
||||||
|
defineEmits
|
||||||
|
} from 'vue'
|
||||||
|
import addBillJson from '@/static/json/add-bill.json'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
billClassifyOptions: {
|
||||||
|
type: Array,
|
||||||
|
default: () => addBillJson.billClassify
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['confirm', 'update:show'])
|
||||||
|
|
||||||
|
const timepopup = ref(null)
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
popupType: '', // 'billClassify' or 'tagAndNote'
|
||||||
|
currentClassifyName: '',
|
||||||
|
tempTags: [],
|
||||||
|
tagInputValue: '',
|
||||||
|
showTagInput: false,
|
||||||
|
tempNote: {
|
||||||
|
text: '',
|
||||||
|
isImage: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开弹窗
|
||||||
|
* @param {String} type 弹窗类型 'billClassify' | 'tagAndNote'
|
||||||
|
* @param {Object} initData 初始化数据
|
||||||
|
*/
|
||||||
|
const open = (type, initData = {}) => {
|
||||||
|
data.popupType = type
|
||||||
|
if (type === 'billClassify') {
|
||||||
|
data.currentClassifyName = initData.classifyName || ''
|
||||||
|
} else if (type === 'tagAndNote') {
|
||||||
|
// Deep copy to prevent direct mutation of prop data before confirm
|
||||||
|
data.tempTags = initData.tags ? JSON.parse(JSON.stringify(initData.tags)) : []
|
||||||
|
data.tempNote = initData.note ? JSON.parse(JSON.stringify(initData.note)) : { text: '', isImage: false }
|
||||||
|
data.showTagInput = false
|
||||||
|
data.tagInputValue = ''
|
||||||
|
}
|
||||||
|
timepopup.value.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭弹窗
|
||||||
|
*/
|
||||||
|
const closeTimePicker = () => {
|
||||||
|
timepopup.value.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认操作
|
||||||
|
*/
|
||||||
|
const confirmClassify = () => {
|
||||||
|
if (data.popupType === 'billClassify') {
|
||||||
|
const selected = props.billClassifyOptions.find(item => item.name === data.currentClassifyName)
|
||||||
|
emit('confirm', { type: 'billClassify', value: data.currentClassifyName, id: selected ? selected.id : 0 })
|
||||||
|
} else if (data.popupType === 'tagAndNote') {
|
||||||
|
emit('confirm', {
|
||||||
|
type: 'tagAndNote',
|
||||||
|
tags: data.tempTags,
|
||||||
|
note: data.tempNote
|
||||||
|
})
|
||||||
|
}
|
||||||
|
closeTimePicker()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除标签
|
||||||
|
*/
|
||||||
|
const deleteTag = (index) => {
|
||||||
|
data.tempTags.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示标签输入框
|
||||||
|
*/
|
||||||
|
const showTagInputFunc = () => {
|
||||||
|
data.showTagInput = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认添加标签
|
||||||
|
*/
|
||||||
|
const confirmAddTag = () => {
|
||||||
|
if (data.tagInputValue.trim()) {
|
||||||
|
data.tempTags.push(data.tagInputValue.trim())
|
||||||
|
}
|
||||||
|
data.tagInputValue = ''
|
||||||
|
data.showTagInput = false
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
open,
|
||||||
|
close: closeTimePicker
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "@/common/specify-style.less";
|
||||||
|
|
||||||
|
.bill-classify-box {
|
||||||
|
|
||||||
|
.tag-content {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20rpx 16rpx 0 16rpx;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
|
||||||
|
.tag-item {
|
||||||
|
position: relative;
|
||||||
|
background-color: #E6F2FF;
|
||||||
|
color: #2788D1;
|
||||||
|
font-size: 26rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
line-height: 60rpx;
|
||||||
|
padding: 0 24rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
margin-right: 24rpx;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.delete-tag {
|
||||||
|
position: absolute;
|
||||||
|
top: -12rpx;
|
||||||
|
right: -12rpx;
|
||||||
|
width: 32rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
background-color: #FE4141;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border: 2rpx solid #ffffff;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
.close-icon-img {
|
||||||
|
width: 14rpx;
|
||||||
|
height: 14rpx;
|
||||||
|
filter: brightness(0) invert(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-tag-box {
|
||||||
|
height: 52rpx;
|
||||||
|
line-height: 52rpx;
|
||||||
|
background-color: #F4F9FF;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
padding: 0 16rpx;
|
||||||
|
|
||||||
|
.add-symbol {
|
||||||
|
color: #2788D1;
|
||||||
|
font-size: 40rpx;
|
||||||
|
line-height: 52rpx;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-box {
|
||||||
|
width: 160rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
background-color: #F4F9FF;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
padding: 0 16rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.tag-input-field {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #2788D1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-content {
|
||||||
|
|
||||||
|
border-bottom: 1rpx solid #EDEDED;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
|
||||||
|
.note-textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: 160rpx;
|
||||||
|
// background-color: #F9F9F9;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-wrap {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
17
pages.json
|
|
@ -50,6 +50,20 @@
|
||||||
"navigationBarTitleText": "账单详情页",
|
"navigationBarTitleText": "账单详情页",
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/index/alipay-annual-bill/alipay-annual-bill",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "支付宝年度账单",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/common/webview/webview",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "webView页面",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"globalStyle": {
|
"globalStyle": {
|
||||||
|
|
@ -61,6 +75,9 @@
|
||||||
"navigationBarBackgroundColor": "#00000000", // 完全透明
|
"navigationBarBackgroundColor": "#00000000", // 完全透明
|
||||||
"navigationBarTextStyle": "white", // 虚拟按键图标颜色
|
"navigationBarTextStyle": "white", // 虚拟按键图标颜色
|
||||||
"backgroundColor": "#00000000" // 背景透明
|
"backgroundColor": "#00000000" // 背景透明
|
||||||
|
},
|
||||||
|
"app-plus": {
|
||||||
|
"bounce": "none" // 全局关闭回弹效果
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uniIdRouter": {}
|
"uniIdRouter": {}
|
||||||
|
|
|
||||||
|
|
@ -238,6 +238,8 @@
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 底部弹出层 -->
|
<!-- 底部弹出层 -->
|
||||||
|
<billManagementPopup ref="billManagementPopupRef" @confirm="handleBillManagementConfirm"></billManagementPopup>
|
||||||
|
|
||||||
<uni-popup ref="timepopup" type="bottom">
|
<uni-popup ref="timepopup" type="bottom">
|
||||||
<!-- 时间选择器 -->
|
<!-- 时间选择器 -->
|
||||||
<view v-if="selectItemInfo.type == 'time'" class="timeBox">
|
<view v-if="selectItemInfo.type == 'time'" class="timeBox">
|
||||||
|
|
@ -252,82 +254,6 @@
|
||||||
<DateTimePicker :defaultDate="datePickerData.selectDate" :minDate="datePickerData.startDate"
|
<DateTimePicker :defaultDate="datePickerData.selectDate" :minDate="datePickerData.startDate"
|
||||||
:maxDate="datePickerData.endDate" :mode="4" @onChange="onChangeStartDate" />
|
:maxDate="datePickerData.endDate" :mode="4" @onChange="onChangeStartDate" />
|
||||||
</view>
|
</view>
|
||||||
<template v-else>
|
|
||||||
<!-- 账单分类 -->
|
|
||||||
<view v-if="data.popupType == 'billClassify'" class="bill-classify-box">
|
|
||||||
<view class="title-box">
|
|
||||||
<view class="title">
|
|
||||||
账单分类
|
|
||||||
</view>
|
|
||||||
<view class="btn" @click="closeTimePicker">
|
|
||||||
<image class="close-image" src="/static/image/common/close.png"></image>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="bill-classify-content">
|
|
||||||
<view class="bill-classify-item" v-for="item in billClassifyOptions" :key="item.id"
|
|
||||||
@click="data.currentClassifyId = item.id">
|
|
||||||
<view class="bill-classify-item-text"
|
|
||||||
:class="{ 'active-item': data.currentClassifyId == item.id }">
|
|
||||||
{{ item.name }}
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="confirm-btn" @click="confirmClassify">
|
|
||||||
确定
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<!-- 标签和备注 -->
|
|
||||||
<view v-if="data.popupType == 'tagAndNote'" class="bill-classify-box">
|
|
||||||
<view class="title-box">
|
|
||||||
<view class="title">
|
|
||||||
标签
|
|
||||||
<text class="text">(最多10个标签)</text>
|
|
||||||
</view>
|
|
||||||
<view class="btn" @click="closeTimePicker">
|
|
||||||
<image class="close-image" src="/static/image/common/close.png"></image>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="bill-classify-content tag-content flex-wrap">
|
|
||||||
<view class="tag-item" v-for="(tag, index) in data.tempTags" :key="index">
|
|
||||||
<text>{{ tag }}</text>
|
|
||||||
<view class="delete-tag" @click="deleteTag(index)">
|
|
||||||
<image src="/static/image/common/close.png" mode="widthFix" class="close-icon-img"></image>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="add-tag-box" v-if="!data.showTagInput && data.tempTags.length < 10"
|
|
||||||
@click="showTagInputFunc">
|
|
||||||
<text class="add-symbol">+</text>
|
|
||||||
</view>
|
|
||||||
<view class="input-box" v-if="data.showTagInput">
|
|
||||||
<input class="tag-input-field" v-model="data.tagInputValue" :focus="data.showTagInput"
|
|
||||||
@confirm="confirmAddTag" @blur="confirmAddTag" placeholder="请输入标签" maxlength="5" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="title-box">
|
|
||||||
<view class="title">
|
|
||||||
备注
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="bill-classify-content note-content">
|
|
||||||
<textarea class="note-textarea" auto-height v-model="data.tempNote.text" placeholder="随便说点什么..."
|
|
||||||
maxlength="50" disable-default-padding></textarea>
|
|
||||||
</view>
|
|
||||||
<view class="title-box">
|
|
||||||
<view class="title">
|
|
||||||
备注图片
|
|
||||||
</view>
|
|
||||||
<switch :checked="data.tempNote.isImage" color="#1676FE" style="transform: scale(0.7);"
|
|
||||||
@change="(e) => data.tempNote.isImage = e.detail.value"></switch>
|
|
||||||
</view>
|
|
||||||
<!-- <view class="bill-classify-content" v-if="data.tempNote.isImage"> -->
|
|
||||||
<!-- 此处展示图片上传或其他逻辑,暂时留空或添加提示 -->
|
|
||||||
<!-- </view> -->
|
|
||||||
<view class="confirm-btn" @click="confirmClassify">
|
|
||||||
确定
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</uni-popup>
|
</uni-popup>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -335,9 +261,9 @@
|
||||||
import navBar from '@/components/nav-bar/nav-bar.vue'
|
import navBar from '@/components/nav-bar/nav-bar.vue'
|
||||||
import addBillJson from '@/static/json/add-bill.json'
|
import addBillJson from '@/static/json/add-bill.json'
|
||||||
import DateTimePicker from '@/components/dengrq-datetime-picker/dateTimePicker/index.vue';
|
import DateTimePicker from '@/components/dengrq-datetime-picker/dateTimePicker/index.vue';
|
||||||
|
import billManagementPopup from '@/components/bill-management-popup/bill-management-popup.vue'
|
||||||
import { stringUtil, randomUtil, util, uiUtil } from '@/utils/common.js';
|
import { stringUtil, randomUtil, util, uiUtil } from '@/utils/common.js';
|
||||||
import hotIcon from "@/static/json/hot-icon.json"
|
import hotIcon from "@/static/json/hot-icon.json"
|
||||||
import { storage } from '@/utils/storage.js'
|
|
||||||
import { useStore } from '@/store/index.js'
|
import { useStore } from '@/store/index.js'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|
@ -357,6 +283,8 @@ import {
|
||||||
|
|
||||||
// 时间选择器
|
// 时间选择器
|
||||||
const timepopup = ref(null)
|
const timepopup = ref(null)
|
||||||
|
// 账单管理弹窗
|
||||||
|
const billManagementPopupRef = ref(null)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
addBill,
|
addBill,
|
||||||
|
|
@ -884,9 +812,11 @@ const onClickItemInfo = async (item, action) => {
|
||||||
selectItemInfo.value = item
|
selectItemInfo.value = item
|
||||||
timepopup.value.open()
|
timepopup.value.open()
|
||||||
} else if (item.key == 'billClassify') {
|
} else if (item.key == 'billClassify') {
|
||||||
// selectItemInfo.value = item
|
// Use bill-management-popup component
|
||||||
data.popupType = "billClassify"
|
const initData = {
|
||||||
timepopup.value.open()
|
classifyName: billData.value.merchantOption.billClassify
|
||||||
|
}
|
||||||
|
billManagementPopupRef.value.open('billClassify', initData)
|
||||||
} else if (item.type == 'text' || item.type == 'number' || item.type == "digit") {
|
} else if (item.type == 'text' || item.type == 'number' || item.type == "digit") {
|
||||||
item.focus = false
|
item.focus = false
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
|
@ -902,10 +832,12 @@ const onClickItemInfo = async (item, action) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else if (item.key == 'tag' || item.key == 'note') {
|
} else if (item.key == 'tag' || item.key == 'note') {
|
||||||
data.tempTags = JSON.parse(JSON.stringify(billData.value.merchantOption.tag))
|
// Use bill-management-popup component
|
||||||
data.tempNote = JSON.parse(JSON.stringify(billData.value.merchantOption.note))
|
const initData = {
|
||||||
data.popupType = "tagAndNote"
|
tags: billData.value.merchantOption.tag,
|
||||||
timepopup.value.open()
|
note: billData.value.merchantOption.note
|
||||||
|
}
|
||||||
|
billManagementPopupRef.value.open('tagAndNote', initData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1030,46 +962,6 @@ const settmes = () => {
|
||||||
data.popupType = ''
|
data.popupType = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除标签
|
|
||||||
const deleteTag = (index) => {
|
|
||||||
data.tempTags.splice(index, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 显示标签输入框
|
|
||||||
const showTagInputFunc = () => {
|
|
||||||
data.showTagInput = true
|
|
||||||
data.tagInputValue = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确认添加标签
|
|
||||||
const confirmAddTag = () => {
|
|
||||||
if (data.tagInputValue && data.tagInputValue.trim()) {
|
|
||||||
data.tempTags.push(data.tagInputValue.trim())
|
|
||||||
}
|
|
||||||
data.showTagInput = false
|
|
||||||
data.tagInputValue = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置分类选择
|
|
||||||
*/
|
|
||||||
const confirmClassify = () => {
|
|
||||||
if (data.popupType == 'billClassify') {
|
|
||||||
billClassifyOptions.value.forEach(option => {
|
|
||||||
if (option.id == data.currentClassifyId) {
|
|
||||||
billData.value.merchantOption.billClassify = option.name
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else if (data.popupType == 'tagAndNote') {
|
|
||||||
billData.value.merchantOption.tag = JSON.parse(JSON.stringify(data.tempTags))
|
|
||||||
billData.value.merchantOption.note = JSON.parse(JSON.stringify(data.tempNote))
|
|
||||||
}
|
|
||||||
|
|
||||||
timepopup.value.close()
|
|
||||||
data.popupType = ''
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Object} date
|
* @param {Object} date
|
||||||
* 切换时间
|
* 切换时间
|
||||||
|
|
@ -1077,6 +969,20 @@ const confirmClassify = () => {
|
||||||
function onChangeStartDate(date) {
|
function onChangeStartDate(date) {
|
||||||
datePickerData.value.selectDate = date;
|
datePickerData.value.selectDate = date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认账单管理弹窗
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
const handleBillManagementConfirm = (data) => {
|
||||||
|
console.log("确认账单管理弹窗", data)
|
||||||
|
if (data.type == 'billClassify') {
|
||||||
|
billData.value.merchantOption.billClassify = data.value
|
||||||
|
} else if (data.type == 'tagAndNote') {
|
||||||
|
billData.value.merchantOption.tag = data.tags
|
||||||
|
billData.value.merchantOption.note = data.note
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|
@ -1472,98 +1378,4 @@ page {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tag-content {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
align-items: center;
|
|
||||||
padding: 20rpx 16rpx 0 16rpx;
|
|
||||||
margin-bottom: 24rpx;
|
|
||||||
|
|
||||||
.tag-item {
|
|
||||||
position: relative;
|
|
||||||
background-color: #E6F2FF;
|
|
||||||
color: #2788D1;
|
|
||||||
font-size: 26rpx;
|
|
||||||
height: 60rpx;
|
|
||||||
line-height: 60rpx;
|
|
||||||
padding: 0 24rpx;
|
|
||||||
border-radius: 8rpx;
|
|
||||||
margin-right: 24rpx;
|
|
||||||
margin-bottom: 24rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.delete-tag {
|
|
||||||
position: absolute;
|
|
||||||
top: -12rpx;
|
|
||||||
right: -12rpx;
|
|
||||||
width: 32rpx;
|
|
||||||
height: 32rpx;
|
|
||||||
background-color: #FE4141;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
border: 2rpx solid #ffffff;
|
|
||||||
z-index: 10;
|
|
||||||
|
|
||||||
.close-icon-img {
|
|
||||||
width: 14rpx;
|
|
||||||
height: 14rpx;
|
|
||||||
filter: brightness(0) invert(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-tag-box {
|
|
||||||
height: 52rpx;
|
|
||||||
line-height: 52rpx;
|
|
||||||
background-color: #F4F9FF;
|
|
||||||
border-radius: 8rpx;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 24rpx;
|
|
||||||
padding: 0 16rpx;
|
|
||||||
|
|
||||||
.add-symbol {
|
|
||||||
color: #2788D1;
|
|
||||||
font-size: 40rpx;
|
|
||||||
line-height: 52rpx;
|
|
||||||
font-weight: 300;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-box {
|
|
||||||
width: 160rpx;
|
|
||||||
height: 60rpx;
|
|
||||||
background-color: #F4F9FF;
|
|
||||||
border-radius: 8rpx;
|
|
||||||
margin-bottom: 24rpx;
|
|
||||||
padding: 0 16rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.tag-input-field {
|
|
||||||
width: 100%;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #2788D1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-content {
|
|
||||||
|
|
||||||
border-bottom: 1rpx solid #EDEDED;
|
|
||||||
margin-bottom: 24rpx;
|
|
||||||
|
|
||||||
.note-textarea {
|
|
||||||
width: 100%;
|
|
||||||
height: 160rpx;
|
|
||||||
// background-color: #F9F9F9;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -154,7 +154,7 @@
|
||||||
</view>
|
</view>
|
||||||
<view class="bill-classification bill-management-item">
|
<view class="bill-classification bill-management-item">
|
||||||
<text class="label">账单分类</text>
|
<text class="label">账单分类</text>
|
||||||
<view class="right-box flex-align-center">
|
<view class="right-box flex-align-center" @click="handleBillManagementClick('billClassify')">
|
||||||
<text>{{ billData.merchantOption.billClassify }}</text>
|
<text>{{ billData.merchantOption.billClassify }}</text>
|
||||||
<uni-icons style="margin-left: 8rpx;" type="right" size="12" color="#969696"></uni-icons>
|
<uni-icons style="margin-left: 8rpx;" type="right" size="12" color="#969696"></uni-icons>
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -163,7 +163,8 @@
|
||||||
<text v-if="billData.merchantOption.note.text || billData.merchantOption.note.isImage"
|
<text v-if="billData.merchantOption.note.text || billData.merchantOption.note.isImage"
|
||||||
class="label">标签</text>
|
class="label">标签</text>
|
||||||
<text v-else class="label">标签和备注</text>
|
<text v-else class="label">标签和备注</text>
|
||||||
<view class="tag-box right-box flex-1 flex-align-center">
|
<view class="tag-box right-box flex-1 flex-align-center"
|
||||||
|
@click="handleBillManagementClick('tagAndNote')">
|
||||||
<text v-if="billData.merchantOption.tag.length == 0 || !billData.merchantOption.tag">添加</text>
|
<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"
|
<view v-else v-for="(tag, index) in billData.merchantOption.tag.slice(0, 3)" :key="tag"
|
||||||
class="tag-item">
|
class="tag-item">
|
||||||
|
|
@ -178,7 +179,8 @@
|
||||||
<view class="bill-management-item"
|
<view class="bill-management-item"
|
||||||
v-if="billData.merchantOption.note.text || billData.merchantOption.note.isImage">
|
v-if="billData.merchantOption.note.text || billData.merchantOption.note.isImage">
|
||||||
<text class="label">备注</text>
|
<text class="label">备注</text>
|
||||||
<view class="tag-box right-box flex-1 flex-align-center">
|
<view class="tag-box right-box flex-1 flex-align-center"
|
||||||
|
@click="handleBillManagementClick('tagAndNote')">
|
||||||
<view class="remark-box flex-align-center text-align-right flex-1">
|
<view class="remark-box flex-align-center text-align-right flex-1">
|
||||||
<image v-if="billData.merchantOption.note.isImage" class="remark-img"
|
<image v-if="billData.merchantOption.note.isImage" class="remark-img"
|
||||||
src="/static/image/bill/bill-detail/bill-remark-img.png">
|
src="/static/image/bill/bill-detail/bill-remark-img.png">
|
||||||
|
|
@ -195,7 +197,8 @@
|
||||||
<view class="bill-management-item" style="margin-top: 32rpx;">
|
<view class="bill-management-item" style="margin-top: 32rpx;">
|
||||||
<text class="label">计入收支</text>
|
<text class="label">计入收支</text>
|
||||||
<view class="right-box flex-align-center" style="transform:scale(0.6); width: 100rpx;">
|
<view class="right-box flex-align-center" style="transform:scale(0.6); width: 100rpx;">
|
||||||
<switch color="#1676FE" :checked="billData.merchantOption.countInAndOut" />
|
<switch color="#1676FE" :checked="billData.merchantOption.countInAndOut"
|
||||||
|
@change="handleCountInAndOutChange" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="bottom-icon-box">
|
<view class="bottom-icon-box">
|
||||||
|
|
@ -212,10 +215,14 @@
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|
||||||
|
<billManagementPopup ref="billManagementPopupRef" @confirm="handleBillManagementConfirm"></billManagementPopup>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import navBar from '@/components/nav-bar/nav-bar.vue'
|
import navBar from '@/components/nav-bar/nav-bar.vue'
|
||||||
|
import billManagementPopup from '@/components/bill-management-popup/bill-management-popup.vue'
|
||||||
import {
|
import {
|
||||||
billBottomIconList
|
billBottomIconList
|
||||||
} from '@/static/json/add-bill.json'
|
} from '@/static/json/add-bill.json'
|
||||||
|
|
@ -233,16 +240,18 @@ import {
|
||||||
onLoad,
|
onLoad,
|
||||||
onShow,
|
onShow,
|
||||||
} from '@dcloudio/uni-app'
|
} from '@dcloudio/uni-app'
|
||||||
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useStore
|
useStore
|
||||||
} from '@/store/index.js'
|
} from '@/store/index.js'
|
||||||
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getBillList,
|
getBillList,
|
||||||
updateBill
|
updateBill
|
||||||
} = useStore()
|
} = useStore()
|
||||||
|
|
||||||
|
const billManagementPopupRef = ref(null)
|
||||||
|
|
||||||
const buttonGroup = [{
|
const buttonGroup = [{
|
||||||
name: "编辑账单",
|
name: "编辑账单",
|
||||||
click: () => {
|
click: () => {
|
||||||
|
|
@ -353,6 +362,47 @@ const getServiceDetailRightText = (value) => {
|
||||||
const item = serviceDetailRightTextList.find(item => item.value === Number(value))
|
const item = serviceDetailRightTextList.find(item => item.value === Number(value))
|
||||||
return item?.text || ""
|
return item?.text || ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 计入收支
|
||||||
|
function handleCountInAndOutChange(e) {
|
||||||
|
billData.value.merchantOption.countInAndOut = e.detail.value
|
||||||
|
console.log(e, billData.value)
|
||||||
|
|
||||||
|
// Edit mode
|
||||||
|
updateBill(billData.value.id, billData.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 账单管理
|
||||||
|
const handleBillManagementClick = (type) => {
|
||||||
|
let initData = {}
|
||||||
|
if (type == 'billClassify') {
|
||||||
|
initData = {
|
||||||
|
classifyName: billData.value.merchantOption.billClassify
|
||||||
|
}
|
||||||
|
} else if (type == 'tagAndNote') {
|
||||||
|
initData = {
|
||||||
|
tags: billData.value.merchantOption.tag,
|
||||||
|
note: billData.value.merchantOption.note
|
||||||
|
}
|
||||||
|
}
|
||||||
|
billManagementPopupRef.value.open(type, initData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认账单管理弹窗
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
const handleBillManagementConfirm = (data) => {
|
||||||
|
console.log(data)
|
||||||
|
if (data.type == 'billClassify') {
|
||||||
|
billData.value.merchantOption.billClassify = data.value
|
||||||
|
billData.value.selectId = data.id
|
||||||
|
} else if (data.type == 'tagAndNote') {
|
||||||
|
billData.value.merchantOption.tag = data.tags
|
||||||
|
billData.value.merchantOption.note = data.note
|
||||||
|
}
|
||||||
|
updateBill(billData.value.id, billData.value)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@
|
||||||
Number(currentMonthData.outCome).toFixed(2) }}</text></view>
|
Number(currentMonthData.outCome).toFixed(2) }}</text></view>
|
||||||
<view class="item"><text>收入¥</text><text class="money wx-font-regular">{{
|
<view class="item"><text>收入¥</text><text class="money wx-font-regular">{{
|
||||||
Number(currentMonthData.inCome).toFixed(2) }}</text></view>
|
Number(currentMonthData.inCome).toFixed(2) }}</text></view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
<view class="">
|
<view class="">
|
||||||
<text>收支分析</text>
|
<text>收支分析</text>
|
||||||
|
|
@ -56,28 +57,34 @@
|
||||||
:ref="el => cardRefs[index] = el">
|
:ref="el => cardRefs[index] = el">
|
||||||
<view class="list-title-card"
|
<view class="list-title-card"
|
||||||
:class="{ 'current-month': item.month == new Date().getMonth() + 1 && item.year == new Date().getFullYear() }">
|
:class="{ 'current-month': item.month == new Date().getMonth() + 1 && item.year == new Date().getFullYear() }">
|
||||||
|
<view v-if="item.month == new Date().getMonth() + 1 && item.year == new Date().getFullYear()"
|
||||||
|
class="bg-right-text">
|
||||||
|
<text>贴纸</text>
|
||||||
|
<image class="right-icon" src="/static/image/common/right-blue.png"></image>
|
||||||
|
</view>
|
||||||
<view class="list-title">
|
<view class="list-title">
|
||||||
<view>
|
<view>
|
||||||
<text class="month alipay-font">{{ item.month }}</text>
|
<text class="month alipay-font">{{ item.month }}</text>
|
||||||
<text>月</text>
|
<text>月</text>
|
||||||
|
<image class="filter-icon down " src="/static/image/bill/bill-list/down-black.png" mode="">
|
||||||
|
</image>
|
||||||
</view>
|
</view>
|
||||||
<image class="filter-icon down " src="/static/image/bill/bill-list/down-black.png" mode="">
|
|
||||||
</image>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="flex-between analysis-box">
|
<view class="flex-between analysis-box">
|
||||||
<view class="income-ande-outCome">
|
<view class="income-ande-outCome">
|
||||||
<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)
|
|
||||||
}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="outCome item">
|
<view class="outCome item">
|
||||||
<text class="title">支出</text>
|
<text class="title">支出</text>
|
||||||
<text class="amount alipay-font"><text class="font-11 wx-font-regular">¥</text>{{
|
<text class="amount alipay-font"><text class="font-11 wx-font-regular">¥</text>{{
|
||||||
Number(item.outCome).toFixed(2)
|
Number(item.outCome).toFixed(2)
|
||||||
}}</text>
|
}}</text>
|
||||||
</view>
|
</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)
|
||||||
|
}}</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view v-if="!(item.month == new Date().getMonth() + 1 && item.year == new Date().getFullYear())"
|
<view v-if="!(item.month == new Date().getMonth() + 1 && item.year == new Date().getFullYear())"
|
||||||
class="analysis-button">
|
class="analysis-button">
|
||||||
|
|
@ -229,6 +236,13 @@ onShow(() => {
|
||||||
|
|
||||||
// #ifdef APP-PLUS
|
// #ifdef APP-PLUS
|
||||||
util.setAndroidSystemBarColor('#F5F5F5')
|
util.setAndroidSystemBarColor('#F5F5F5')
|
||||||
|
uni.setNavigationBarColor({
|
||||||
|
animation: { // 动画效果
|
||||||
|
duration: 100,
|
||||||
|
timingFunc: 'easeIn'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
plus.navigator.setStatusBarStyle("dark");
|
||||||
// #endif
|
// #endif
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -629,7 +643,6 @@ page {
|
||||||
.income-ande-outCome {
|
.income-ande-outCome {
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
margin-top: 6px;
|
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
|
|
@ -648,7 +661,7 @@ page {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
margin: 0 12px;
|
margin: 0 12px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
background-color: #FFFFFF;
|
// background-color: #FFFFFF;
|
||||||
|
|
||||||
.list-title-card {
|
.list-title-card {
|
||||||
background-color: #FFFFFF;
|
background-color: #FFFFFF;
|
||||||
|
|
@ -666,7 +679,6 @@ page {
|
||||||
}
|
}
|
||||||
|
|
||||||
.income-ande-outCome {
|
.income-ande-outCome {
|
||||||
margin-top: 8px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
|
|
@ -712,13 +724,20 @@ page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.list-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.current-month {
|
.current-month {
|
||||||
|
position: relative;
|
||||||
padding: 10px 12px 18px;
|
padding: 10px 12px 18px;
|
||||||
background: url('/static/image/bill/bill-list/current-month-bill-bg.png') no-repeat center center;
|
background: url('/static/image/bill/bill-list/current-month-bill-bg.png') no-repeat center center;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
|
background-color: transparent;
|
||||||
|
|
||||||
.income-ande-outCome {
|
.income-ande-outCome {
|
||||||
margin-top: 8px;
|
margin-top: 8rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
|
|
@ -747,7 +766,6 @@ page {
|
||||||
}
|
}
|
||||||
|
|
||||||
.income-ande-outCome-analysis {
|
.income-ande-outCome-analysis {
|
||||||
margin-top: 3px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
|
|
@ -780,5 +798,26 @@ page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-right-text {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: #2B3841;
|
||||||
|
font-size: 22rpx;
|
||||||
|
position: absolute;
|
||||||
|
right: 18rpx;
|
||||||
|
top: 32rpx;
|
||||||
|
|
||||||
|
.right-icon {
|
||||||
|
width: 16rpx;
|
||||||
|
height: 16rpx;
|
||||||
|
margin-left: 2rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.bill-list {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
<!-- pages/webview/webview.vue -->
|
||||||
|
<template>
|
||||||
|
<view class="webview-container">
|
||||||
|
<navBar class="nav-bar" :title="pageTitle" :bgColor="data.navBar.bgColor" isBack></navBar>
|
||||||
|
<web-view :src="url" :webview-styles="webviewStyles"></web-view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
// 自定义头部
|
||||||
|
// import ZdyNavbar from "@/components/navbar/navbar.vue"
|
||||||
|
import navBar from '@/components/nav-bar/nav-bar.vue'
|
||||||
|
import { util } from '@/utils/common.js'
|
||||||
|
|
||||||
|
import {
|
||||||
|
ref,
|
||||||
|
reactive,
|
||||||
|
watch,
|
||||||
|
nextTick,
|
||||||
|
getCurrentInstance,
|
||||||
|
onMounted,
|
||||||
|
onBeforeUnmount,
|
||||||
|
toRefs,
|
||||||
|
computed
|
||||||
|
} from "vue";
|
||||||
|
import {
|
||||||
|
onLoad,
|
||||||
|
onReady,
|
||||||
|
onShow
|
||||||
|
} from '@dcloudio/uni-app'
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
navBar: {
|
||||||
|
title: "",
|
||||||
|
bgColor: '#ffffff',
|
||||||
|
},
|
||||||
|
dark: "dark",
|
||||||
|
// 状态栏高度
|
||||||
|
systemBarHeight: "0",
|
||||||
|
})
|
||||||
|
|
||||||
|
let {
|
||||||
|
systemBarHeight
|
||||||
|
} = toRefs(data)
|
||||||
|
|
||||||
|
const url = ref('')
|
||||||
|
const pageTitle = ref('')
|
||||||
|
|
||||||
|
onLoad((options) => {
|
||||||
|
uni.getSystemInfo({
|
||||||
|
success: res => {
|
||||||
|
systemBarHeight.value = res.statusBarHeight; // 获取状态栏高度
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (options.url) {
|
||||||
|
url.value = decodeURIComponent(options.url)
|
||||||
|
// const videoExps = [/\.mp4$/i, /\.m3u8$/i, /\.flv$/i, /\.avi$/i, /\.mov$/i, /\.wmv$/i, /\.webm$/i,
|
||||||
|
// /\.mkv$/i
|
||||||
|
// ];
|
||||||
|
// const isVideo = videoExps.some(exp => exp.test(url.value))
|
||||||
|
// console.log(isVideo)
|
||||||
|
// if (isVideo) {
|
||||||
|
// plus.navigator.setStatusBarStyle("light");
|
||||||
|
// } else {
|
||||||
|
// plus.navigator.setStatusBarStyle("dark");
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
console.log("options参数", options);
|
||||||
|
if (options.title) {
|
||||||
|
console.log("标题", options.title);
|
||||||
|
pageTitle.value = decodeURIComponent(options.title)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onShow(() => {
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
util.setAndroidSystemBarColor('#ffffff')
|
||||||
|
plus.navigator.setStatusBarStyle("dark");
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
uni.navigateBack()
|
||||||
|
}
|
||||||
|
|
||||||
|
const isVideo = computed(() => {
|
||||||
|
if (!url.value) return false
|
||||||
|
const videoExps = [/\.mp4$/i, /\.m3u8$/i, /\.flv$/i, /\.avi$/i, /\.mov$/i, /\.wmv$/i, /\.webm$/i,
|
||||||
|
/\.mkv$/i
|
||||||
|
];
|
||||||
|
return videoExps.some(exp => exp.test(url.value));
|
||||||
|
})
|
||||||
|
|
||||||
|
const webviewStyles = computed(() => {
|
||||||
|
return {
|
||||||
|
top: `${Number(systemBarHeight.value) + 40}px`,
|
||||||
|
bottom: '0px',
|
||||||
|
'padding-bottom': '20px'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.webview-container {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 20rpx;
|
||||||
|
background: #fff;
|
||||||
|
border-bottom: 1rpx solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-web {
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style>
|
||||||
|
page {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,934 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="bg-container"></view>
|
||||||
|
<view class="status-nav-bar" :style="{ height: (statusBarHeight + 44) + 'px' }">
|
||||||
|
<view class="status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
|
||||||
|
<view class="nav-bar">
|
||||||
|
<view class="nav-bar-left" @click="goback()">
|
||||||
|
<image class="nav-bar-left-image" src="@/static/image/alipay-bill/back.png" mode=""></image>
|
||||||
|
</view>
|
||||||
|
<view class="nav-bar-right">
|
||||||
|
<image class="nav-bar-right-image" src="@/static/image/alipay-bill/music-icon.png" mode=""></image>
|
||||||
|
<image class="nav-bar-right-image" src="@/static/image/alipay-bill/share-icon.png" mode=""></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<image ref="bgImage" class="bg-image" src="@/static/image/alipay-bill/main-bg.png" mode="widthFix"></image>
|
||||||
|
<image class="eye-image" src="@/static/image/alipay-bill/hide.png" mode="widthFix"></image>
|
||||||
|
<image class="find-more" src="@/static/image/alipay-bill/find-more.png" mode=""></image>
|
||||||
|
|
||||||
|
<view class="total-money">
|
||||||
|
<text>年度总支出</text>
|
||||||
|
<text class="money alipay-font-bold" @click="openPopup">{{ formatMoney(totalMoney) }}</text>
|
||||||
|
<text class="unit">元</text>
|
||||||
|
</view>
|
||||||
|
<view class="frist-money money-type-item">
|
||||||
|
<view class="type-input-box">
|
||||||
|
<!-- <{{ moneyFrist.type }}>支出最多! -->
|
||||||
|
<<view class="percentage-input-box">
|
||||||
|
<text class="ghost-text">{{ moneyFrist.type }}</text>
|
||||||
|
<input class="percentage-input" type="text" v-model="moneyFrist.type"
|
||||||
|
@input="inputPercentage($event, 'moneyFrist')" maxlength="4"></input>
|
||||||
|
</view>>支出最多!
|
||||||
|
</view>
|
||||||
|
<view class="money">
|
||||||
|
占
|
||||||
|
<view class="percentage-input-box">
|
||||||
|
<text class="ghost-text">{{ moneyFrist.percentage }}</text>
|
||||||
|
<input class="percentage-input" type="digit" v-model="moneyFrist.percentage"
|
||||||
|
@input="inputPercentage($event, 'moneyFrist')"></input>
|
||||||
|
</view>
|
||||||
|
<view>%</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="second-money money-type-item">
|
||||||
|
<view class="type-input-box">
|
||||||
|
<!-- {{ moneySecond.type }} -->
|
||||||
|
<view class="percentage-input-box">
|
||||||
|
<text class="ghost-text">{{ moneySecond.type }}</text>
|
||||||
|
<input class="percentage-input" type="text" v-model="moneySecond.type"
|
||||||
|
@input="inputPercentage($event, 'moneySecond')"></input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="money">
|
||||||
|
占
|
||||||
|
<view class="percentage-input-box">
|
||||||
|
<text class="ghost-text">{{ moneySecond.percentage }}</text>
|
||||||
|
<input class="percentage-input" type="digit" v-model="moneySecond.percentage"
|
||||||
|
@input="inputPercentage($event, 'moneySecond')"></input>
|
||||||
|
</view>
|
||||||
|
<view>%</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="third-money money-type-item">
|
||||||
|
<view class="type-input-box">
|
||||||
|
<!-- {{ moneyThird.type }} -->
|
||||||
|
<view class="percentage-input-box">
|
||||||
|
<text class="ghost-text">{{ moneyThird.type }}</text>
|
||||||
|
<input class="percentage-input" type="text" v-model="moneyThird.type"
|
||||||
|
@input="inputPercentage($event, 'moneyThird')"></input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="money">
|
||||||
|
占
|
||||||
|
<view class="percentage-input-box">
|
||||||
|
<text class="ghost-text">{{ moneyThird.percentage }}</text>
|
||||||
|
<input class="percentage-input" type="digit" v-model="moneyThird.percentage"
|
||||||
|
@input="inputPercentage($event, 'moneyThird')"></input>
|
||||||
|
</view>
|
||||||
|
<view>%</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="fourth-money money-type-item">
|
||||||
|
<view class="type-input-box">
|
||||||
|
<!-- {{ moneyFourth.type }} -->
|
||||||
|
<view class="percentage-input-box">
|
||||||
|
<text class="ghost-text">{{ moneyFourth.type }}</text>
|
||||||
|
<input class="percentage-input" type="text" v-model="moneyFourth.type"
|
||||||
|
@input="inputPercentage($event, 'moneyFourth')"></input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="money">
|
||||||
|
占
|
||||||
|
<view class="percentage-input-box">
|
||||||
|
<text class="ghost-text">{{ moneyFourth.percentage }}</text>
|
||||||
|
<input class="percentage-input" type="digit" v-model="moneyFourth.percentage"
|
||||||
|
@input="inputPercentage($event, 'moneyFourth')"></input>
|
||||||
|
</view>
|
||||||
|
<view>%</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="fifth-money money-type-item">
|
||||||
|
<view class="type-input-box">
|
||||||
|
<!-- {{ moneyFifth.type }} -->
|
||||||
|
<view class="percentage-input-box">
|
||||||
|
<text class="ghost-text">{{ moneyFifth.type }}</text>
|
||||||
|
<input class="percentage-input" type="text" v-model="moneyFifth.type"
|
||||||
|
@input="inputPercentage($event, 'moneyFifth')"></input>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="money">
|
||||||
|
占
|
||||||
|
<view class="percentage-input-box">
|
||||||
|
<text class="ghost-text">{{ moneyFifth.percentage }}</text>
|
||||||
|
<input class="percentage-input" type="digit" v-model="moneyFifth.percentage"
|
||||||
|
@input="inputPercentage($event, 'moneyFifth')"></input>
|
||||||
|
</view>
|
||||||
|
<view>%</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="time-box" @click="openTimePopup">
|
||||||
|
数据统计截至{{ formatDate(time) }}
|
||||||
|
</view>
|
||||||
|
<image class="footer-image" src="@/static/image/alipay-bill/footer.png" mode="heightFix"></image>
|
||||||
|
|
||||||
|
<!-- 修改金额弹窗 -->
|
||||||
|
<uni-popup ref="dialogPopup" type="dialog">
|
||||||
|
<uni-popup-dialog class="popup-dialog" mode="input" title="修改年度总支出" :before-close="true"
|
||||||
|
@close="dialogPopupClose()" @confirm="confirm">
|
||||||
|
<uni-easyinput v-model="totalMoney" step="0.01" type="digit" :focus="true"
|
||||||
|
placeholder="请输入金额"></uni-easyinput>
|
||||||
|
</uni-popup-dialog>
|
||||||
|
</uni-popup>
|
||||||
|
|
||||||
|
<!-- 修改时间弹窗 -->
|
||||||
|
<uni-popup ref="timeDialogPopup" type="dialog">
|
||||||
|
<uni-popup-dialog class="popup-dialog" mode="input" title="修改时间" :before-close="true"
|
||||||
|
@close="timeDialogPopupClose()" @confirm="confirmTime">
|
||||||
|
<picker mode="date" fields="day" :value="time" @change="bindTimeChange" start="2025-12-29"
|
||||||
|
:end="formatDateISO(new Date())">
|
||||||
|
<view class="picker-view" style="padding: 10px; border-radius: 4px; text-align: center;">
|
||||||
|
{{ formatDate(time) || '请选择时间' }}
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</uni-popup-dialog>
|
||||||
|
</uni-popup>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 水印 -->
|
||||||
|
<!-- <view v-if="$isVip()">
|
||||||
|
<watermark :dark="data.dark" />
|
||||||
|
<liu-drag-button :canDocking="false" @clickBtn="$goRechargePage('watermark')">
|
||||||
|
<c-lottie ref="cLottieRef" :src='$watermark()' width="94px" height='74px' :loop="true"></c-lottie>
|
||||||
|
</liu-drag-button>
|
||||||
|
</view> -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
ref,
|
||||||
|
reactive,
|
||||||
|
toRefs
|
||||||
|
} from 'vue';
|
||||||
|
import {
|
||||||
|
onLoad,
|
||||||
|
onShow,
|
||||||
|
onUnload
|
||||||
|
} from '@dcloudio/uni-app';
|
||||||
|
const statusBarHeight = ref(0);
|
||||||
|
const dialogPopup = ref(null);
|
||||||
|
const timeDialogPopup = ref(null);
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
totalMoney: 10000000,
|
||||||
|
time: "",
|
||||||
|
moneyFrist: {
|
||||||
|
type: '转账红包',
|
||||||
|
percentage: "83"
|
||||||
|
},
|
||||||
|
moneySecond: {
|
||||||
|
type: '家居家装',
|
||||||
|
percentage: "83"
|
||||||
|
},
|
||||||
|
moneyThird: {
|
||||||
|
type: '餐饮美食',
|
||||||
|
percentage: "83"
|
||||||
|
},
|
||||||
|
moneyFourth: {
|
||||||
|
type: '日用百货',
|
||||||
|
percentage: "83"
|
||||||
|
},
|
||||||
|
moneyFifth: {
|
||||||
|
type: '服饰装扮',
|
||||||
|
percentage: "83"
|
||||||
|
},
|
||||||
|
navBarHeight: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
let {
|
||||||
|
totalMoney,
|
||||||
|
moneyFrist,
|
||||||
|
moneySecond,
|
||||||
|
moneyThird,
|
||||||
|
moneyFourth,
|
||||||
|
moneyFifth,
|
||||||
|
time,
|
||||||
|
navBarHeight
|
||||||
|
} = toRefs(data)
|
||||||
|
|
||||||
|
|
||||||
|
onLoad(() => {
|
||||||
|
time.value = getYesterday();
|
||||||
|
statusBarHeight.value = uni.getSystemInfoSync().statusBarHeight;
|
||||||
|
|
||||||
|
const config = uni.getStorageSync('config')
|
||||||
|
console.log("---config---", config);
|
||||||
|
const font = config.config['client.uniapp.font']
|
||||||
|
|
||||||
|
console.log("字体地址信息", font.alipay2025);
|
||||||
|
// Font loading logic
|
||||||
|
const fontUrl = font.alipay2025;
|
||||||
|
const fontName = 'AlibabaSemiBold';
|
||||||
|
|
||||||
|
const loadFont = (path) => {
|
||||||
|
uni.loadFontFace({
|
||||||
|
family: fontName,
|
||||||
|
source: `url("${path}")`,
|
||||||
|
success() {
|
||||||
|
console.log('字体加载成功');
|
||||||
|
},
|
||||||
|
fail(err) {
|
||||||
|
console.error('字体加载失败', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// #ifdef H5
|
||||||
|
// H5 环境直接从 URL 加载字体
|
||||||
|
loadFont(fontUrl);
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifndef H5
|
||||||
|
// 非 H5 环境使用下载和保存逻辑
|
||||||
|
const savedFontPath = uni.getStorageSync('alipay_font_path');
|
||||||
|
if (savedFontPath) {
|
||||||
|
loadFont(savedFontPath);
|
||||||
|
} else {
|
||||||
|
uni.downloadFile({
|
||||||
|
url: fontUrl,
|
||||||
|
success: (res) => {
|
||||||
|
if (res.statusCode === 200) {
|
||||||
|
uni.saveFile({
|
||||||
|
tempFilePath: res.tempFilePath,
|
||||||
|
success: (saveRes) => {
|
||||||
|
const savedPath = saveRes.savedFilePath;
|
||||||
|
uni.setStorageSync('alipay_font_path', savedPath);
|
||||||
|
console.log("字体保存路径", savedPath);
|
||||||
|
loadFont(savedPath);
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('保存文件失败', err);
|
||||||
|
// Fallback: 尝试加载临时路径
|
||||||
|
loadFont(res.tempFilePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('下载字体失败', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
try {
|
||||||
|
data.totalMoney = uni.getStorageSync('totalMoney') || 1000000;
|
||||||
|
data.moneyFrist = uni.getStorageSync('moneyFrist') || {
|
||||||
|
type: '转账红包',
|
||||||
|
percentage: "66.3"
|
||||||
|
};
|
||||||
|
data.moneySecond = uni.getStorageSync('moneySecond') || {
|
||||||
|
type: '家居家装',
|
||||||
|
percentage: "16.8"
|
||||||
|
};
|
||||||
|
data.moneyThird = uni.getStorageSync('moneyThird') || {
|
||||||
|
type: '服饰装备',
|
||||||
|
percentage: "8.3"
|
||||||
|
};
|
||||||
|
data.moneyFourth = uni.getStorageSync('moneyFourth') || {
|
||||||
|
type: '日用百货',
|
||||||
|
percentage: "5.2"
|
||||||
|
};
|
||||||
|
data.moneyFifth = uni.getStorageSync('moneyFifth') || {
|
||||||
|
type: '餐饮美食',
|
||||||
|
percentage: "3.2"
|
||||||
|
};
|
||||||
|
data.time = uni.getStorageSync('alipayBillEndTime') || getYesterday();
|
||||||
|
console.log('数据同步缓存成功');
|
||||||
|
} catch (err) {
|
||||||
|
console.log('数据同步缓存失败', err);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开修改金额弹窗
|
||||||
|
*/
|
||||||
|
const openPopup = () => {
|
||||||
|
dialogPopup.value.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
const goback = () => {
|
||||||
|
uni.navigateBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatMoney = (val) => {
|
||||||
|
let num = Number(val);
|
||||||
|
if (isNaN(num)) {
|
||||||
|
return '0.00';
|
||||||
|
}
|
||||||
|
let str = num.toFixed(2);
|
||||||
|
let parts = str.split('.');
|
||||||
|
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||||
|
return parts.join('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const dialogPopupClose = () => {
|
||||||
|
dialogPopup.value.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirm = () => {
|
||||||
|
uni.setStorageSync('totalMoney', totalMoney.value);
|
||||||
|
dialogPopup.value.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化时间
|
||||||
|
* @param {Object} date
|
||||||
|
*/
|
||||||
|
const formatDate = (date) => {
|
||||||
|
const d = new Date(date);
|
||||||
|
const y = d.getFullYear();
|
||||||
|
const m = d.getMonth() + 1;
|
||||||
|
const day = d.getDate();
|
||||||
|
return `${y}年${m}月${day}日`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputPercentage = (e, type) => {
|
||||||
|
console.log('Saving', type, data[type]);
|
||||||
|
uni.setStorageSync(type, data[type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开修改时间弹窗
|
||||||
|
*/
|
||||||
|
const openTimePopup = () => {
|
||||||
|
timeDialogPopup.value.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeDialogPopupClose = () => {
|
||||||
|
timeDialogPopup.value.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
const bindTimeChange = (e) => {
|
||||||
|
time.value = e.detail.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取昨天的时间
|
||||||
|
*/
|
||||||
|
const getYesterday = () => {
|
||||||
|
const date = new Date();
|
||||||
|
date.setDate(date.getDate() - 1);
|
||||||
|
return formatDateISO(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化时间 2025-12-01
|
||||||
|
* @param {Object} date
|
||||||
|
*/
|
||||||
|
const formatDateISO = (date) => {
|
||||||
|
const d = new Date(date);
|
||||||
|
const y = d.getFullYear();
|
||||||
|
const m = (d.getMonth() + 1).toString().padStart(2, '0');
|
||||||
|
const day = d.getDate().toString().padStart(2, '0');
|
||||||
|
return `${y}-${m}-${day}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmTime = () => {
|
||||||
|
uni.setStorageSync('alipayBillEndTime', time.value);
|
||||||
|
timeDialogPopup.value.close();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.container {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: #D3E9FE;
|
||||||
|
// background: linear-gradient(180deg, #6BB8FE 0%, #D3E9FE 100%);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.nav-bar {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100vw;
|
||||||
|
height: 44px;
|
||||||
|
background-color: transparent;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 10px;
|
||||||
|
|
||||||
|
.nav-bar-left-image {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-bar-right-image {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-container {
|
||||||
|
width: 100vw;
|
||||||
|
height: 50%;
|
||||||
|
background: linear-gradient(180deg, #6BB8FE 0%, #D3E9FE 100%);
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-image {
|
||||||
|
width: 100vw;
|
||||||
|
height: 85% !important;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total-money {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(15% + 12px);
|
||||||
|
left: 10%;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.money {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 44rpx;
|
||||||
|
margin-left: 6rpx;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-input-box {
|
||||||
|
margin-left: 6rpx;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ghost-text {
|
||||||
|
font-size: 44rpx;
|
||||||
|
min-width: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
white-space: pre;
|
||||||
|
height: 44rpx;
|
||||||
|
line-height: 44rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-input {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 44rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit {
|
||||||
|
font-size: 44rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.frist-money {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(48%);
|
||||||
|
left: 16%;
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
transform: rotate(6deg);
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 58rpx;
|
||||||
|
|
||||||
|
.type-input-box {
|
||||||
|
.ghost-text {
|
||||||
|
font-size: 36rpx;
|
||||||
|
min-width: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
white-space: pre;
|
||||||
|
height: 36rpx;
|
||||||
|
line-height: 36rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-input {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 36rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.money {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 44rpx;
|
||||||
|
margin-left: 6rpx;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.percentage-input-box {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ghost-text {
|
||||||
|
font-size: 44rpx;
|
||||||
|
min-width: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
white-space: pre;
|
||||||
|
height: 44rpx;
|
||||||
|
line-height: 44rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-input {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 44rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.second-money {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(33% + 8rpx);
|
||||||
|
right: 12%;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
transform: rotate(6deg);
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 44rpx;
|
||||||
|
|
||||||
|
.type-input-box {
|
||||||
|
height: 44rpx;
|
||||||
|
|
||||||
|
.ghost-text {
|
||||||
|
font-size: 32rpx;
|
||||||
|
min-width: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
white-space: pre;
|
||||||
|
height: 32rpx;
|
||||||
|
line-height: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-input {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 32rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.money {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
margin-left: 6rpx;
|
||||||
|
|
||||||
|
.percentage-input-box {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ghost-text {
|
||||||
|
font-size: 32rpx;
|
||||||
|
min-width: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
white-space: pre;
|
||||||
|
height: 32rpx;
|
||||||
|
line-height: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-input {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 32rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.third-money {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(25% + 8rpx);
|
||||||
|
left: 23%;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
transform: rotate(4deg);
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 42rpx;
|
||||||
|
|
||||||
|
.type-input-box {
|
||||||
|
height: 42rpx;
|
||||||
|
line-height: 42rpx;
|
||||||
|
|
||||||
|
.ghost-text {
|
||||||
|
font-size: 32rpx;
|
||||||
|
min-width: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
white-space: pre;
|
||||||
|
height: 32rpx;
|
||||||
|
line-height: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-input {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 32rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.money {
|
||||||
|
font-size: 32rpx;
|
||||||
|
margin-left: 6rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.percentage-input-box {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ghost-text {
|
||||||
|
font-size: 32rpx;
|
||||||
|
min-width: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
white-space: pre;
|
||||||
|
height: 32rpx;
|
||||||
|
line-height: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-input {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 32rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fourth-money {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(44% - 4rpx);
|
||||||
|
right: calc(14% + 4px);
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
transform: rotate(4deg);
|
||||||
|
line-height: 28rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
|
||||||
|
.type-input-box {
|
||||||
|
height: 28rpx;
|
||||||
|
line-height: 28rpx;
|
||||||
|
|
||||||
|
.ghost-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
min-width: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
white-space: pre;
|
||||||
|
height: 24rpx;
|
||||||
|
line-height: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-input {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 24rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.money {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 24rpx;
|
||||||
|
margin-left: 6rpx;
|
||||||
|
|
||||||
|
.percentage-input-box {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ghost-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
min-width: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
white-space: pre;
|
||||||
|
height: 24rpx;
|
||||||
|
line-height: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-input {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 24rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fifth-money {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(35% - 4rpx);
|
||||||
|
left: 7%;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
transform: rotate(4deg);
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 42rpx;
|
||||||
|
|
||||||
|
.type-input-box {
|
||||||
|
height: 42rpx;
|
||||||
|
line-height: 42rpx;
|
||||||
|
|
||||||
|
.ghost-text {
|
||||||
|
font-size: 30rpx;
|
||||||
|
min-width: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
white-space: pre;
|
||||||
|
height: 30rpx;
|
||||||
|
line-height: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-input {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.money {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 30rpx;
|
||||||
|
margin-left: 6rpx;
|
||||||
|
|
||||||
|
.percentage-input-box {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ghost-text {
|
||||||
|
font-size: 30rpx;
|
||||||
|
min-width: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
white-space: pre;
|
||||||
|
height: 30rpx;
|
||||||
|
line-height: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-input {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.money-type-item {
|
||||||
|
color: #000000;
|
||||||
|
font-weight: 700;
|
||||||
|
|
||||||
|
.type-input-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.percentage-input-box {
|
||||||
|
margin-left: 6rpx;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.find-more {
|
||||||
|
width: 118rpx;
|
||||||
|
height: 50rpx;
|
||||||
|
position: absolute;
|
||||||
|
top: 28%;
|
||||||
|
right: -4%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.eye-image {
|
||||||
|
width: 98rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
position: absolute;
|
||||||
|
top: 17%;
|
||||||
|
right: 8%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-box {
|
||||||
|
padding: 10rpx 56rpx;
|
||||||
|
background-color: #000000;
|
||||||
|
opacity: 0.35;
|
||||||
|
color: #FAC6CA;
|
||||||
|
font-size: 22rpx;
|
||||||
|
line-height: 22rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 286px;
|
||||||
|
position: absolute;
|
||||||
|
white-space: nowrap;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
bottom: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-image {
|
||||||
|
height: 190rpx;
|
||||||
|
position: fixed;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
bottom: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alipay-font-bold {
|
||||||
|
font-family: 'AlibabaSemiBold';
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<view class="nav-bar-box">
|
<view class="nav-bar-box">
|
||||||
<view class="status-box" :style="{ height: statusBarHeight + 'px' }"></view>
|
<view class="status-box" :style="{ height: statusBarHeight + 'px' }"></view>
|
||||||
<view class="nav-box">
|
<view class="nav-box">
|
||||||
<view class="left-box">
|
<view class="left-box" @click="exit">
|
||||||
<image style="width: 40rpx; height: 40rpx;" src="/static/image/nav-bar/back-black.png"></image>
|
<image style="width: 40rpx; height: 40rpx;" src="/static/image/nav-bar/back-black.png"></image>
|
||||||
</view>
|
</view>
|
||||||
<view class="title">小宝模拟器</view>
|
<view class="title">小宝模拟器</view>
|
||||||
|
|
@ -14,68 +14,90 @@
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
<view class="content-box">
|
<view class="content-box" :style="{ height: windowHeight + 'px' }">
|
||||||
<view class="user-box">
|
<view>
|
||||||
<image class="user-bg" :style="{ width: (windowWidth - 32) + 'px' }"
|
<view style="background-color: transparent;" :style="{ height: (44 + statusBarHeight) + 'px' }"></view>
|
||||||
:src="`/static/image/index/${userInfo.vip > 1 ? (userInfo.vip == 3 ? 'lifetime-vip-bg' : 'vip-bg') : 'no-vip-bg'}.png`"
|
<view class="user-box">
|
||||||
mode=""></image>
|
<image class="user-bg" :style="{ width: (windowWidth - 32) + 'px' }"
|
||||||
<view class="user-info-box" :style="{ width: (windowWidth - 32) + 'px' }">
|
:src="`/static/image/index/${userInfo.vip > 1 ? (userInfo.vip == 3 ? 'lifetime-vip-bg' : 'vip-bg') : 'no-vip-bg'}.png`"
|
||||||
<image class="user-avatar" :src="userInfo.avater"></image>
|
mode=""></image>
|
||||||
<view class="user-info">
|
<view class="user-info-box" :style="{ width: (windowWidth - 32) + 'px' }">
|
||||||
<view class="name-box">
|
<image class="user-avatar" :src="userInfo.avater"></image>
|
||||||
<text class="phone-text">ID:{{ userInfo.user_id }}</text>
|
<view class="user-info">
|
||||||
<image v-if="userInfo.vip > 1" class="vip-logo" src="/static/image/index/vip-logo.png">
|
<view class="name-box">
|
||||||
|
<text class="phone-text">ID:{{ userInfo.user_id }}</text>
|
||||||
|
<image v-if="userInfo.vip > 1" class="vip-logo" src="/static/image/index/vip-logo.png">
|
||||||
|
</image>
|
||||||
|
</view>
|
||||||
|
<view class="">
|
||||||
|
<text v-if="userInfo.vip > 1" class="vip-end-time">会员到期:{{ userInfo.vip_expire }}</text>
|
||||||
|
<text v-else class="vip-end-time">开通会员解锁全部功能</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="userInfo.vip && userInfo.vip != 3" class="btn-box">
|
||||||
|
<image class="open-vip-btn"
|
||||||
|
:src="`/static/image/index/${userInfo.vip > 1 ? 'vip-btn' : 'open-vip-btn'}.png`">
|
||||||
</image>
|
</image>
|
||||||
</view>
|
</view>
|
||||||
<view class="">
|
</view>
|
||||||
<text v-if="userInfo.vip > 1" class="vip-end-time">会员到期:{{ userInfo.vip_expire }}</text>
|
</view>
|
||||||
<text v-else class="vip-end-time">开通会员解锁全部功能</text>
|
|
||||||
|
<view class="notice-box" @click="clickNotice">
|
||||||
|
<view class="sound-box">
|
||||||
|
<uni-icons type="sound" size="18" color="#D8D8D8"></uni-icons>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view ref="noticeContainer" class="notice-content-wrapper">
|
||||||
|
<view ref="noticeInner" class="notice-inner">
|
||||||
|
<text ref="noticeBox" class="notice-content" style="margin-right: 30rpx;">{{ noticeInfo.text
|
||||||
|
}}</text>
|
||||||
|
<text class="notice-content" style="margin-right: 30rpx;">{{ noticeInfo.text }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view v-if="userInfo.vip && userInfo.vip != 3" class="btn-box">
|
|
||||||
<image class="open-vip-btn"
|
|
||||||
:src="`/static/image/index/${userInfo.vip > 1 ? 'vip-btn' : 'open-vip-btn'}.png`"></image>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="notice-box">
|
<view class="group-box">
|
||||||
<uni-icons type="sound" size="18" color="#D8D8D8"></uni-icons>
|
<image class="title-img" src="/static/image/index/shipingjiaocheng.png"></image>
|
||||||
<text class="notice-content">欢迎大家使用装样大师,使用中有问题客服为您解答</text>
|
<view class="video-help-box">
|
||||||
</view>
|
<view class="video-help-item" v-for="item in videoHelpList" :key="item.id"
|
||||||
|
@click="clickVideoHelp(item)">
|
||||||
<view class="group-box">
|
<image class="video-help-img" :src="item.icon"></image>
|
||||||
<image class="title-img" src="/static/image/index/shipingjiaocheng.png"></image>
|
<text class="video-help-title">{{ item.text }}教程</text>
|
||||||
<view class="video-help-box">
|
|
||||||
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="group-box">
|
|
||||||
<image class="title-img" src="/static/image/index/monixiaobao.png"></image>
|
|
||||||
<view class="menu-box">
|
|
||||||
<view class="item-box" v-for="item in menuList" :key="item.name" @click="util.goPage(item.path)">
|
|
||||||
<view class="menu-item" :style="{ width: (windowWidth - 50) / 2 + 'px' }">
|
|
||||||
<!-- <text class="menu-item-name">{{ item.name }}</text> -->
|
|
||||||
<image class="name-img" :src="'/static/image/index/menu-name/' + item.icon + '.png'"
|
|
||||||
mode="heightFix">
|
|
||||||
</image>
|
|
||||||
<image style="width: 108rpx;height: 108rpx; flex-shrink: 0;"
|
|
||||||
:src="'/static/image/index/menu-icon/' + item.icon + '.png'"></image>
|
|
||||||
</view>
|
</view>
|
||||||
<image v-if="item.isHot" class="hot-icon" src="/static/image/index/hot-icon.png"></image>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<view class="group-box">
|
||||||
|
<image class="title-img" src="/static/image/index/monixiaobao.png"></image>
|
||||||
|
<view class="menu-box">
|
||||||
|
<view class="item-box" v-for="item in menuList" :key="item.name"
|
||||||
|
@click="util.goPage(item.path)">
|
||||||
|
<view class="menu-item" :style="{ width: (windowWidth - 50) / 2 + 'px' }">
|
||||||
|
<!-- <text class="menu-item-name">{{ item.name }}</text> -->
|
||||||
|
<image class="name-img" :src="'/static/image/index/menu-name/' + item.icon + '.png'"
|
||||||
|
mode="heightFix">
|
||||||
|
</image>
|
||||||
|
<image style="width: 108rpx;height: 108rpx; flex-shrink: 0;"
|
||||||
|
:src="'/static/image/index/menu-icon/' + item.icon + '.png'"></image>
|
||||||
|
</view>
|
||||||
|
<image v-if="item.isHot" class="hot-icon" src="/static/image/index/hot-icon.png"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="activity-box">
|
||||||
|
<image class="alipay-year-bill" :style="{ width: (windowWidth - 32) + 'px' }"
|
||||||
|
src="/static/image/index/alipay-year-bill.png" mode="widthFix"
|
||||||
|
@click="util.goPage(`/pages/index/alipay-annual-bill/alipay-annual-bill`)"></image>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="activity-box">
|
<view class="footer-box">
|
||||||
<image class="alipay-year-bill" :style="{ width: (windowWidth - 32) + 'px' }"
|
<text class="vision-text">版本:{{ vision }}</text>
|
||||||
src="/static/image/index/alipay-year-bill.png" mode="widthFix"></image>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|
@ -85,6 +107,9 @@ import {
|
||||||
import {
|
import {
|
||||||
storage
|
storage
|
||||||
} from '@/utils/storage.js'
|
} from '@/utils/storage.js'
|
||||||
|
import {
|
||||||
|
get
|
||||||
|
} from '@/utils/requests.js'
|
||||||
import {
|
import {
|
||||||
ref,
|
ref,
|
||||||
reactive,
|
reactive,
|
||||||
|
|
@ -128,20 +153,30 @@ const data = reactive({
|
||||||
statusBarHeight: 0,
|
statusBarHeight: 0,
|
||||||
windowWidth: 0,
|
windowWidth: 0,
|
||||||
windowHeight: 0,
|
windowHeight: 0,
|
||||||
userInfo: {}
|
userInfo: {},
|
||||||
|
videoHelpList: [],
|
||||||
|
noticeInfo: {},
|
||||||
|
vision: "1.0.0"
|
||||||
})
|
})
|
||||||
|
|
||||||
const {
|
const {
|
||||||
statusBarHeight,
|
statusBarHeight,
|
||||||
windowWidth,
|
windowWidth,
|
||||||
userInfo
|
windowHeight,
|
||||||
|
userInfo,
|
||||||
|
videoHelpList,
|
||||||
|
noticeInfo,
|
||||||
|
vision
|
||||||
} = toRefs(data);
|
} = toRefs(data);
|
||||||
|
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
setUserData()
|
// 启动时获取数据
|
||||||
|
fetchUserData()
|
||||||
})
|
})
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
|
// 每次显示时刷新数据
|
||||||
|
setUserData()
|
||||||
// 获取系统信息
|
// 获取系统信息
|
||||||
const systemInfo = uni.getSystemInfoSync();
|
const systemInfo = uni.getSystemInfoSync();
|
||||||
data.statusBarHeight = systemInfo.statusBarHeight;
|
data.statusBarHeight = systemInfo.statusBarHeight;
|
||||||
|
|
@ -151,13 +186,222 @@ onShow(() => {
|
||||||
util.setAndroidSystemBarColor('#F0F4F9')
|
util.setAndroidSystemBarColor('#F0F4F9')
|
||||||
// #endif
|
// #endif
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置用户数据
|
* 获取用户数据(从服务器)
|
||||||
|
*/
|
||||||
|
const fetchUserData = async () => {
|
||||||
|
try {
|
||||||
|
// 先设置默认值,避免页面显示异常
|
||||||
|
setUserData()
|
||||||
|
|
||||||
|
// 并行获取用户信息和配置
|
||||||
|
const [userResult, configResult] = await Promise.allSettled([
|
||||||
|
fetchUserInfo(),
|
||||||
|
fetchUserConfig()
|
||||||
|
])
|
||||||
|
|
||||||
|
// 处理用户信息结果
|
||||||
|
if (userResult.status === 'fulfilled') {
|
||||||
|
console.log('用户信息获取成功')
|
||||||
|
} else {
|
||||||
|
console.error('获取用户信息失败:', userResult.reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理用户配置结果
|
||||||
|
if (configResult.status === 'fulfilled') {
|
||||||
|
console.log('用户配置获取成功')
|
||||||
|
} else {
|
||||||
|
console.error('获取用户配置失败:', configResult.reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新页面数据
|
||||||
|
setUserData()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取用户数据异常:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户信息
|
||||||
|
*/
|
||||||
|
const fetchUserInfo = async () => {
|
||||||
|
const data = await get('', 'api/user', {})
|
||||||
|
if (data.code === 0) {
|
||||||
|
uni.setStorageSync('userInfo', data.data)
|
||||||
|
return data.data
|
||||||
|
} else {
|
||||||
|
throw new Error(data.message || '获取用户信息失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户配置
|
||||||
|
*/
|
||||||
|
const fetchUserConfig = async () => {
|
||||||
|
const data = await get('', 'api/user/config', {})
|
||||||
|
if (data.code === 0) {
|
||||||
|
uni.setStorageSync('config', data.data)
|
||||||
|
return data.data
|
||||||
|
} else {
|
||||||
|
throw new Error(data.message || '获取用户配置失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置用户数据(从本地存储读取)
|
||||||
*/
|
*/
|
||||||
const setUserData = () => {
|
const setUserData = () => {
|
||||||
data.userInfo = storage.get("userInfo")
|
// 用户信息 - 提供默认值
|
||||||
console.log(data.userInfo)
|
const userInfoData = storage.get("userInfo")
|
||||||
}
|
data.userInfo = userInfoData || {
|
||||||
|
user_id: '加载中...',
|
||||||
|
avater: '/static/default-avatar.png',
|
||||||
|
vip: 0,
|
||||||
|
vip_expire: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置信息 - 安全访问
|
||||||
|
const configData = storage.get("config")
|
||||||
|
if (configData && configData.config) {
|
||||||
|
data.noticeInfo = configData.config['client.uniapp.notice'] || { text: '加载中...', url: '' }
|
||||||
|
data.noticeInfo = configData.config['client.uniapp.notice'] || { text: '加载中...', url: '' }
|
||||||
|
// 启动走马灯
|
||||||
|
startMarquee();
|
||||||
|
data.videoHelpList = configData.config['client.uniapp.alipay.video_help'] || []
|
||||||
|
} else {
|
||||||
|
data.noticeInfo = { text: '加载中...', url: '' }
|
||||||
|
data.videoHelpList = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点击视频教程
|
||||||
|
* @param item
|
||||||
|
*/
|
||||||
|
const clickVideoHelp = (item) => {
|
||||||
|
const url = item.url
|
||||||
|
util.goPage(`/pages/common/webview/webview?url=${encodeURIComponent(url)}&title=${item.text}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点击公告
|
||||||
|
*/
|
||||||
|
const clickNotice = () => {
|
||||||
|
if (!noticeInfo.value.url) return
|
||||||
|
const url = noticeInfo.value.url + `&uni_id=${userInfo.value.user_id}`
|
||||||
|
util.goPage(`/pages/common/webview/webview?url=${encodeURIComponent(url)}&title=${noticeInfo.value.title}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出模拟器
|
||||||
|
*/
|
||||||
|
const exit = () => {
|
||||||
|
plus.runtime.quit()
|
||||||
|
}
|
||||||
|
|
||||||
|
const noticeContainer = ref(null);
|
||||||
|
const noticeInner = ref(null);
|
||||||
|
const noticeBox = ref(null);
|
||||||
|
|
||||||
|
// #ifndef H5
|
||||||
|
const animation = uni.requireNativePlugin('animation');
|
||||||
|
const dom = uni.requireNativePlugin('dom');
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
let marqueeTimer = null;
|
||||||
|
const currentMarqueeId = ref(0);
|
||||||
|
const lastMarqueeText = ref('');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始走马灯
|
||||||
|
*/
|
||||||
|
const startMarquee = () => {
|
||||||
|
// 避免不必要的重置:如果文本没有变化且正在运行,则忽略
|
||||||
|
if (lastMarqueeText.value === noticeInfo.value.text && currentMarqueeId.value > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastMarqueeText.value = noticeInfo.value.text;
|
||||||
|
|
||||||
|
// 清除待执行的启动定时器
|
||||||
|
if (marqueeTimer) {
|
||||||
|
clearTimeout(marqueeTimer);
|
||||||
|
marqueeTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 增加 ID 以使之前的动画循环失效
|
||||||
|
currentMarqueeId.value++;
|
||||||
|
const myId = currentMarqueeId.value;
|
||||||
|
|
||||||
|
// 清除旧动画状态 (重置位置)
|
||||||
|
if (noticeInner.value) {
|
||||||
|
animation.transition(noticeInner.value, {
|
||||||
|
styles: { transform: 'translateX(0)' },
|
||||||
|
duration: 0,
|
||||||
|
delay: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
marqueeTimer = setTimeout(() => {
|
||||||
|
if (!noticeContainer.value || !noticeInner.value) return;
|
||||||
|
// 如果ID不匹配,说明有新的启动请求,放弃当前
|
||||||
|
if (myId !== currentMarqueeId.value) return;
|
||||||
|
|
||||||
|
// 获取容器宽度
|
||||||
|
dom.getComponentRect(noticeContainer.value, (resContainer) => {
|
||||||
|
const containerWidth = resContainer.size.width;
|
||||||
|
if (!containerWidth) return;
|
||||||
|
|
||||||
|
// 获取文本/内部容器宽度
|
||||||
|
dom.getComponentRect(noticeInner.value, (resText) => {
|
||||||
|
const textWidth = resText.size.width / 2; // 因为复制了一份
|
||||||
|
if (!textWidth) return;
|
||||||
|
|
||||||
|
// 执行滚动
|
||||||
|
runMarqueeAnimation(containerWidth, textWidth, myId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, 1000); // 增加延时确保渲染
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行滚动动画循环
|
||||||
|
*/
|
||||||
|
const runMarqueeAnimation = (containerWidth, textWidth, myId) => {
|
||||||
|
// ID 校验:如果当前ID不匹配,说明已被新动画取代,停止递归
|
||||||
|
if (myId !== currentMarqueeId.value) return;
|
||||||
|
if (!noticeInner.value) return;
|
||||||
|
|
||||||
|
// 动画的目标:移动 Inner 容器
|
||||||
|
const target = noticeInner.value;
|
||||||
|
const realScrollDistance = textWidth;
|
||||||
|
|
||||||
|
// 1. 重置位置到 0 (无感重置)
|
||||||
|
animation.transition(target, {
|
||||||
|
styles: { transform: `translateX(0)` },
|
||||||
|
duration: 0,
|
||||||
|
delay: 0
|
||||||
|
}, () => {
|
||||||
|
// 再次校验ID
|
||||||
|
if (myId !== currentMarqueeId.value) return;
|
||||||
|
|
||||||
|
// 计算时间
|
||||||
|
const speed = 50; // px/s
|
||||||
|
const duration = (realScrollDistance / speed) * 1000;
|
||||||
|
|
||||||
|
// 2. 向左滚动一个文本宽度的距离
|
||||||
|
animation.transition(target, {
|
||||||
|
styles: { transform: `translateX(-${realScrollDistance}px)` },
|
||||||
|
duration: duration,
|
||||||
|
timingFunction: 'linear',
|
||||||
|
delay: 0
|
||||||
|
}, () => {
|
||||||
|
// 3. 循环
|
||||||
|
runMarqueeAnimation(containerWidth, textWidth, myId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
.container {
|
.container {
|
||||||
|
|
@ -182,11 +426,14 @@ const setUserData = () => {
|
||||||
|
|
||||||
.content-box {
|
.content-box {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 150rpx;
|
top: 0rpx;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-box {
|
.status-box {
|
||||||
|
|
@ -215,6 +462,7 @@ const setUserData = () => {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 44px;
|
height: 44px;
|
||||||
font-size: 32rpx;
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
color: #1A1A1A;
|
color: #1A1A1A;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
|
@ -234,7 +482,7 @@ const setUserData = () => {
|
||||||
|
|
||||||
.user-box {
|
.user-box {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 0 32rpx 0;
|
margin: 24rpx 32rpx 0;
|
||||||
height: 120rpx;
|
height: 120rpx;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
@ -310,12 +558,33 @@ const setUserData = () => {
|
||||||
border-radius: 16rpx 16rpx 16rpx 16rpx;
|
border-radius: 16rpx 16rpx 16rpx 16rpx;
|
||||||
padding: 0 16rpx;
|
padding: 0 16rpx;
|
||||||
height: 64rpx;
|
height: 64rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sound-box {
|
||||||
|
height: 64rpx;
|
||||||
|
width: 50rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-content-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: row;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-inner {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notice-content {
|
.notice-content {
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #767676;
|
color: #767676;
|
||||||
margin-left: 8rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-box {
|
.group-box {
|
||||||
|
|
@ -329,12 +598,30 @@ const setUserData = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-help-box {
|
.video-help-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
background-color: #FFFFFF;
|
background-color: #FFFFFF;
|
||||||
padding: 24rpx 32rpx;
|
padding: 24rpx 32rpx;
|
||||||
border-radius: 24rpx;
|
border-radius: 24rpx;
|
||||||
margin-top: 16rpx;
|
margin-top: 16rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.video-help-item {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-help-img {
|
||||||
|
width: 96rpx;
|
||||||
|
height: 96rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-help-title {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #1A1A1A;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-box {
|
.menu-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
@ -380,8 +667,8 @@ const setUserData = () => {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 72rpx;
|
width: 68rpx;
|
||||||
height: 32rpx;
|
height: 30rpx;
|
||||||
z-index: 99;
|
z-index: 99;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -392,4 +679,17 @@ const setUserData = () => {
|
||||||
.alipay-year-bill {
|
.alipay-year-bill {
|
||||||
/* width: 100%; */
|
/* width: 100%; */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.footer-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 40rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vision-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #767676;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 486 B |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 861 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 269 B |
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 8.7 KiB |
|
|
@ -383,7 +383,6 @@ export const util = {
|
||||||
timingFunc: 'easeIn'
|
timingFunc: 'easeIn'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
console.log("状态栏设置完毕!");
|
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
uni.setNavigationBarColor({
|
uni.setNavigationBarColor({
|
||||||
frontColor: frontColor,
|
frontColor: frontColor,
|
||||||
|
|
|
||||||