From 9d4cbff7464ebfd7803c2ce53ded49d0f73fe011 Mon Sep 17 00:00:00 2001
From: longz <longzhaoz@qq.com>
Date: 星期一, 29 六月 2026 20:33:55 +0800
Subject: [PATCH] 初步调整fix
---
yuyueMiniProgram/src/pages/reviewDetail/index.vue | 318 ++++++++++++++++++++++++++--------------------------
1 files changed, 159 insertions(+), 159 deletions(-)
diff --git a/yuyueMiniProgram/src/pages/reviewDetail/index.vue b/yuyueMiniProgram/src/pages/reviewDetail/index.vue
index 2bfa685..fc44f30 100644
--- a/yuyueMiniProgram/src/pages/reviewDetail/index.vue
+++ b/yuyueMiniProgram/src/pages/reviewDetail/index.vue
@@ -99,12 +99,7 @@
const selectedAreaIds = ref<number[]>([])
const selectedAreaParentId = ref<number | null>(null)
const selectedAreaChildId = ref<number | null>(null)
-const regionColumns = ref<string[][]>([
- ['东区', '西区', 'AA区'],
- ['A部', 'B部', 'C部'],
-])
-const regionPickerIndex = ref([1, 1])
-const regionValue = ref(['西区', 'B部'])
+const activeAreaParentId = ref<number | null>(null)
const unitInput = ref('')
const unitList = ref<string[]>([])
@@ -396,24 +391,68 @@
}
function buildRegionColumns(parentIndex: number, childIndex: number) {
+ // 树形展开模式不需要此方法
+}
+
+function isAreaSelected(areaId: number) {
+ return selectedAreaIds.value.includes(areaId)
+}
+
+const activeAreaParent = computed(() => {
if (areaTree.value.length === 0) {
+ return null
+ }
+ return areaTree.value.find(item => item.id === activeAreaParentId.value) || areaTree.value[0]
+})
+
+const activeAreaChildren = computed(() => activeAreaParent.value?.children || [])
+
+function getAreaSelectableIds(parent: MiniPassAccessAreaTreeItem) {
+ const childIds = (parent.children || []).map(child => child.id)
+ return childIds.length > 0 ? childIds : [parent.id]
+}
+
+function isParentAreaSelected(parent: MiniPassAccessAreaTreeItem) {
+ const ids = getAreaSelectableIds(parent)
+ return ids.length > 0 && ids.every(id => selectedAreaIds.value.includes(id))
+}
+
+function isParentAreaPartialSelected(parent: MiniPassAccessAreaTreeItem) {
+ const ids = getAreaSelectableIds(parent)
+ return ids.some(id => selectedAreaIds.value.includes(id)) && !ids.every(id => selectedAreaIds.value.includes(id))
+}
+
+function selectActiveParent(parentId: number) {
+ activeAreaParentId.value = parentId
+}
+
+function toggleParentAreaSelection(parent: MiniPassAccessAreaTreeItem) {
+ if (isHandlerReadOnly()) {
return
}
- const safeParentIndex = Math.min(Math.max(parentIndex, 0), areaTree.value.length - 1)
- const parent = areaTree.value[safeParentIndex]
- const childOptions = parent.children && parent.children.length > 0
- ? parent.children
- : [{ id: parent.id, areaName: parent.areaName, children: [] }]
- const safeChildIndex = Math.min(Math.max(childIndex, 0), childOptions.length - 1)
- regionColumns.value = [
- areaTree.value.map(item => item.areaName),
- childOptions.map(item => item.areaName),
- ]
- regionPickerIndex.value = [safeParentIndex, safeChildIndex]
- regionValue.value = [
- regionColumns.value[0][safeParentIndex] || '',
- regionColumns.value[1][safeChildIndex] || '',
- ]
+ activeAreaParentId.value = parent.id
+ const ids = getAreaSelectableIds(parent)
+ if (isParentAreaSelected(parent)) {
+ const removeIds = new Set(ids)
+ selectedAreaIds.value = selectedAreaIds.value.filter(id => !removeIds.has(id))
+ }
+ else {
+ selectedAreaIds.value = Array.from(new Set([...selectedAreaIds.value, ...ids]))
+ }
+ syncSelectedAreaDisplay()
+}
+
+function toggleChildAreaSelection(child: MiniPassAccessAreaTreeItem) {
+ if (isHandlerReadOnly()) {
+ return
+ }
+ if (selectedAreaIds.value.includes(child.id)) {
+ selectedAreaIds.value = selectedAreaIds.value.filter(id => id !== child.id)
+ }
+ else {
+ selectedAreaIds.value = [...selectedAreaIds.value, child.id]
+ }
+ syncSelectedAreaDisplay()
}
function resolveAreaDisplayById(targetId: number) {
@@ -470,30 +509,18 @@
if (areaTree.value.length === 0) {
return
}
- let parentIndex = 0
- let childIndex = 0
- const targetId = selectedAreaIds.value[selectedAreaIds.value.length - 1]
- if (targetId) {
- areaTree.value.some((parent, pIndex) => {
- if (parent.id === targetId) {
- parentIndex = pIndex
- childIndex = 0
- selectedAreaParentId.value = parent.id
- selectedAreaChildId.value = null
- return true
+ // 自动展开已选中区域的父节点
+ areaTree.value.forEach((parent) => {
+ const hasSelectedChild = (parent.children || []).some(child => selectedAreaIds.value.includes(child.id))
+ if (hasSelectedChild || selectedAreaIds.value.includes(parent.id)) {
+ if (activeAreaParentId.value == null) {
+ activeAreaParentId.value = parent.id
}
- const cIndex = (parent.children || []).findIndex(child => child.id === targetId)
- if (cIndex >= 0) {
- parentIndex = pIndex
- childIndex = cIndex
- selectedAreaParentId.value = parent.id
- selectedAreaChildId.value = parent.children[cIndex].id
- return true
- }
- return false
- })
+ }
+ })
+ if (activeAreaParentId.value == null && areaTree.value.length > 0) {
+ activeAreaParentId.value = areaTree.value[0].id
}
- buildRegionColumns(parentIndex, childIndex)
syncSelectedAreaDisplay()
}
@@ -504,74 +531,15 @@
try {
areaTree.value = await fetchPassAccessAreaTree()
if (areaTree.value.length > 0) {
+ if (activeAreaParentId.value == null || !areaTree.value.some(parent => parent.id === activeAreaParentId.value)) {
+ activeAreaParentId.value = areaTree.value[0].id
+ }
syncRegionFromSelectedIds()
}
}
catch (error) {
uni.showToast({ title: error instanceof Error ? error.message : '加载通行区域失败', icon: 'none' })
}
-}
-
-function onRegionConfirm(e: any) {
- if (isHandlerReadOnly()) {
- return
- }
- const value = e.detail?.value || []
- if (value.length < 2 || areaTree.value.length === 0) {
- return
- }
- const parentChanged = Number(value[0]) !== regionPickerIndex.value[0]
- buildRegionColumns(Number(value[0]), parentChanged ? 0 : Number(value[1]))
-}
-
-function resolveCurrentRegionSelection() {
- if (areaTree.value.length === 0) {
- return null
- }
- const parent = areaTree.value[regionPickerIndex.value[0]]
- if (!parent) {
- return null
- }
- const childOptions = parent.children && parent.children.length > 0
- ? parent.children
- : [{ id: parent.id, areaName: parent.areaName, children: [] }]
- const child = childOptions[regionPickerIndex.value[1]]
- const pickedId = child && child.id !== parent.id ? child.id : parent.id
- const selectedNames = child && child.areaName !== parent.areaName
- ? [parent.areaName, child.areaName]
- : [parent.areaName]
- return {
- parentId: parent.id,
- childId: child?.id ?? null,
- pickedId,
- value: [selectedNames[0], selectedNames[selectedNames.length - 1]],
- }
-}
-
-const currentRegionPickedId = computed(() => resolveCurrentRegionSelection()?.pickedId ?? null)
-const isCurrentRegionSelected = computed(() => {
- const pickedId = currentRegionPickedId.value
- return pickedId != null && selectedAreaIds.value.includes(pickedId)
-})
-
-function toggleCurrentRegionSelection() {
- if (isHandlerReadOnly()) {
- return
- }
- const current = resolveCurrentRegionSelection()
- if (!current) {
- return
- }
- selectedAreaParentId.value = current.parentId
- selectedAreaChildId.value = current.childId
- regionValue.value = current.value
- if (selectedAreaIds.value.includes(current.pickedId)) {
- selectedAreaIds.value = selectedAreaIds.value.filter(item => item !== current.pickedId)
- }
- else {
- selectedAreaIds.value = [...selectedAreaIds.value, current.pickedId]
- }
- syncSelectedAreaDisplay()
}
function confirmRegionPicker() {
@@ -1284,68 +1252,71 @@
<!-- 通行区域选择器 -->
<wd-popup v-model="showRegionPicker" position="bottom" custom-style="border-radius: 24rpx 24rpx 0 0; z-index: 9999;">
- <view class="w-full bg-white rounded-t-[24rpx] flex flex-col h-[860rpx]">
+ <view class="w-full bg-white rounded-t-[24rpx] flex flex-col h-[900rpx]">
<!-- 头部:关闭图标和标题 -->
- <view class="flex items-center justify-between h-[108rpx] px-[32rpx] border-b border-solid border-[#F0F0F0] shrink-0">
- <view class="w-[48rpx] h-[48rpx] flex items-center justify-center" @click="showRegionPicker = false">
- <image src="/static/review/close@2x.png" class="w-[48rpx] h-[48rpx]" mode="aspectFit" />
- </view>
- <text class="text-[#333333] text-[32rpx] font-medium flex-1 text-center pr-[48rpx]">选择通行区域</text>
- </view>
-
- <!-- 选择器区域 -->
- <view class="flex flex-col justify-center px-[32rpx] h-[330rpx] relative shrink-0">
- <view class="absolute left-[32rpx] right-[32rpx] top-1/2 -translate-y-1/2 h-[96rpx] bg-[#F4F8FF] rounded-[8rpx] z-0"></view>
- <picker-view
- class="custom-picker-view region-picker-view relative z-10"
- :value="regionPickerIndex"
- indicator-style="height: 48px; background-color: transparent;"
- style="width: 100%; height: 192px;"
- @change="onRegionConfirm"
- >
- <picker-view-column v-for="(col, colIndex) in regionColumns" :key="colIndex">
- <view
- v-for="(item, itemIndex) in col"
- :key="itemIndex"
- class="flex items-center justify-center h-[48px] wd-picker-view-column__item"
- :class="{ 'wd-picker-view-column__item--active': regionPickerIndex[colIndex] === itemIndex }"
- >
- {{ item }}
- </view>
- </picker-view-column>
- </picker-view>
- </view>
-
- <view class="px-[32rpx] pb-[24rpx] shrink-0">
- <view
- class="w-full h-[72rpx] rounded-[36rpx] flex items-center justify-center border-[2rpx] border-solid active:opacity-80"
- :class="isCurrentRegionSelected ? 'bg-[#F0F6FF] border-[#0068FF]' : 'bg-white border-[#0068FF]'"
- @click="toggleCurrentRegionSelection"
- >
- <text class="text-[28rpx]" :class="isCurrentRegionSelected ? 'text-[#0068FF]' : 'text-[#0068FF]'">
- {{ isCurrentRegionSelected ? '已选择,点击取消' : '添加当前区域' }}
- </text>
+ <view class="relative h-[108rpx] px-[32rpx] border-b border-solid border-[#F0F0F0] shrink-0 flex items-center justify-center">
+ <text class="text-[#333333] text-[32rpx] font-medium">选择访问区域</text>
+ <view class="absolute right-[32rpx] top-[30rpx] w-[48rpx] h-[48rpx] flex items-center justify-center rounded-full bg-[#F5F7FB]" @click="showRegionPicker = false">
+ <text class="text-[#9AA4B2] text-[32rpx] leading-none">×</text>
</view>
</view>
- <view class="px-[32rpx] pb-[16rpx] shrink-0">
- <view class="flex items-center justify-between mb-[16rpx]">
- <text class="text-[#333333] text-[28rpx] font-medium">已选区域</text>
- <text class="text-[#999999] text-[24rpx]">共{{ selectedAreaIds.length }}个</text>
- </view>
- <scroll-view scroll-y class="h-[150rpx]">
- <view v-if="selectedAreaIds.length > 0" class="flex flex-wrap gap-[14rpx] pb-[16rpx]">
- <view v-for="areaId in selectedAreaIds" :key="areaId" class="flex items-center justify-center px-[24rpx] h-[56rpx] rounded-[28rpx] border-[2rpx] border-solid border-[#E5E5E5] box-border">
- <text class="text-[#666666] text-[24rpx]">{{ resolveAreaDisplayById(areaId) }}</text>
- <view class="flex items-center justify-center w-[24rpx] h-[24rpx] ml-[8rpx] active:opacity-80" @click.stop="removeSelectedArea(areaId)">
- <image src="/static/review/close.png" class="w-[24rpx] h-[24rpx]" mode="aspectFit" />
+ <!-- 左右两栏选择区域 -->
+ <view class="relative flex-1 mx-[24rpx] mt-[24rpx] rounded-[24rpx] border border-solid border-[#EDF1F7] overflow-hidden flex min-h-0">
+ <scroll-view scroll-y class="w-[350rpx] bg-white py-[12rpx] px-[12rpx] box-border">
+ <view
+ v-for="parent in areaTree"
+ :key="parent.id"
+ class="h-[78rpx] mb-[10rpx] rounded-[12rpx] px-[14rpx] flex items-center justify-between"
+ :class="activeAreaParent?.id === parent.id ? 'bg-[#EEF4FF]' : 'bg-white'"
+ @click="selectActiveParent(parent.id)"
+ >
+ <view class="flex items-center min-w-0 flex-1" @click.stop="toggleParentAreaSelection(parent)">
+ <view
+ class="w-[34rpx] h-[34rpx] rounded-[8rpx] border-[2rpx] border-solid flex items-center justify-center mr-[14rpx] shrink-0"
+ :class="isParentAreaSelected(parent) || isParentAreaPartialSelected(parent) ? 'bg-[#2F74FF] border-[#2F74FF]' : 'bg-white border-[#E2E8F0]'"
+ >
+ <view v-if="isParentAreaSelected(parent)" class="checkbox-icon"></view>
+ <view v-else-if="isParentAreaPartialSelected(parent)" class="w-[16rpx] h-[4rpx] bg-white rounded-full"></view>
</view>
+ <text class="text-[26rpx] font-medium truncate" :class="isParentAreaSelected(parent) || isParentAreaPartialSelected(parent) ? 'text-[#2F74FF]' : 'text-[#4A5568]'">{{ parent.areaName }}</text>
</view>
- </view>
- <view v-else class="h-[96rpx] flex items-center justify-center">
- <text class="text-[#B3B3B3] text-[24rpx]">请选择至少一个通行区域</text>
+ <text class="text-[30rpx]" :class="activeAreaParent?.id === parent.id ? 'text-[#2F74FF]' : 'text-[#B8C0CC]'">›</text>
</view>
</scroll-view>
+
+ <scroll-view scroll-y class="flex-1 bg-white py-[12rpx] px-[12rpx] box-border border-l border-solid border-[#F2F5FA]">
+ <view
+ v-for="child in activeAreaChildren"
+ :key="child.id"
+ class="h-[78rpx] mb-[12rpx] rounded-[12rpx] px-[14rpx] flex items-center bg-[#EEF4FF]"
+ @click="toggleChildAreaSelection(child)"
+ >
+ <view
+ class="w-[34rpx] h-[34rpx] rounded-[8rpx] border-[2rpx] border-solid flex items-center justify-center mr-[14rpx] shrink-0"
+ :class="isAreaSelected(child.id) ? 'bg-[#2F74FF] border-[#2F74FF]' : 'bg-white border-[#E2E8F0]'"
+ >
+ <view v-if="isAreaSelected(child.id)" class="checkbox-icon"></view>
+ </view>
+ <text class="text-[26rpx] font-medium truncate" :class="isAreaSelected(child.id) ? 'text-[#2F74FF]' : 'text-[#4A5568]'">{{ child.areaName }}</text>
+ </view>
+
+ <view v-if="activeAreaParent && activeAreaChildren.length === 0" class="h-[180rpx] flex items-center justify-center">
+ <text class="text-[#B3B3B3] text-[26rpx]">当前区域无子区域</text>
+ </view>
+ </scroll-view>
+
+ <view v-if="areaTree.length === 0" class="absolute inset-0 bg-white flex items-center justify-center">
+ <text class="text-[#B3B3B3] text-[28rpx]">暂无通行区域</text>
+ </view>
+ </view>
+
+ <!-- 已选区域统计 -->
+ <view class="px-[32rpx] py-[16rpx] border-t border-solid border-[#F0F0F0] shrink-0">
+ <view class="flex items-center justify-between">
+ <text class="text-[#333333] text-[28rpx]">已选择</text>
+ <text class="text-[#0068FF] text-[28rpx] font-medium">{{ selectedAreaIds.length }} 个区域</text>
+ </view>
</view>
<!-- 底部确认按钮 -->
@@ -1459,6 +1430,35 @@
border-radius: 28rpx;
background: linear-gradient(180deg, #FFFFFF 0%, rgba(255, 255, 255, 0) 69%);
}
+
+/* 复选框勾选图标 - 使用CSS绘制 */
+.checkbox-icon {
+ width: 16rpx;
+ height: 10rpx;
+ border-left: 3rpx solid #FFFFFF;
+ border-bottom: 3rpx solid #FFFFFF;
+ transform: rotate(-45deg);
+ margin-top: -4rpx;
+}
+
+/* 箭头图标 - 使用CSS绘制 */
+.arrow-icon {
+ width: 16rpx;
+ height: 16rpx;
+ border-top: 3rpx solid #666666;
+ border-right: 3rpx solid #666666;
+ transition: transform 0.3s ease;
+}
+
+.arrow-down {
+ transform: rotate(135deg);
+ margin-top: -6rpx;
+}
+
+.arrow-up {
+ transform: rotate(-45deg);
+ margin-bottom: -6rpx;
+}
</style>
<style>
--
Gitblit v1.7.1