diff --git a/.env.development b/.env.development index 00c0ba4..8798391 100644 --- a/.env.development +++ b/.env.development @@ -1,5 +1,5 @@ NODE_ENV= development VITE_HTTP_BASE_URL = http://10.39.13.78:8002/api/ -# VITE_HTTP_BASE_URL = https://test-weapp-api.linyikj.com.cn/api/ +# VITE_HTTP_BASE_URL = http://test-weapp-api.linyikj.com.cn/api/ # VITE_HTTP_BASE_URL = https://weapp-api.linyikj.com.cn/api/ VITE_ACCESS_TOKEN_KEY= 'ACCESS_TOKEN_CUSTOMER' \ No newline at end of file diff --git a/ci/project.config.json b/ci/project.config.json index 9689888..2954887 100644 --- a/ci/project.config.json +++ b/ci/project.config.json @@ -1,3 +1,3 @@ { - "version": "0.0.95" + "version": "0.0.108" } \ No newline at end of file diff --git a/gencode.json b/gencode.json index 5e4739f..cc33bc3 100644 --- a/gencode.json +++ b/gencode.json @@ -1,5 +1,5 @@ { - "url": "http://10.39.13.78:8001/api/docs/openapi", + "url": "http://10.39.13.78:8002/api/docs/openapi", "module": "Customer", "outPath": "./src/gen/", "apis": { diff --git a/src/App.vue b/src/App.vue index 99bc363..08a990a 100644 --- a/src/App.vue +++ b/src/App.vue @@ -8,6 +8,7 @@ const auth = useWeAppAuthStore() const globalData = { //全局变量 selectProject: {}, + address_city:"", //当前默认角色 selectedOrg: {}, selectedIndex: 0, @@ -17,12 +18,16 @@ const globalData = { onLaunch(async () => { const app = getCurrentInstance() await auth.login(app) + auth.SetAddressCity() console.log('App Launch') // 检查更新 // #ifdef MP-WEIXIN CheckUpdate() // #endif }) + + + onShow(() => {}) onHide(() => { console.log('App Hide') diff --git a/src/INDEX/address_city/index.vue b/src/INDEX/address_city/index.vue new file mode 100644 index 0000000..128e9cf --- /dev/null +++ b/src/INDEX/address_city/index.vue @@ -0,0 +1,102 @@ + + + + diff --git a/src/INDEX/address_city/method.ts b/src/INDEX/address_city/method.ts new file mode 100644 index 0000000..ba6c9ea --- /dev/null +++ b/src/INDEX/address_city/method.ts @@ -0,0 +1,85 @@ +import useModel, { City } from './model' +import { Apis } from '@/gen/Apis' +import { getApiLoading } from '@/common/libraries/apiLoading' +import { useWeAppAuthStore } from '@/common' +import config from '@/common/libraries/config' +const auth = useWeAppAuthStore() +/** + * 搜索输入处理 + */ +const onSearchInput = (e: any) => { + useModel.searchKeyword.value = e.detail.value +} + +/** + * 清空搜索 + */ +const clearSearch = () => { + useModel.searchKeyword.value = '' +} + +/** + * 选择城市 + */ +const selectCity = (city: City) => { + console.log('选择城市:', city) + // TODO: 返回上一页并传递选中的城市 + // 可以通过事件总线或 uni.$emit 传递数据 + auth.data.address_city = {city: city?.name || '',...city} +// uni.$emit('citySelected', city) + uni.navigateBack({ + delta: 1 + }) +} + +/** + * 滚动到指定字母区域 + */ +const scrollToSection = (letter: string) => { + useModel.scrollToId.value = `section_${letter}` +} + +/** + * 获取定位 + */ +const getLocation = () => { + // TODO: 实际项目中调用定位API + uni.getLocation({ + type: 'wgs84', + success: (res) => { + console.log('当前位置:', res) + // 根据经纬度获取城市名称 + // 可以调用逆地理编码API获取城市信息 + // currentCity.value = { name: '深圳', pinyin: 'shenzhen', code: '440300' } + }, + fail: (err) => { + console.log('获取定位失败:', err) + uni.showToast({ + title: '获取定位失败', + icon: 'none' + }) + } + }) +} + +/** + * 获取城市列表(从接口获取) + */ +const getCityList = () => { + // TODO: 调用接口获取城市列表 + // const res = await Apis.City.List() + // useModel.allCities.value = res.data + getApiLoading(Apis.Asset.AssetHouses.GetCities, {app_id: config?.WxAppId}).then(res => { + useModel.openCities.value = res.data || [] + console.log(res) + }) +} + +export default { + onSearchInput, + clearSearch, + selectCity, + scrollToSection, + getLocation, + getCityList +} diff --git a/src/INDEX/address_city/model.ts b/src/INDEX/address_city/model.ts new file mode 100644 index 0000000..f228dce --- /dev/null +++ b/src/INDEX/address_city/model.ts @@ -0,0 +1,144 @@ +import { ref, computed } from 'vue' + +// 城市数据类型 +export interface City { + name?: string + pinyin?: string + code?: string + city?: string + city_id?: number +} + +// 搜索关键词 +export const searchKeyword = ref('') + +// 当前定位城市 +export const currentCity = ref(null) + +// 滚动定位ID +export const scrollToId = ref('') + +// 热门城市列表 +export const hotCities = ref([ + { name: '北京', pinyin: 'beijing', code: '110000' }, + { name: '上海', pinyin: 'shanghai', code: '310000' }, + { name: '广州', pinyin: 'guangzhou', code: '440100' }, + { name: '深圳', pinyin: 'shenzhen', code: '440300' }, + { name: '杭州', pinyin: 'hangzhou', code: '330100' }, + { name: '成都', pinyin: 'chengdu', code: '510100' }, + { name: '重庆', pinyin: 'chongqing', code: '500000' }, + { name: '武汉', pinyin: 'wuhan', code: '420100' } +]) + +//已开通城市 +export const openCities = ref([]) + + +// 所有城市数据(示例数据,实际应从接口获取) +export const allCities = ref([ + // A-G + { name: '安庆', pinyin: 'anqing' }, + { name: '蚌埠', pinyin: 'bengbu' }, + { name: '包头', pinyin: 'baotou' }, + { name: '北京', pinyin: 'beijing', code: '110000' }, + { name: '常州', pinyin: 'changzhou' }, + { name: '成都', pinyin: 'chengdu', code: '510100' }, + { name: '重庆', pinyin: 'chongqing', code: '500000' }, + { name: '大连', pinyin: 'dalian' }, + { name: '东莞', pinyin: 'dongguan' }, + // F + { name: '佛山', pinyin: 'foshan' }, + { name: '福州', pinyin: 'fuzhou' }, + // G + { name: '广州', pinyin: 'guangzhou', code: '440100' }, + { name: '贵阳', pinyin: 'guiyang' }, + // H + { name: '杭州', pinyin: 'hangzhou', code: '330100' }, + { name: '哈尔滨', pinyin: 'haerbin' }, + { name: '合肥', pinyin: 'hefei' }, + { name: '湖州', pinyin: 'huzhou' }, + // J + { name: '嘉兴', pinyin: 'jiaxing' }, + { name: '金华', pinyin: 'jinhua' }, + { name: '济南', pinyin: 'jinan' }, + // K + { name: '昆明', pinyin: 'kunming' }, + // L + { name: '兰州', pinyin: 'lanzhou' }, + // N + { name: '南昌', pinyin: 'nanchang' }, + { name: '南京', pinyin: 'nanjing' }, + { name: '南宁', pinyin: 'nanning' }, + { name: '宁波', pinyin: 'ningbo' }, + // Q + { name: '青岛', pinyin: 'qingdao' }, + // S + { name: '上海', pinyin: 'shanghai', code: '310000' }, + { name: '深圳', pinyin: 'shenzhen', code: '440300' }, + { name: '沈阳', pinyin: 'shenyang' }, + { name: '石家庄', pinyin: 'shijiazhuang' }, + { name: '苏州', pinyin: 'suzhou' }, + // T + { name: '唐山', pinyin: 'tangshan' }, + { name: '天津', pinyin: 'tianjin' }, + // W + { name: '潍坊', pinyin: 'weifang' }, + { name: '温州', pinyin: 'wenzhou' }, + { name: '武汉', pinyin: 'wuhan', code: '420100' }, + { name: '无锡', pinyin: 'wuxi' }, + // X + { name: '厦门', pinyin: 'xiamen' }, + { name: '西安', pinyin: 'xian' }, + // Y + { name: '烟台', pinyin: 'yantai' }, + { name: '扬州', pinyin: 'yangzhou' }, + { name: '宜昌', pinyin: 'yichang' }, + // Z + { name: '郑州', pinyin: 'zhengzhou' }, + { name: '珠海', pinyin: 'zhuhai' } +]) + +// 搜索结果 +export const searchResults = computed(() => { + if (!searchKeyword.value) return [] + const keyword = searchKeyword.value.toLowerCase() + return openCities.value.filter((city:any) => { + return city.city?.includes(keyword) + }) +}) + +// 索引字母列表 +export const indexLetters = computed(() => { + return Object.keys(cityGroups.value).sort() +}) + +// 城市按首字母分组 +export const cityGroups = computed(() => { + const groups: Record = {} + allCities.value.forEach((city:any) => { + const letter = getPinyinFirstLetter(city?.pinyin || city?.name) + if (!groups[letter]) { + groups[letter] = [] + } + groups[letter].push(city) + }) + return groups +}) + +// 获取拼音首字母(简化版,实际应使用拼音库) +const getPinyinFirstLetter = (str: string) => { + const firstChar = str.charAt(0).toUpperCase() + return firstChar +} + +export default { + searchKeyword, + currentCity, + scrollToId, + hotCities, + allCities, + searchResults, + indexLetters, + cityGroups, + openCities +} diff --git a/src/INDEX/address_city/style.scss b/src/INDEX/address_city/style.scss new file mode 100644 index 0000000..08ee0cf --- /dev/null +++ b/src/INDEX/address_city/style.scss @@ -0,0 +1,202 @@ +.city-selector { + width: 100%; + height: 100vh; + display: flex; + flex-direction: column; + background-color: #f5f5f5; + + // 搜索栏 + .search-bar { + background-color: #fff; + padding: 20rpx 30rpx; + position: sticky; + top: 0; + z-index: 100; + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); + + .search-input-wrapper { + display: flex; + align-items: center; + .search-icon { + width: 32rpx; + height: 32rpx; + margin-right: 16rpx; + } + + .search-input { + flex: 1; + font-size: 28rpx; + color: #333; + height: 100%; + } + + .search-placeholder { + color: #999; + } + + .clear-icon { + width: 32rpx; + height: 32rpx; + margin-left: 16rpx; + } + } + } + + // 搜索结果 + .search-results { + flex: 1; + overflow: hidden; + background-color: #fff; + + .results-scroll { + height: 100%; + } + } + + // 空状态 + .empty-result { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 60rpx 0; + + .empty-icon { + width: 200rpx; + height: 200rpx; + margin-bottom: 30rpx; + opacity: 0.5; + } + + .empty-text { + font-size: 28rpx; + color: #999; + } + } + + // 城市列表容器 + .city-list-container { + flex: 1; + display: flex; + position: relative; + overflow: hidden; + + .city-scroll { + flex: 1; + height: 100%; + } + + // 右侧字母索引 + .index-bar { + position: absolute; + right: 10rpx; + top: 50%; + transform: translateY(-50%); + display: flex; + flex-direction: column; + align-items: center; + background-color: rgba(255, 255, 255, 0.9); + border-radius: 40rpx; + padding: 20rpx 10rpx; + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); + + .index-item { + font-size: 22rpx; + color: #666; + padding: 6rpx 10rpx; + font-weight: 500; + } + } + } + + // 城市分组 + .city-section { + background-color: #fff; + margin-bottom: 20rpx; + + .section-title { + padding: 20rpx 30rpx; + font-size: 26rpx; + color: #999; + background-color: #f5f5f5; + font-weight: 500; + } + } + + // 当前定位城市 + .current-city { + display: flex; + align-items: center; + padding: 30rpx; + + .location-icon { + width: 32rpx; + height: 32rpx; + margin-right: 16rpx; + } + + .city-name { + color: #0082FA; + padding-left:5rpx; + } + } + + // 热门城市网格 + .hot-cities-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 20rpx; + padding: 20rpx 30rpx 30rpx; + + .hot-city-item { + display: flex; + align-items: center; + justify-content: center; + height: 72rpx; + background-color: #f5f5f5; + border-radius: 12rpx; + font-size: 28rpx; + color: #333; + text-align: center; + padding: 0 10rpx; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + &:active { + background-color: #e8e8e8; + } + } + } + + // 城市列表项 + .city-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: 30rpx; + border-bottom: 1rpx solid #f0f0f0; + transition: background-color 0.2s; + + &:last-child { + border-bottom: none; + } + + &:active { + background-color: #f8f8f8; + } + + .city-name { + font-size: 30rpx; + color: #333; + flex: 1; + } + + .city-pinyin { + font-size: 24rpx; + color: #999; + margin-left: 20rpx; + } + } +} diff --git a/src/ME/decoration/add/index.vue b/src/ME/decoration/add/index.vue new file mode 100644 index 0000000..b8ca422 --- /dev/null +++ b/src/ME/decoration/add/index.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/src/ME/decoration/add/method.ts b/src/ME/decoration/add/method.ts new file mode 100644 index 0000000..09ca6c8 --- /dev/null +++ b/src/ME/decoration/add/method.ts @@ -0,0 +1,71 @@ +import { Apis } from '@/gen/Apis' +import { getApiLoading } from '@/common/libraries/apiLoading' +import userLoginStatus from '@/common/libraries/userUserLogin' +import { showToastBack, showToast } from '@/common/libraries/naviHelper' +import { useWeAppAuthStore, useWorkStore } from '@/common' +import useModel from './model' +const work = useWorkStore() +const auth = useWeAppAuthStore() +const getList = () => { + getApiLoading(Apis.Activity.ActivityEnrolls.List, useModel?.formData?.value).then(res => { + useModel.listData.value = [...useModel.listData.value, ...res.data] + useModel.metaData.value = res.meta + console.log(res) + }) +} + +export default { + getList, + init() { + if (work?.selectWorkHouse?.asset_house) { + useModel.formData.value = { + ...useModel.formData.value, + asset_houses_id: work?.selectWorkHouse?.asset_house?.id, + full_name: work?.selectWorkHouse?.asset_house?.full_name + } + } else { + useModel.formData.value = { + ...useModel.formData.value, + asset_houses_id: auth?.data?.selected_house?.id, + full_name: auth?.data?.selected_house?.full_name + } + } + }, + loadMore(page: number) { + useModel.formData.value.page = page + this.getList() + }, + handleTabsChange(idx: number, res: any) { + useModel.currentTabs.value = idx + useModel.formData.value = { + page: 1, + status: res?.value + } + useModel.listData.value = [] + getList() + console.log(idx, 'e') + }, + handleToSelectHouse() { + uni.navigateTo({ + url: '/INDEX/asset_houses/index?type=work_add' + }) + }, + handleSubmit() { + let data = useModel?.formData?.value + if (!data?.asset_houses_id) { + return showToast('请选择房屋!') + } + if (!data?.type) { + return showToast('请选择装修类型!') + } + if (!data?.process_type) { + return showToast('请选择办理类型!') + } + getApiLoading(Apis.Renovation.RenovationApplies.Store, useModel?.formData?.value).then(res => { + uni.redirectTo({ + url: `/ME/decoration/update/index?id=${res.data.id}` + }) + console.log(res) + }) + } +} diff --git a/src/ME/decoration/add/model.ts b/src/ME/decoration/add/model.ts new file mode 100644 index 0000000..12c044f --- /dev/null +++ b/src/ME/decoration/add/model.ts @@ -0,0 +1,7 @@ +import { reactive, ref } from 'vue' +export default { + listData: ref([]), + formData: ref({}), + metaData: ref({}), + currentTabs: ref(0) +} diff --git a/src/ME/decoration/add/style.scss b/src/ME/decoration/add/style.scss new file mode 100644 index 0000000..0493562 --- /dev/null +++ b/src/ME/decoration/add/style.scss @@ -0,0 +1,3 @@ +page { + background-color: #f8f8f8; +} diff --git a/src/ME/decoration/add_worker/index.vue b/src/ME/decoration/add_worker/index.vue new file mode 100644 index 0000000..50b0738 --- /dev/null +++ b/src/ME/decoration/add_worker/index.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/src/ME/decoration/add_worker/method.ts b/src/ME/decoration/add_worker/method.ts new file mode 100644 index 0000000..c31ee4f --- /dev/null +++ b/src/ME/decoration/add_worker/method.ts @@ -0,0 +1,57 @@ +import { Apis } from '@/gen/Apis' +import { getApiLoading } from '@/common/libraries/apiLoading' +import userLoginStatus from '@/common/libraries/userUserLogin' +import { showToastBack, showToast } from '@/common/libraries/naviHelper' +import { useWeAppAuthStore, useWorkStore } from '@/common' +import useModel from './model' +const work = useWorkStore() +const auth = useWeAppAuthStore() + +export default { + init() { + useModel.formData.value = { + ...useModel.formData.value, + // worker_phone: auth?.data?.user?.phone || useModel.formData.value?.worker_phone || '', + worker_name: auth?.data?.user?.name || useModel.formData.value?.worker_name || '' + } + }, + handleSubmit() { + let data = useModel?.formData?.value + if (!userLoginStatus?.onBindPhone()) { + return false + } + if (!data?.worker_name) { + return showToast('请设置工人姓名!') + } + if (!data?.worker_phone) { + return showToast('请设置工人手机号!') + } + if (!data?.card_type) { + return showToast('请选择工人证件类型!') + } + if (!data?.id_card) { + return showToast('请设置工人证件号!') + } + if (!data?.card_front?.length || !data?.card_back?.length) { + return showToast('请上传工人证件照片!') + } + if (!data?.worker_photo?.length) { + return showToast('请上传工人照片!') + } + if (!data?.valid_from || !data?.valid_to) { + return showToast('请设置通行有效期!') + } + getApiLoading(Apis.Renovation.RenovationWorkers.Store, useModel?.formData?.value).then(res => { + if (useModel?.formData?.value?.type === 'share') { + showToast('提交成功!', () => { + uni.switchTab({ + url: '/pages/index/index' + }) + }) + } else { + showToastBack('提交成功!', 1, true) + } + console.log(res) + }) + } +} diff --git a/src/ME/decoration/add_worker/model.ts b/src/ME/decoration/add_worker/model.ts new file mode 100644 index 0000000..12c044f --- /dev/null +++ b/src/ME/decoration/add_worker/model.ts @@ -0,0 +1,7 @@ +import { reactive, ref } from 'vue' +export default { + listData: ref([]), + formData: ref({}), + metaData: ref({}), + currentTabs: ref(0) +} diff --git a/src/ME/decoration/add_worker/style.scss b/src/ME/decoration/add_worker/style.scss new file mode 100644 index 0000000..5e40394 --- /dev/null +++ b/src/ME/decoration/add_worker/style.scss @@ -0,0 +1,7 @@ +page { + background-color: #f8f8f8; +} +.add_worker_container { + padding-bottom: calc(130rpx + constant(safe-area-inset-bottom)); + padding-bottom: calc(130rpx + env(safe-area-inset-bottom)); +} diff --git a/src/ME/decoration/components/PopupAcceptance.vue b/src/ME/decoration/components/PopupAcceptance.vue new file mode 100644 index 0000000..eee4e38 --- /dev/null +++ b/src/ME/decoration/components/PopupAcceptance.vue @@ -0,0 +1,60 @@ + + + diff --git a/src/ME/decoration/components/PopupDelayedEntryExit.vue b/src/ME/decoration/components/PopupDelayedEntryExit.vue new file mode 100644 index 0000000..9982966 --- /dev/null +++ b/src/ME/decoration/components/PopupDelayedEntryExit.vue @@ -0,0 +1,66 @@ + + + diff --git a/src/ME/decoration/components/PopupExtension.vue b/src/ME/decoration/components/PopupExtension.vue new file mode 100644 index 0000000..1c5642b --- /dev/null +++ b/src/ME/decoration/components/PopupExtension.vue @@ -0,0 +1,50 @@ + + + diff --git a/src/ME/decoration/components/PopupFilingList.vue b/src/ME/decoration/components/PopupFilingList.vue new file mode 100644 index 0000000..6cf5240 --- /dev/null +++ b/src/ME/decoration/components/PopupFilingList.vue @@ -0,0 +1,68 @@ + + + + diff --git a/src/ME/decoration/components/PopupSelectWorker.vue b/src/ME/decoration/components/PopupSelectWorker.vue new file mode 100644 index 0000000..1c21f3c --- /dev/null +++ b/src/ME/decoration/components/PopupSelectWorker.vue @@ -0,0 +1,105 @@ + + + + + diff --git a/src/ME/decoration/decoration_share/index.vue b/src/ME/decoration/decoration_share/index.vue new file mode 100644 index 0000000..6762788 --- /dev/null +++ b/src/ME/decoration/decoration_share/index.vue @@ -0,0 +1,168 @@ +