From 92230c9a97dc9ce9df3313d11d26999c04bb6b26 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 15 七月 2025 13:12:48 +0800
Subject: [PATCH] 项目初始化

---
 src/components/u-city-select/u-city-select.vue |  265 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 265 insertions(+), 0 deletions(-)

diff --git a/src/components/u-city-select/u-city-select.vue b/src/components/u-city-select/u-city-select.vue
new file mode 100644
index 0000000..6f4eef7
--- /dev/null
+++ b/src/components/u-city-select/u-city-select.vue
@@ -0,0 +1,265 @@
+<template>
+	<u-popup :show="modelValue" mode="bottom" :popup="false" :mask="true" :closeable="true"
+		:safe-area-inset-bottom="true" close-icon-color="#ffffff" :z-index="uZIndex" :maskCloseAble="maskCloseAble"
+		@close="close">
+		<u-tabs v-if="modelValue" :list="genTabsList" :scrollable="true" :current="tabsIndex" @change="tabsChange"
+			ref="tabs" />
+		<view class="area-box">
+			<view class="u-flex" :class="{ 'change': isChange }">
+				<view class="area-item">
+					<view class="u-padding-10 u-bg-gray" style="height: 100%;">
+						<scroll-view :scroll-y="true" style="height: 100%">
+							<u-cell-group>
+								<u-cell v-for="(item, index) in provinces" :title="item.label" :arrow="false"
+									:index="index" :key="index" @click="provinceChange(index)">
+									<template v-slot:right-icon>
+										<u-icon v-if="isChooseP && province === index" size="17"
+											name="checkbox-mark"></u-icon>
+									</template>
+								</u-cell>
+							</u-cell-group>
+						</scroll-view>
+					</view>
+				</view>
+				<view class="area-item">
+					<view class="u-padding-10 u-bg-gray" style="height: 100%;">
+						<scroll-view :scroll-y="true" style="height: 100%">
+							<u-cell-group v-if="isChooseP">
+								<u-cell v-for="(item, index) in citys" :title="item.label" :arrow="false" :index="index"
+									:key="index" @click="cityChange(index)">
+									<template v-slot:right-icon>
+										<u-icon v-if="isChooseC && city === index" size="17"
+											name="checkbox-mark"></u-icon>
+									</template>
+								</u-cell>
+							</u-cell-group>
+						</scroll-view>
+					</view>
+				</view>
+				<view class="area-item">
+					<view class="u-padding-10 u-bg-gray" style="height: 100%;">
+						<scroll-view :scroll-y="true" style="height: 100%">
+							<u-cell-group v-if="isChooseC">
+								<u-cell v-for="(item, index) in areas" :title="item.label" :arrow="false" :index="index"
+									:key="index" @click="areaChange(index)">
+									<template v-slot:right-icon>
+										<u-icon v-if="isChooseA && area === index" size="17"
+											name="checkbox-mark"></u-icon>
+									</template>
+								</u-cell>
+							</u-cell-group>
+						</scroll-view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</u-popup>
+</template>
+
+<script setup lang="ts">
+import { ref, computed, onMounted, PropType } from 'vue';
+import provincesSource from "./province.js";
+import citysSource from "./city.js";
+import areasSource from "./area.js";
+
+// 瀹氫箟鎺ュ彛
+interface Region {
+	label: string;
+	value: string;
+}
+
+interface CitySelectResult {
+	province: Region;
+	city: Region;
+	area: Region;
+}
+
+interface TabItem {
+	name: string;
+}
+
+// Props 瀹氫箟
+const props = defineProps({
+	// 閫氳繃鍙屽悜缁戝畾鎺у埗缁勪欢鐨勫脊鍑轰笌鏀惰捣
+	modelValue: {
+		type: Boolean,
+		default: false
+	},
+	// 榛樿鏄剧ず鐨勫湴鍖猴紝鍙紶绫讳技["娌冲寳鐪�", "绉︾殗宀涘競", "鍖楁埓娌冲尯"]
+	defaultRegion: {
+		type: Array as PropType<string[]>,
+		default: () => []
+	},
+	// 榛樿鏄剧ず鍦板尯鐨勭紪鐮侊紝defaultRegion鍜宎reaCode鍚屾椂瀛樺湪锛宎reaCode浼樺厛锛屽彲浼犵被浼糩"13", "1303", "130304"]
+	areaCode: {
+		type: Array as PropType<string[]>,
+		default: () => []
+	},
+	// 鏄惁鍏佽閫氳繃鐐瑰嚮閬僵鍏抽棴Picker
+	maskCloseAble: {
+		type: Boolean,
+		default: true
+	},
+	// 寮瑰嚭鐨剒-index鍊�
+	zIndex: {
+		type: [String, Number],
+		default: 0
+	}
+});
+
+// 浜嬩欢瀹氫箟
+const emit = defineEmits<{
+	(e: 'update:modelValue', value: boolean): void;
+	(e: 'close'): void;
+	(e: 'city-change', result: CitySelectResult): void;
+}>();
+
+const cityValue = ref("");
+const isChooseP = ref(false); // 鏄惁宸茬粡閫夋嫨浜嗙渷
+const province = ref(0); // 鐪佺骇涓嬫爣
+const provinces = ref<Region[]>(provincesSource);
+const isChooseC = ref(false); // 鏄惁宸茬粡閫夋嫨浜嗗競
+const city = ref(0); // 甯傜骇涓嬫爣
+const citys = ref<Region[]>(citysSource[0]);
+const isChooseA = ref(false); // 鏄惁宸茬粡閫夋嫨浜嗗尯
+const area = ref(0); // 鍖虹骇涓嬫爣
+const areas = ref<Region[]>(areasSource[0][0]);
+const tabsIndex = ref(0);
+const tabs = ref();
+
+// 璁$畻灞炴��
+const isChange = computed(() => {
+	return tabsIndex.value > 1;
+});
+
+const genTabsList = computed((): TabItem[] => {
+	let tabsList: TabItem[] = [{
+		name: "璇烽�夋嫨"
+	}];
+
+	if (isChooseP.value) {
+		tabsList[0].name = provinces.value[province.value].label;
+		tabsList[1] = {
+			name: "璇烽�夋嫨"
+		};
+	}
+
+	if (isChooseC.value) {
+		tabsList[1].name = citys.value[city.value].label;
+		tabsList[2] = {
+			name: "璇烽�夋嫨"
+		};
+	}
+
+	if (isChooseA.value) {
+		tabsList[2].name = areas.value[area.value].label;
+	}
+
+	return tabsList;
+});
+
+const uZIndex = computed(() => {
+	// 濡傛灉鐢ㄦ埛鏈変紶閫抸-index鍊硷紝浼樺厛浣跨敤
+	return props.zIndex ? props.zIndex : 1075; // 鍋囪$u.zIndex.popup涓�1075
+});
+
+// 鏂规硶
+const setProvince = (label = "", value = "") => {
+	provinces.value.map((v, k) => {
+		if (value ? v.value == value : v.label == label) {
+			provinceChange(k);
+		}
+	});
+};
+
+const setCity = (label = "", value = "") => {
+	citys.value.map((v, k) => {
+		if (value ? v.value == value : v.label == label) {
+			cityChange(k);
+		}
+	});
+};
+
+const setArea = (label = "", value = "") => {
+	areas.value.map((v, k) => {
+		if (value ? v.value == value : v.label == label) {
+			isChooseA.value = true;
+			area.value = k;
+		}
+	});
+};
+
+const close = () => {
+	emit('update:modelValue', false);
+	emit('close');
+};
+
+const tabsChange = (value: { index: number }) => {
+	tabsIndex.value = value.index;
+};
+
+const provinceChange = (index: number) => {
+	isChooseP.value = true;
+	isChooseC.value = false;
+	isChooseA.value = false;
+	province.value = index;
+	citys.value = citysSource[index];
+	tabsIndex.value = 1;
+};
+
+const cityChange = (index: number) => {
+	isChooseC.value = true;
+	isChooseA.value = false;
+	city.value = index;
+	areas.value = areasSource[province.value][index];
+	tabsIndex.value = 2;
+};
+
+const areaChange = (index: number) => {
+	isChooseA.value = true;
+	area.value = index;
+	const result: CitySelectResult = {
+		province: provinces.value[province.value],
+		city: citys.value[city.value],
+		area: areas.value[area.value]
+	};
+	emit('city-change', result);
+	close();
+};
+
+// 鐢熷懡鍛ㄦ湡閽╁瓙
+onMounted(() => {
+	if (props.areaCode.length == 3) {
+		setProvince("", props.areaCode[0]);
+		setCity("", props.areaCode[1]);
+		setArea("", props.areaCode[2]);
+	} else if (props.defaultRegion.length == 3) {
+		setProvince(props.defaultRegion[0], "");
+		setCity(props.defaultRegion[1], "");
+		setArea(props.defaultRegion[2], "");
+	}
+});
+</script>
+
+<style lang="scss">
+.area-box {
+	width: 100%;
+	overflow: hidden;
+	height: 800rpx;
+
+	>view {
+		width: 150%;
+		transition: transform 0.3s ease-in-out 0s;
+		transform: translateX(0);
+
+		&.change {
+			transform: translateX(-33.3333333%);
+		}
+	}
+
+	.area-item {
+		width: 33.3333333%;
+		height: 800rpx;
+	}
+}
+</style>
\ No newline at end of file

--
Gitblit v1.9.3