智慧教务系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

533 lines
13 KiB

<template>
<div class="main-container">
<el-card class="card !border-none mb-[15px]" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back" />
</el-card>
<el-card class="box-card !border-none" shadow="never" v-loading="loading">
<el-form
:model="formData"
label-width="90px"
ref="formRef"
:rules="formRules"
class="page-form"
>
<el-form-item :label="t('addressType')" prop="address_type">
<div class="flex flex-col">
<div>
<el-checkbox
v-model="formData.is_delivery_address"
:label="t('deliveryAddress')"
:true-label="1"
:false-label="0"
/>
<el-checkbox
v-model="formData.is_default_delivery"
:label="t('defaultDeliveryAddress')"
:true-label="1"
:false-label="0"
v-show="formData.is_delivery_address"
/>
</div>
<div>
<el-checkbox
v-model="formData.is_refund_address"
:label="t('refundAddress')"
:true-label="1"
:false-label="0"
/>
<el-checkbox
v-model="formData.is_default_refund"
:label="t('defaultRefundAddress')"
:true-label="1"
:false-label="0"
v-show="formData.is_refund_address"
/>
</div>
</div>
</el-form-item>
<el-form-item :label="t('contactName')" prop="contact_name">
<el-input
v-model.trim="formData.contact_name"
clearable
:placeholder="t('contactNamePlaceholder')"
class="input-width"
maxlength="10"
/>
</el-form-item>
<el-form-item :label="t('mobile')" prop="mobile">
<el-input
v-model.trim="formData.mobile"
clearable
:placeholder="t('mobilePlaceholder')"
class="input-width"
@keyup="filterNumber($event)"
@blur="formData.mobile = $event.target.value"
/>
</el-form-item>
<el-form-item :label="t('fullAddress')" prop="address_area">
<el-select
v-model="formData.province_id"
value-key="id"
clearable
class="w-[200px]"
ref="provinceRef"
>
<el-option :label="t('provincePlaceholder')" :value="0" />
<el-option
v-for="(item, index) in areaList.province"
:key="index"
:label="item.name"
:value="item.id"
/>
</el-select>
<el-select
v-model="formData.city_id"
value-key="id"
clearable
class="w-[200px] ml-3"
ref="cityRef"
>
<el-option :label="t('cityPlaceholder')" :value="0" />
<el-option
v-for="(item, index) in areaList.city"
:key="index"
:label="item.name"
:value="item.id"
/>
</el-select>
<el-select
v-model="formData.district_id"
value-key="id"
clearable
class="w-[200px] ml-3"
ref="districtRef"
>
<el-option :label="t('districtPlaceholder')" :value="0" />
<el-option
v-for="(item, index) in areaList.district"
:key="index"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item prop="address">
<el-input
v-model.trim="formData.address"
clearable
:placeholder="t('addressPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item>
<div
id="container"
class="w-[800px] h-[520px] relative"
v-loading="mapLoading"
></div>
</el-form-item>
</el-form>
</el-card>
<div class="fixed-footer-wrap">
<div class="fixed-footer !z-[9999]">
<el-button type="primary" @click="onSave(formRef)">{{
t('save')
}}</el-button>
<el-button @click="back()">{{ t('cancel') }}</el-button>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import {
getShopAddressInfo,
addShopAddress,
editShopAddress,
} from '@/addon/shop/api/shop_address'
import { getMap, getAreaListByPid, getAreaByCode } from '@/app/api/sys'
import { useRoute } from 'vue-router'
import { createMarker, latLngToAddress, addressToLatLng } from '@/utils/qqmap'
import { filterNumber, debounce } from '@/utils/common'
const route = useRoute()
const id: number = parseInt(route.query.id as string)
const loading = ref(false)
const pageName = route.meta.title
interface areaType {
province: any[]
city: any[]
district: any[]
}
const areaList = reactive<areaType>({
province: [],
city: [],
district: [],
})
const provinceRef = ref()
const cityRef = ref()
const districtRef = ref()
/**
* 获取省
*/
getAreaListByPid(0).then((res) => {
areaList.province = res.data
})
let mapKey: string = ''
onMounted(() => {
const mapScript = document.createElement('script')
getMap().then((res) => {
mapKey = res.data.key
mapScript.type = 'text/javascript'
mapScript.src =
'https://map.qq.com/api/gljs?libraries=tools,service&v=1.exp&key=' +
res.data.key
document.body.appendChild(mapScript)
})
mapScript.onload = () => {
setTimeout(() => {
initMap()
}, 500)
}
})
/**
* 初始化地图
*/
let map: any
let marker: any
const mapLoading = ref(true)
const initMap = () => {
const TMap = (window as any).TMap
const LatLng = TMap.LatLng
const center = new LatLng(formData.lat, formData.lng)
map = new TMap.Map('container', {
center,
zoom: 14,
})
map.on('tilesloaded', () => {
mapLoading.value = false
})
marker = createMarker(map)
map.on('click', (evt: any) => {
map.setCenter(evt.latLng)
marker.updateGeometries({
id: 'center',
position: evt.latLng,
})
latLngChange(evt.latLng.lat, evt.latLng.lng)
})
latLngChange(center.lat, center.lng)
}
const storeArea = reactive({
province_id: 0,
city_id: 0,
district_id: 0,
})
const latLngChange = (lat: number, lng: number) => {
latLngToAddress({ mapKey, lat, lng })
.then(({ message, result }) => {
if (message == 'query ok' || message == 'Success') {
formData.lat = result.location.lat
formData.lng = result.location.lng
formData.address = result.formatted_addresses.recommend
getAreaByCode(result.ad_info.adcode).then(({ data }) => {
storeArea.province_id = data.province ? data.province.id : 0
storeArea.city_id = data.city ? data.city.id : 0
storeArea.district_id = data.district ? data.district.id : 0
})
} else {
console.error(message, result)
}
})
.catch((err) => {
console.log(err)
})
}
/**
* 表单数据
*/
const initialFormData = {
id: 0,
contact_name: '',
mobile: '',
province_id: 0,
city_id: 0,
district_id: 0,
address: '',
full_address: '',
lat: 39.908626,
lng: 116.39719,
is_delivery_address: 0,
is_refund_address: 0,
is_default_delivery: 0,
is_default_refund: 0,
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const setFormData = async (id: number = 0) => {
loading.value = true
Object.assign(formData, initialFormData)
const data = await (await getShopAddressInfo(id)).data
Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
})
loading.value = false
}
if (id) setFormData(id)
const formRef = ref<FormInstance>()
// 表单验证规则
const formRules = computed(() => {
return {
address_type: [
{
validator: (rule: any, value: any, callback: any) => {
if (!formData.is_delivery_address && !formData.is_refund_address) {
callback(new Error(t('addressTypeRequire')))
}
callback()
},
},
],
contact_name: [
{ required: true, message: t('contactNamePlaceholder'), trigger: 'blur' },
],
mobile: [
{ required: true, message: t('mobilePlaceholder'), trigger: 'blur' },
{
trigger: 'blur',
validator: (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) {
callback(new Error(t('mobileTips')))
}
callback()
},
},
],
address_area: [
{
validator: (rule: any, value: any, callback: any) => {
if (!formData.province_id) {
callback(new Error(t('provincePlaceholder')))
}
if (!formData.city_id) {
callback(new Error(t('cityPlaceholder')))
}
if (areaList.district.length && !formData.district_id) {
callback(new Error(t('districtPlaceholder')))
}
callback()
},
},
],
address: [
{ required: true, message: t('addressPlaceholder'), trigger: 'blur' },
],
}
})
/**
* 获取市
*/
watch(
() => formData.province_id,
(nval) => {
if (nval) {
getAreaListByPid(formData.province_id).then((res) => {
areaList.city = res.data
const cityId = formData.city_id
if (cityId) {
let isExist = false
for (let i = 0; i < res.data.length; i++) {
if (cityId == res.data[i].id) {
isExist = true
break
}
}
if (isExist) {
formData.city_id = cityId
return
}
}
formData.city_id = 0
areaChange()
})
} else {
formData.city_id = 0
}
}
)
/**
* 获取区
*/
watch(
() => formData.city_id,
(nval) => {
if (nval) {
getAreaListByPid(formData.city_id).then((res) => {
areaList.district = res.data
const districtId = formData.district_id
if (districtId) {
let isExist = false
for (let i = 0; i < res.data.length; i++) {
if (districtId == res.data[i].id) {
isExist = true
break
}
}
if (isExist) {
formData.district_id = districtId
return
}
}
areaChange()
formData.district_id = 0
})
} else {
formData.district_id = 0
}
}
)
watch(
() => formData.district_id,
(nval) => {
if (nval) {
areaChange()
}
}
)
const areaChange = debounce(() => {
setTimeout(() => {
const address = [
formData.province_id ? provinceRef.value.selectedLabel : '',
formData.city_id ? cityRef.value.selectedLabel : '',
formData.district_id ? districtRef.value.selectedLabel : '',
]
addressToLatLng({ mapKey, address: address.join('') }).then(
({ message, result }) => {
if (message == 'Success' || message == 'query ok') {
const latLng = new (window as any).TMap.LatLng(
result.location.lat,
result.location.lng
)
map.setCenter(latLng)
marker.updateGeometries({
id: 'center',
position: latLng,
})
formData.lat = result.location.lat
formData.lng = result.location.lng
} else {
console.error(message, result)
}
}
)
}, 500)
}, 500)
/**
* 地图点选获取市
*/
watch(
() => storeArea.province_id,
(nval) => {
if (nval) {
getAreaListByPid(storeArea.province_id).then((res) => {
areaList.city = res.data
formData.province_id = storeArea.province_id
formData.city_id = storeArea.city_id
})
}
}
)
/**
* 地图点选获取区
*/
watch(
() => storeArea.city_id,
(nval) => {
if (nval) {
getAreaListByPid(storeArea.city_id).then((res) => {
areaList.district = res.data
formData.city_id = storeArea.city_id
formData.district_id = storeArea.district_id
})
}
}
)
/**
* 地图点选获取区
*/
watch(
() => storeArea.district_id,
(nval) => {
if (nval) {
formData.district_id = storeArea.district_id
}
}
)
const onSave = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
const data = formData
const address = [
data.province_id ? provinceRef.value.selectedLabel : '',
data.city_id ? cityRef.value.selectedLabel : '',
data.district_id ? districtRef.value.selectedLabel : '',
data.address,
]
data.full_address = address.join('')
const save = id ? editShopAddress : addShopAddress
save(data)
.then((res) => {
loading.value = false
history.back()
})
.catch(() => {
loading.value = false
})
}
})
}
const back = () => {
history.back()
}
</script>
<style lang="scss" scoped></style>