290 lines
8.9 KiB
Vue
290 lines
8.9 KiB
Vue
<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
|
|
} 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> |