master
parent
dfcad17fb4
commit
824d2402a9
2
.env
2
.env
|
|
@ -8,6 +8,8 @@ VITE_APP_BASE_URL=/
|
|||
# 服务器基础地址
|
||||
VITE_HTTP_SERVER_BASE_URL=/api
|
||||
VITE_HTTP_PROXY_TARGET=http://127.0.0.1:10086
|
||||
VITE_HTTP_MAP_SERVER_BASE_URL=/api/map
|
||||
VITE_HTTP_MAP_SERVER_PROXY_TARGET=https://apis.map.qq.com
|
||||
VITE_WS_SERVER_BASE_URL=/api/fdx
|
||||
VITE_WS_PROXY_TARGET=ws://127.0.0.1:10086
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"axios": "^1.11.0",
|
||||
"decimal.js": "^10.6.0",
|
||||
"echarts": "^5.4.1",
|
||||
"element-plus": "^2.11.8",
|
||||
"element-plus": "^2.13.2",
|
||||
"luxon": "^3.7.1",
|
||||
"mitt": "^3.0.1",
|
||||
"nanoid": "^5.1.5",
|
||||
|
|
@ -2971,9 +2971,9 @@
|
|||
"license": "ISC"
|
||||
},
|
||||
"node_modules/element-plus": {
|
||||
"version": "2.13.1",
|
||||
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.13.1.tgz",
|
||||
"integrity": "sha512-eG4BDBGdAsUGN6URH1PixzZb0ngdapLivIk1meghS1uEueLvQ3aljSKrCt5x6sYb6mUk8eGtzTQFgsPmLavQcA==",
|
||||
"version": "2.13.2",
|
||||
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.13.2.tgz",
|
||||
"integrity": "sha512-Zjzm1NnFXGhV4LYZ6Ze9skPlYi2B4KAmN18FL63A3PZcjhDfroHwhtM6RE8BonlOPHXUnPQynH0BgaoEfvhrGw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ctrl/tinycolor": "^3.4.1",
|
||||
|
|
@ -2985,8 +2985,8 @@
|
|||
"@vueuse/core": "^10.11.0",
|
||||
"async-validator": "^4.2.5",
|
||||
"dayjs": "^1.11.19",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lodash": "^4.17.23",
|
||||
"lodash-es": "^4.17.23",
|
||||
"lodash-unified": "^1.0.3",
|
||||
"memoize-one": "^6.0.0",
|
||||
"normalize-wheel-es": "^1.2.0"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"axios": "^1.11.0",
|
||||
"decimal.js": "^10.6.0",
|
||||
"echarts": "^5.4.1",
|
||||
"element-plus": "^2.11.8",
|
||||
"element-plus": "^2.13.2",
|
||||
"luxon": "^3.7.1",
|
||||
"mitt": "^3.0.1",
|
||||
"nanoid": "^5.1.5",
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
|
|
@ -51,7 +51,7 @@
|
|||
box-sizing border-box !important
|
||||
|
||||
& > .el-scrollbar > .el-scrollbar__wrap {
|
||||
max-height calc(100vh - 400px)
|
||||
max-height 850px
|
||||
height unset
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,14 @@ export const useAppSettingStore = defineStore('AppSetting', () => {
|
|||
const language = ref<'zh' | 'en'>('zh')
|
||||
const logo = ref<string | null>(null)
|
||||
const collectedMenus = ref<AppTypes.Menu[]>([])
|
||||
const defaultAddress = reactive({
|
||||
lat: 31.96873,
|
||||
lng: 118.798171,
|
||||
province: '320000',
|
||||
city: '320100',
|
||||
provinceName: '江苏省',
|
||||
cityName: '南京市',
|
||||
})
|
||||
|
||||
const menus = ref<AppTypes.Menu[]>([])
|
||||
const menuTree = ref<AppTypes.Menu[]>([])
|
||||
|
|
@ -29,6 +37,7 @@ export const useAppSettingStore = defineStore('AppSetting', () => {
|
|||
logo,
|
||||
language,
|
||||
stationId,
|
||||
defaultAddress,
|
||||
$reset,
|
||||
}
|
||||
}, {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export const appTitle = import.meta.env.VITE_APP_TITLE
|
|||
* 服务器基础地址
|
||||
*/
|
||||
export const serverBaseUrl = import.meta.env.VITE_HTTP_SERVER_BASE_URL ?? ''
|
||||
export const mapServerBaseUrl = import.meta.env.VITE_HTTP_MAP_SERVER_BASE_URL ?? ''
|
||||
|
||||
export const wsServerBaseUrl = import.meta.env.VITE_WS_SERVER_BASE_URL ?? '/'
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ type RuleType<T extends object> = Partial<Record<keyof T | string, Arrayable<For
|
|||
|
||||
export interface FormPanelType<T extends object> {
|
||||
title: string
|
||||
defaultFormData: T
|
||||
detailsLoader: (id?: string) => Promise<T | undefined | null | void>
|
||||
doSubmit: (data: T) => Promise<boolean | undefined | null | void>
|
||||
rules: RuleType<T> | ((formData: T) => RuleType<T>)
|
||||
|
|
@ -40,7 +41,7 @@ const component = defineComponent(
|
|||
const showDialog = ref(false)
|
||||
const loading = ref(false)
|
||||
|
||||
const formData = Utils.resetAble(reactive<T>({} as T))
|
||||
const formData = Utils.resetAble(reactive<T>(props.defaultFormData))
|
||||
|
||||
function dialogCloseHandler() {
|
||||
formData.$reset()
|
||||
|
|
@ -134,7 +135,7 @@ const component = defineComponent(
|
|||
},
|
||||
{
|
||||
name: 'AFormPanel',
|
||||
props: [ 'title', 'detailsLoader', 'doSubmit', 'rules', 'watchForm', 'labelWidth', 'width', 'modal', 'appendToBody' ],
|
||||
props: [ 'title', 'defaultFormData', 'detailsLoader', 'doSubmit', 'rules', 'watchForm', 'labelWidth', 'width', 'modal', 'appendToBody' ],
|
||||
})
|
||||
|
||||
export interface AFormPanelInstance extends InstanceType<typeof component> {
|
||||
|
|
@ -167,6 +168,10 @@ export function buildFormPanelProps<T extends object>(props: Partial<Exclude<For
|
|||
props.watchForm.formItems = '_none_'
|
||||
}
|
||||
|
||||
if (props.defaultFormData == null) {
|
||||
props.defaultFormData = {} as T
|
||||
}
|
||||
|
||||
return reactive({
|
||||
title: props.title!,
|
||||
detailsLoader: props.detailsLoader!,
|
||||
|
|
@ -176,6 +181,7 @@ export function buildFormPanelProps<T extends object>(props: Partial<Exclude<For
|
|||
labelWidth: props.labelWidth!,
|
||||
width: props.width!,
|
||||
modal: props.modal!,
|
||||
defaultFormData: props.defaultFormData!,
|
||||
appendToBody: props.appendToBody!,
|
||||
} as FormPanelType<T>)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
import { defineComponent } from 'vue'
|
||||
import Types from '@/common/utils/types.ts'
|
||||
|
||||
const key = '3TGBZ-ZK7K5-CMNIK-ICIGZ-K6TYQ-HTBTZ'
|
||||
|
||||
// 32.087182, 118.797109
|
||||
interface InitOption {
|
||||
/**
|
||||
* 容器
|
||||
*/
|
||||
el: string | HTMLDivElement
|
||||
/**
|
||||
* 中心点
|
||||
*/
|
||||
center?: {
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
lat: number
|
||||
/**
|
||||
* 纬度
|
||||
*/
|
||||
lng: number
|
||||
}
|
||||
/**
|
||||
* 缩放级别
|
||||
*/
|
||||
zoom?: number
|
||||
/**
|
||||
* 俯仰角
|
||||
*/
|
||||
pitch?: number
|
||||
/**
|
||||
* 旋转角度
|
||||
*/
|
||||
rotation?: number
|
||||
}
|
||||
|
||||
function initMap({
|
||||
el,
|
||||
center,
|
||||
zoom = 15,
|
||||
pitch = 0,
|
||||
rotation = 0,
|
||||
}: InitOption) {
|
||||
let centerLatLng: TMap.LatLng | undefined = undefined
|
||||
if (center != null) {
|
||||
centerLatLng = new TMap.LatLng(center.lat, center.lng)
|
||||
}
|
||||
if (Types.isString(el)) {
|
||||
const htmlNode = document.getElementById(el as string)
|
||||
if (htmlNode == null) {
|
||||
throw new Error('地图容器不存在')
|
||||
}
|
||||
el = htmlNode as HTMLDivElement
|
||||
}
|
||||
|
||||
return new TMap.Map(el, {
|
||||
center: centerLatLng,
|
||||
zoom,
|
||||
pitch,
|
||||
rotation,
|
||||
})
|
||||
}
|
||||
|
||||
export interface AMapType {
|
||||
init: () => void
|
||||
}
|
||||
|
||||
const component = defineComponent(
|
||||
(_, ctx) => {
|
||||
const el = ref<HTMLDivElement | undefined>(undefined)
|
||||
const init = () => {
|
||||
initMap({
|
||||
el: el.value as HTMLDivElement,
|
||||
center: {
|
||||
lat: 32.087182,
|
||||
lng: 118.797109,
|
||||
},
|
||||
})
|
||||
}
|
||||
ctx.expose({init})
|
||||
return () => {
|
||||
return (
|
||||
<div ref={el}>
|
||||
</div>)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
export default component
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
<script lang="ts" setup>
|
||||
import {
|
||||
defineExpose,
|
||||
defineProps,
|
||||
reactive,
|
||||
ref,
|
||||
watchEffect,
|
||||
} from 'vue'
|
||||
import AmapApi, {
|
||||
type Poi,
|
||||
type SearchPlaceResult,
|
||||
} from '@/components/a-map/amap-api.ts'
|
||||
import {
|
||||
ElOption,
|
||||
ElPagination,
|
||||
ElSelect,
|
||||
} from 'element-plus'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
|
||||
const key = '3TGBZ-ZK7K5-CMNIK-ICIGZ-K6TYQ-HTBTZ'
|
||||
|
||||
interface AMapPropsType {
|
||||
width?: string
|
||||
mapConfig: {
|
||||
lat: number
|
||||
lng: number
|
||||
/**
|
||||
* 缩放级别
|
||||
*/
|
||||
zoom?: number
|
||||
/**
|
||||
* 俯仰角
|
||||
*/
|
||||
pitch?: number
|
||||
/**
|
||||
* 旋转角度
|
||||
*/
|
||||
rotation?: number
|
||||
}
|
||||
}
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<AMapPropsType>(),
|
||||
{
|
||||
width: '500px',
|
||||
},
|
||||
)
|
||||
|
||||
const addressModel = defineModel<string>('address', {required: false})
|
||||
const latModel = defineModel<number>('lat', {required: false})
|
||||
const lngModel = defineModel<number>('lng', {required: false})
|
||||
const areaModel = defineModel<number | string>('area', {required: false})
|
||||
const areaNameModel = defineModel<string>('areaName', {required: false})
|
||||
|
||||
const mapWrapper = useTemplateRef<HTMLDivElement>('mapRef')
|
||||
let map: TMap.Map | null = null
|
||||
let multiMarker: TMap.MultiMarker | null = null
|
||||
const paginationData = reactive<{
|
||||
current: number
|
||||
size: number
|
||||
total: number
|
||||
}>({
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
})
|
||||
const pois = ref<Poi[]>([])
|
||||
let keywords: string | undefined = undefined
|
||||
const currentPoi = ref<string>('')
|
||||
|
||||
function onSelected(value: string) {
|
||||
const poi = pois.value.find((it) => it.id === value)
|
||||
if (!poi) return
|
||||
addressModel.value = poi.title + '(' + poi.address + ')'
|
||||
latModel.value = poi.location.lat
|
||||
lngModel.value = poi.location.lng
|
||||
areaModel.value = poi.ad_info.adcode
|
||||
areaNameModel.value = poi.ad_info.city
|
||||
}
|
||||
|
||||
function createMap() {
|
||||
if (mapWrapper.value == null) {
|
||||
console.error('地图容器不存在')
|
||||
return null
|
||||
}
|
||||
if (map != null) return map
|
||||
return new TMap.Map(mapWrapper.value, {
|
||||
center: new TMap.LatLng(props.mapConfig.lat, props.mapConfig.lng),
|
||||
zoom: props.mapConfig.zoom ?? 16,
|
||||
pitch: props.mapConfig.pitch ?? 0,
|
||||
rotation: props.mapConfig.rotation ?? 0,
|
||||
})
|
||||
}
|
||||
|
||||
function createMarkerLayer() {
|
||||
if (map == null) return null
|
||||
if (multiMarker != null) return multiMarker
|
||||
return new TMap.MultiMarker({
|
||||
map,
|
||||
geometries: [
|
||||
{
|
||||
id: '1',
|
||||
position: new TMap.LatLng(props.mapConfig.lat, props.mapConfig.lng),
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if (Strings.isBlank(currentPoi.value)) return
|
||||
const poi = pois.value.find((it) => it.id === currentPoi.value)
|
||||
if (!poi) return
|
||||
map?.setCenter(new TMap.LatLng(poi.location.lat, poi.location.lng))
|
||||
multiMarker?.updateGeometries([
|
||||
{
|
||||
id: '1',
|
||||
position: new TMap.LatLng(poi.location.lat, poi.location.lng),
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
function paginationChange() {
|
||||
doSearch()
|
||||
}
|
||||
|
||||
function doSearch(queryStr?: string) {
|
||||
if (!Strings.isBlank(queryStr)) keywords = queryStr
|
||||
if (Strings.isBlank(keywords)) return
|
||||
AmapApi.searchPlace({
|
||||
key,
|
||||
keyword: keywords!,
|
||||
boundary: {lat: props.mapConfig.lat, lng: props.mapConfig.lng},
|
||||
page_size: paginationData.size,
|
||||
page_index: paginationData.current,
|
||||
get_subpois: 1,
|
||||
}).then((res) => {
|
||||
if (!res) return
|
||||
const result = res as SearchPlaceResult
|
||||
paginationData.total = result.count
|
||||
pois.value = result.data
|
||||
})
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (mapWrapper.value == null) return
|
||||
try {
|
||||
map = createMap()
|
||||
multiMarker = createMarkerLayer()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
function destroy() {
|
||||
multiMarker?.destroy()
|
||||
map?.destroy()
|
||||
multiMarker = null
|
||||
map = null
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(init)
|
||||
})
|
||||
|
||||
|
||||
onBeforeUnmount(destroy)
|
||||
|
||||
defineExpose({init, destroy})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="a-map">
|
||||
<ElSelect
|
||||
v-model="currentPoi"
|
||||
:placeholder="addressModel??'请搜索地点'"
|
||||
:remote-method="doSearch"
|
||||
filterable
|
||||
no-data-text="暂无数据"
|
||||
no-match-text="暂无数据"
|
||||
remote
|
||||
@change="onSelected">
|
||||
<ElOption
|
||||
v-for="item in pois"
|
||||
:key="item.id"
|
||||
:label="item.title+'('+item.address+')'"
|
||||
:value="item.id"
|
||||
/>
|
||||
<template #footer>
|
||||
<ElPagination
|
||||
:background="true"
|
||||
:current-page="paginationData.current"
|
||||
:hide-on-single-page="false"
|
||||
:page-size="paginationData.size"
|
||||
:teleported="false"
|
||||
:total="paginationData.total"
|
||||
layout="total, prev, pager, next,"
|
||||
@change="paginationChange"
|
||||
@update:current-page="(val) => paginationData.current = val"
|
||||
@update:page-size="(val) => paginationData.size = val"
|
||||
/>
|
||||
</template>
|
||||
</ElSelect>
|
||||
<div ref="mapRef" class="map-wrapper"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.a-map {
|
||||
width v-bind('props.width');
|
||||
height 100%;
|
||||
display flex;
|
||||
flex-direction column;
|
||||
gap 10px
|
||||
|
||||
:deep(.el-select) {
|
||||
height 32px
|
||||
width 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.map-wrapper {
|
||||
flex 1
|
||||
width 100%;
|
||||
}
|
||||
|
||||
:deep(.el-pagination) {
|
||||
justify-content center
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1 +1,113 @@
|
|||
// https://apis.map.qq.com/ws/place/v1/search?boundary=nearby(40.040589,116.273543,1000)&keyword=公园&page_size=10&page_index=1&key=OB4BZ-D4W3U-*****
|
||||
import axios from 'axios'
|
||||
import { mapServerBaseUrl } from '@/common'
|
||||
import mime from '@/common/utils/mime.ts'
|
||||
import qs from 'qs'
|
||||
|
||||
const httpUtil = axios.create({
|
||||
timeout: 10000,
|
||||
baseURL: mapServerBaseUrl,
|
||||
headers: {
|
||||
Accept: mime.JSON,
|
||||
},
|
||||
})
|
||||
|
||||
interface SearchPlaceParam {
|
||||
/**
|
||||
* 开发密钥,必填
|
||||
*/
|
||||
key: string;
|
||||
/**
|
||||
* 搜索关键字(UTF-8编码,最大96字节),必填
|
||||
*/
|
||||
keyword: string;
|
||||
/**
|
||||
* 格式:nearby(纬度,经度,半径[,是否自动扩大]),必填
|
||||
*/
|
||||
boundary: {
|
||||
lat: number
|
||||
lng: number
|
||||
radius?: number
|
||||
auto_extend?: 0 | 1
|
||||
};
|
||||
/**
|
||||
* 是否返回子地点,如大厦停车场、出入口等取值:
|
||||
* 0 [默认]不返回、1 返回
|
||||
*/
|
||||
get_subpois?: 0 | 1;
|
||||
filter?: string; // 筛选条件(分类筛选/排除分类/筛选有电话),可选
|
||||
added_fields?: string; // 附加字段,仅支持category_code,可选
|
||||
orderby?: '_distance'; // 排序方式,仅支持按距离排序,可选
|
||||
page_size?: number; // 每页条目数(1-20),默认10,可选
|
||||
page_index?: number; // 页码,默认1,可选
|
||||
output?: 'json' | 'jsonp'; // 返回格式,默认json,可选
|
||||
callback?: string; // JSONP回调函数名,可选
|
||||
}
|
||||
|
||||
// 坐标类型
|
||||
interface Location {
|
||||
lat: number; // 纬度
|
||||
lng: number; // 经度
|
||||
}
|
||||
|
||||
// 行政区划信息类型
|
||||
interface AdInfo {
|
||||
adcode: number; // 行政区划代码
|
||||
province: string; // 省份
|
||||
city: string; // 城市(省直辖县级区划返回空)
|
||||
district: string; // 区/县
|
||||
}
|
||||
|
||||
export interface Poi {
|
||||
id: string; // POI唯一标识
|
||||
title: string; // POI名称
|
||||
address: string; // 地址
|
||||
tel: string; // 电话
|
||||
category: string; // POI分类
|
||||
category_code?: number; // 分类编码(added_fields=category_code时返回)
|
||||
type: 0 | 1 | 2 | 3 | 4; // POI类型
|
||||
location: Location; // 坐标
|
||||
_distance: number; // 直线距离(米)
|
||||
ad_info: AdInfo; // 行政区划信息
|
||||
}
|
||||
|
||||
// 子地点类型
|
||||
interface SubPoi extends Exclude<Poi, '_distance'> {
|
||||
parent_id: string; // 主地点ID
|
||||
}
|
||||
|
||||
// 周边搜索响应类型
|
||||
export interface SearchPlaceResult {
|
||||
status: number; // 状态码(0为正常)
|
||||
message: string; // 状态说明
|
||||
count: number; // 搜索结果总数(最多返回200条)
|
||||
request_id: string; // 请求唯一标识
|
||||
data: Poi[];
|
||||
sub_pois?: SubPoi[]; // 子地点列表(get_subpois=1时返回)
|
||||
}
|
||||
|
||||
const paramsSerializer = (params: any) => {
|
||||
return qs.stringify(params, {indices: false, allowDots: true})
|
||||
}
|
||||
|
||||
function searchPlace(params: SearchPlaceParam) {
|
||||
return httpUtil.get<SearchPlaceResult>('/ws/place/v1/search', {
|
||||
params: {
|
||||
...params,
|
||||
boundary: `nearby(${params.boundary.lat},${params.boundary.lng},${params.boundary.radius == null || params.boundary.radius < 10 ? 1000 : params.boundary.radius},${params.boundary.auto_extend ?? 1})`,
|
||||
},
|
||||
paramsSerializer,
|
||||
responseType: 'json',
|
||||
})
|
||||
.then(res => {
|
||||
if (res.data.status !== 0) return Promise.reject({message: res.data.message})
|
||||
return res.data
|
||||
})
|
||||
.catch(err => {
|
||||
ElMessage.error(err.message)
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
searchPlace,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ interface ImportMetaEnv {
|
|||
readonly VITE_APP_TITLE: string
|
||||
readonly VITE_APP_BASE_URL: string
|
||||
readonly VITE_HTTP_SERVER_BASE_URL: string
|
||||
readonly VITE_HTTP_MAP_SERVER_BASE_URL: string
|
||||
readonly VITE_HTTP_MAP_SERVER_PROXY_TARGET: string
|
||||
readonly VITE_HTTP_PROXY_TARGET: string
|
||||
readonly VITE_WS_SERVER_BASE_URL: string
|
||||
readonly VITE_WS_PROXY_TARGET: string
|
||||
|
|
|
|||
|
|
@ -4,10 +4,8 @@
|
|||
v-bind="tablePageProps">
|
||||
|
||||
<template #simpleFormItem="formData">
|
||||
<ElFormItem label="站点名称">
|
||||
<ElInput
|
||||
v-model="formData.stationName"
|
||||
placeholder="站点名称"/>
|
||||
<ElFormItem>
|
||||
<ElInput v-model="formData.stationName" clearable placeholder="站点名称" @clear="research"/>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
<template #columns>
|
||||
|
|
@ -64,22 +62,22 @@ const tablePageProps = buildTablePageProps<StationTypes.SearchStationParam, Stat
|
|||
stationFormIns.value?.open(row)
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'Delete',
|
||||
loading: false,
|
||||
type: 'danger',
|
||||
tooltip: '删除',
|
||||
confirm: {
|
||||
title: '是否删除当前数据',
|
||||
},
|
||||
action({row}) {
|
||||
return StationApi.del([ row.id! ])
|
||||
.then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
return true
|
||||
})
|
||||
},
|
||||
},
|
||||
/* {
|
||||
icon: 'Delete',
|
||||
loading: false,
|
||||
type: 'danger',
|
||||
tooltip: '删除',
|
||||
confirm: {
|
||||
title: '是否删除当前数据',
|
||||
},
|
||||
action({row}) {
|
||||
return StationApi.del([ row.id! ])
|
||||
.then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
return true
|
||||
})
|
||||
},
|
||||
}, */
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,26 +7,35 @@
|
|||
<ElFormItem label="站点名称" prop="stationName">
|
||||
<ElInput v-model="formData.stationName" placeholder="站点名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="管理员账号" prop="userId">
|
||||
<UserDropTable v-model="formData.userId"/>
|
||||
<ElFormItem label="企业代码" prop="uscc">
|
||||
<ElInput v-model="formData.uscc" placeholder="统一社会信用代码"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="企业名称" prop="orgName">
|
||||
<ElInput v-model="formData.orgInfo.orgName" placeholder="企业名称"/>
|
||||
<ElInput v-model="formData.orgName" placeholder="企业名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="管理员账号" prop="userId">
|
||||
<UserDropTable v-model="formData.userId" :placeholder="formData.username"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="管理员姓名" prop="customerName">
|
||||
<ElInput v-model="formData.customerName" placeholder="管理员姓名"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="企业代码" prop="uscc">
|
||||
<ElInput v-model="formData.orgInfo.uscc" placeholder="统一社会信用代码"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="管理员电话" prop="phone">
|
||||
<ElInput v-model="formData.phone" placeholder="管理员电话"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="地址" prop="address">
|
||||
<ElInput v-model="formData.address" placeholder="详细地址"/>
|
||||
<AMap
|
||||
ref="amap"
|
||||
v-model:address="formData.address"
|
||||
v-model:area="formData.area"
|
||||
v-model:areaName="formData.areaName"
|
||||
v-model:lat="formData.lat"
|
||||
v-model:lng="formData.lng"
|
||||
:map-config="{
|
||||
lat:appSettingStore.defaultAddress.lat,
|
||||
lng:appSettingStore.defaultAddress.lng,
|
||||
}"
|
||||
class="amap" width="700px"/>
|
||||
</ElFormItem>
|
||||
<AMap ref="amap" class="amap"/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
</AFormPanel>
|
||||
|
|
@ -40,7 +49,10 @@ import AFormPanel, {
|
|||
buildFormPanelProps,
|
||||
} from '@/components/a-form-panel/AFormPanel.tsx'
|
||||
import UserDropTable from '@/pages/sys/user/UserDropTable.vue'
|
||||
import AMap, { type AMapType } from '@/components/a-map/AMap.tsx'
|
||||
import AMap from '@/components/a-map/AMap.vue'
|
||||
import { useAppSettingStore } from '@/common/app/app-setting-store.ts'
|
||||
|
||||
const appSettingStore = useAppSettingStore()
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
research?: () => void
|
||||
|
|
@ -49,32 +61,116 @@ const props = withDefaults(defineProps<{
|
|||
},
|
||||
})
|
||||
|
||||
const amapIns = useTemplateRef<AMapType>('amap')
|
||||
interface StationFormType {
|
||||
id?: string
|
||||
// 站点名称
|
||||
stationName?: string
|
||||
// 省;代码
|
||||
province?: string
|
||||
// 市;代码
|
||||
city?: string
|
||||
// 区县;代码
|
||||
area?: string
|
||||
// 乡镇街道;代码
|
||||
town?: string
|
||||
// 省;名称
|
||||
provinceName?: string
|
||||
// 市;名称
|
||||
cityName?: string
|
||||
// 区县;名称
|
||||
areaName?: string
|
||||
// 乡镇街道;名称
|
||||
townName?: string
|
||||
// 详细地址
|
||||
address?: string
|
||||
// 经度
|
||||
lng?: number
|
||||
// 纬度
|
||||
lat?: number
|
||||
// 账号
|
||||
userId?: string
|
||||
username?: string
|
||||
customerName?: string
|
||||
phone?: string
|
||||
// 统一社会信用代码
|
||||
uscc?: string
|
||||
// 企业名称
|
||||
orgName?: string
|
||||
}
|
||||
|
||||
const formPanelIns = useTemplateRef<AFormPanelInstance>('formPanel')
|
||||
const status = ref<'add' | 'modify'>('add')
|
||||
type T = StationTypes.SearchStationResult & StationTypes.AddStationParam
|
||||
const formPanelProps = buildFormPanelProps<T>({
|
||||
const formPanelProps = buildFormPanelProps<StationFormType>({
|
||||
title: status.value === 'add' ? '新建站点' : '修改站点',
|
||||
labelWidth: '100px',
|
||||
detailsLoader(id?: string) {
|
||||
if (Strings.isBlank(id)) {
|
||||
status.value = 'add'
|
||||
return Promise.resolve({
|
||||
orgInfo: {},
|
||||
} as T)
|
||||
return Promise.resolve()
|
||||
} else {
|
||||
status.value = 'modify'
|
||||
return StationApi
|
||||
.detail(id!)
|
||||
.then(res => res.data)
|
||||
.then(res => {
|
||||
return {
|
||||
id: res.data.id,
|
||||
stationName: res.data.stationName,
|
||||
province: res.data.province,
|
||||
city: res.data.city,
|
||||
area: res.data.area,
|
||||
town: res.data.town,
|
||||
provinceName: res.data.provinceName,
|
||||
cityName: res.data.cityName,
|
||||
areaName: res.data.areaName,
|
||||
townName: res.data.townName,
|
||||
address: res.data.address,
|
||||
lng: res.data.lng,
|
||||
lat: res.data.lat,
|
||||
userId: res.data.customer.userId,
|
||||
username: res.data.customer.username,
|
||||
customerName: res.data.customer.customerName,
|
||||
phone: res.data.customer.phone,
|
||||
uscc: res.data.customer.uscc,
|
||||
orgName: res.data.customer.orgName,
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
doSubmit(data) {
|
||||
if (status.value === 'add') {
|
||||
return StationApi.add(data)
|
||||
return StationApi.add({
|
||||
stationName: data.stationName,
|
||||
area: data.area,
|
||||
areaName: data.areaName,
|
||||
address: data.address,
|
||||
lng: data.lng,
|
||||
lat: data.lat,
|
||||
userId: data.userId,
|
||||
customerName: data.customerName,
|
||||
phone: data.phone,
|
||||
orgInfo: {
|
||||
uscc: data.uscc,
|
||||
orgName: data.orgName,
|
||||
},
|
||||
})
|
||||
.then(props.research)
|
||||
} else {
|
||||
return StationApi.modify(data)
|
||||
return StationApi.modify({
|
||||
id: data.id,
|
||||
stationName: data.stationName,
|
||||
area: data.area,
|
||||
areaName: data.areaName,
|
||||
address: data.address,
|
||||
lng: data.lng,
|
||||
lat: data.lat,
|
||||
userId: data.userId,
|
||||
customerName: data.customerName,
|
||||
phone: data.phone,
|
||||
orgInfo: {
|
||||
uscc: data.uscc,
|
||||
orgName: data.orgName,
|
||||
},
|
||||
})
|
||||
.then(props.research)
|
||||
}
|
||||
},
|
||||
|
|
@ -93,33 +189,25 @@ const formPanelProps = buildFormPanelProps<T>({
|
|||
defineExpose({
|
||||
open(data?: ProjectTypes.SearchProjectResult) {
|
||||
formPanelIns.value?.open(data?.id)
|
||||
nextTick(() => {
|
||||
amapIns.value?.init()
|
||||
})
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.form-items {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-areas ". address" \
|
||||
". map" \
|
||||
". map" \
|
||||
". map" \
|
||||
". map" \
|
||||
". map" \
|
||||
". map";
|
||||
grid-template-areas "a1 a4" \
|
||||
"a2 a5" \
|
||||
"a3 a6" \
|
||||
"a7 a7";
|
||||
gap 10px
|
||||
|
||||
:deep(.el-form-item):nth-child(7) {
|
||||
grid-area address
|
||||
:deep(.el-form-item) {
|
||||
align-items start
|
||||
}
|
||||
for val, i in (a1 a2 a3 a4 a5 a6 a7) {
|
||||
:deep(.el-form-item):nth-child({i+1}) {
|
||||
grid-area val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.amap {
|
||||
width 500px
|
||||
height 232px
|
||||
grid-area map
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ declare global {
|
|||
|
||||
interface CustomerInfo {
|
||||
id?: string
|
||||
userId?: string
|
||||
username?: string
|
||||
uscc?: string
|
||||
// 客户姓名
|
||||
customerName?: string
|
||||
// 客户联系电话
|
||||
|
|
@ -134,6 +136,11 @@ declare global {
|
|||
lng?: number
|
||||
// 纬度
|
||||
lat?: number
|
||||
// 账号
|
||||
userId?: string
|
||||
customerName?: string
|
||||
phone?: string
|
||||
orgInfo?: OrgInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,15 +50,17 @@ const formPanelIns = useTemplateRef<AFormPanelInstance>('formPanel')
|
|||
const uploaderIns = useTemplateRef<InstanceType<typeof Uploader>>('uploader')
|
||||
const status = ref<'add' | 'modify'>('add')
|
||||
const formPanelProps = buildFormPanelProps<GoodsCategoryTypes.SearchGoodsCategoryResult>({
|
||||
title: status.value === 'add' ? '新建产品分类' : '修改产品分类',
|
||||
title: '新建产品分类',
|
||||
detailsLoader(id?: string) {
|
||||
if (Strings.isBlank(id)) {
|
||||
status.value = 'add'
|
||||
formPanelProps.title = '新建产品分类'
|
||||
return Promise.resolve({
|
||||
bizType: props.defaultBizType,
|
||||
sort: 0,
|
||||
} as GoodsCategoryTypes.SearchGoodsCategoryResult)
|
||||
} else {
|
||||
formPanelProps.title = '修改产品分类'
|
||||
status.value = 'modify'
|
||||
return GoodsCategoryApi.detail(id!)
|
||||
.then((res) => {
|
||||
|
|
@ -72,6 +74,7 @@ const formPanelProps = buildFormPanelProps<GoodsCategoryTypes.SearchGoodsCategor
|
|||
return GoodsCategoryApi.add({
|
||||
bizType: data.bizType,
|
||||
categoryName: data.categoryName,
|
||||
sn: data.bizType === bizType.HuiShouPin ? data.sn : undefined,
|
||||
picture: data.picture,
|
||||
sort: data.sort,
|
||||
memo: data.memo,
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ declare global {
|
|||
id?: string
|
||||
// 业务类型;字典代码:biz_type,ZaiShengPin-->再生品、HuiShouPin-->回收品、QiTa-->其他
|
||||
bizType?: string
|
||||
sn?: string
|
||||
// 分类名称
|
||||
categoryName?: string
|
||||
// 图片
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
import ADropTable from '@/components/a-drop-table/ADropTable.vue'
|
||||
import UserApi from '@/pages/sys/user/user-api.ts'
|
||||
|
||||
defineProps<{
|
||||
placeholder?: string
|
||||
}>()
|
||||
const model = defineModel<string | undefined | null>()
|
||||
const dropTableColumns = [
|
||||
{
|
||||
|
|
@ -23,5 +26,6 @@ const dropTableLoader = (param: UserTypes.SearchUserParam) => {
|
|||
<ADropTable v-model="model"
|
||||
:columns="dropTableColumns"
|
||||
:loader="dropTableLoader"
|
||||
:placeholder="placeholder"
|
||||
display-field="username"/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -64,6 +64,13 @@ export default defineConfig((configEnv) => {
|
|||
host: '0.0.0.0',
|
||||
port: 5173,
|
||||
proxy: {
|
||||
[env.VITE_HTTP_MAP_SERVER_BASE_URL]: {
|
||||
proxyTimeout: 10000,
|
||||
target: env.VITE_HTTP_MAP_SERVER_PROXY_TARGET,
|
||||
secure: false,
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => (env.VITE_HTTP_MAP_SERVER_BASE_URL == null || env.VITE_HTTP_MAP_SERVER_BASE_URL == '/' ? path : path.replace(new RegExp(env.VITE_HTTP_MAP_SERVER_BASE_URL), '')),
|
||||
} as ProxyOptions,
|
||||
[env.VITE_HTTP_SERVER_BASE_URL]: {
|
||||
proxyTimeout: 10000,
|
||||
target: env.VITE_HTTP_PROXY_TARGET,
|
||||
|
|
|
|||
Loading…
Reference in New Issue