Files
threeonecheck_web/components/AreaFormPopup.vue

283 lines
5.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="popup-mask" v-if="visible" @click="handleClose">
<view class="popup-content" @click.stop>
<view class="popup-header">
<view class="popup-title text-bold">{{ isEdit ? '编辑区域' : '新增区域' }}</view>
<view class="popup-close" @click="handleClose">×</view>
</view>
<view class="popup-body">
<!-- 区域名称 -->
<view class="flex margin-bottom-sm">
<view>区域名称</view>
<view class="text-red">*</view>
</view>
<input
class="form-input"
v-model="formData.name"
placeholder="请输入区域名称"
/>
<!-- 区域颜色 -->
<view class="flex margin-bottom-sm margin-top">
<view>区域颜色</view>
<view class="text-red">*</view>
</view>
<view class="flex align-center margin-bottom-sm">
<view class="color-preview" :style="{ backgroundColor: formData.color }"></view>
<text class="margin-left-sm text-gray">{{ selectedColorLabel }}</text>
</view>
<view class="margin-bottom-sm text-gray">请选择颜色</view>
<view class="color-grid">
<view
v-for="item in presetColors"
:key="item.value"
class="color-option"
@click="selectColor(item.value)"
>
<view
class="color-item"
:class="{ 'color-item-active': formData.color === item.value }"
:style="{ backgroundColor: item.value }"
></view>
<text class="color-label">{{ item.name }}</text>
</view>
</view>
</view>
<view class="popup-footer">
<button class="btn-cancel" @click="handleClose">取消</button>
<button class="btn-confirm bg-blue" @click="handleSubmit" :loading="loading">确定</button>
</view>
</view>
</view>
</template>
<script setup>
import { reactive, watch, computed } from 'vue';
const props = defineProps({
visible: {
type: Boolean,
default: false
},
isEdit: {
type: Boolean,
default: false
},
editData: {
type: Object,
default: () => ({})
},
loading: {
type: Boolean,
default: false
}
});
const emit = defineEmits(['update:visible', 'submit', 'close']);
// 表单数据
const formData = reactive({
name: '',
color: '#D92121'
});
// 可选颜色(固定四种)
const presetColors = [
{ name: '红色', value: '#D92121' },
{ name: '橙色', value: '#FF8822' },
{ name: '黄色', value: '#FFCC00' },
{ name: '蓝色', value: '#165DFF' }
];
const presetColorValues = presetColors.map((item) => item.value);
const selectedColorLabel = computed(() => {
const found = presetColors.find((item) => item.value === formData.color);
return found ? `${found.name} ${found.value}` : formData.color;
});
const normalizeColor = (color) => {
if (!color) return presetColors[0].value;
const upper = String(color).toUpperCase();
const matched = presetColorValues.find((v) => v.toUpperCase() === upper);
return matched || presetColors[0].value;
};
// 监听 editData 变化,填充表单
watch(() => props.editData, (newVal) => {
if (newVal && Object.keys(newVal).length > 0) {
formData.name = newVal.name || '';
formData.color = normalizeColor(newVal.color);
}
}, { immediate: true, deep: true });
// 监听弹窗关闭,重置表单
watch(() => props.visible, (newVal) => {
if (!newVal) {
resetForm();
}
});
// 选择预设颜色
const selectColor = (color) => {
formData.color = color;
};
// 重置表单
const resetForm = () => {
formData.name = '';
formData.color = '#D92121';
};
// 关闭弹窗
const handleClose = () => {
emit('update:visible', false);
emit('close');
};
// 提交表单
const handleSubmit = () => {
// 表单验证
if (!formData.name) {
uni.showToast({ title: '请输入区域名称', icon: 'none' });
return;
}
if (!presetColorValues.includes(formData.color)) {
uni.showToast({ title: '请从预设颜色中选择', icon: 'none' });
return;
}
emit('submit', {
name: formData.name,
color: formData.color
});
};
</script>
<style lang="scss" scoped>
// 弹窗遮罩
.popup-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 999;
}
// 弹窗内容
.popup-content {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #eee;
}
.popup-title {
font-size: 32rpx;
}
.popup-close {
font-size: 40rpx;
color: #999;
}
.popup-body {
padding: 30rpx;
}
.popup-footer {
display: flex;
padding: 20rpx 30rpx 30rpx;
button {
flex: 1;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
font-size: 30rpx;
margin: 0 10rpx;
&::after {
border: none;
}
}
.btn-cancel {
background: #f5f5f5;
color: #666;
}
.btn-confirm {
color: #fff;
}
}
// 表单输入框
.form-input {
width: 100%;
height: 70rpx;
padding: 0 20rpx;
border: 2rpx solid #dadbde;
border-radius: 8rpx;
font-size: 28rpx;
box-sizing: border-box;
}
// 颜色预览
.color-preview {
width: 70rpx;
height: 70rpx;
border-radius: 8rpx;
flex-shrink: 0;
border: 2rpx solid #e5e5e5;
}
// 预设颜色
.color-grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 24rpx 0;
}
.color-option {
width: 25%;
display: flex;
flex-direction: column;
align-items: center;
}
.color-item {
width: 80rpx;
height: 80rpx;
border-radius: 12rpx;
border: 4rpx solid transparent;
box-sizing: border-box;
}
.color-label {
margin-top: 12rpx;
font-size: 24rpx;
color: #666;
}
.color-item-active {
border-color: #333;
box-shadow: 0 0 0 4rpx rgba(0, 0, 0, 0.08);
}
</style>