hc_zhufu
石超 2024-06-04 11:01:24 +08:00
commit a98ca3e24c
38 changed files with 2186 additions and 301 deletions

View File

@ -8,9 +8,8 @@ VITE_PUBLIC_PATH = /
#VITE_GLOB_API_URL=/basic-api
#财源
# VITE_GLOB_API_URL=http://192.168.10.102:9500
VITE_GLOB_API_URL=http://192.168.10.102:9023
#基础框架
#VITE_GLOB_API_URL=http://192.168.10.102:9023
VITE_GLOB_API_URL=http://192.168.10.102:9023

View File

@ -102,7 +102,10 @@
"mapbox-gl-utils": "^0.44.0",
"@mapbox/mapbox-gl-draw": "^1.4.1",
"mapbox-gl-draw-snap-mode": "^0.2.0",
"mapbox-extensions":"^1.3.38",
"terraformer-wkt-parser": "^1.2.1",
"ceel-json-editor":"^0.0.3",
"@originjs/vite-plugin-commonjs":"^1.0.3",
"mars3d": "^3.7.0",
"mars3d-cesium": "^1.113.0",
"min-dash": "^4.2.1",

View File

@ -22,3 +22,14 @@ export function uploadApi(
params,
);
}
export function fileUploadApi(params: UploadFileParams,url:string,onUploadProgress: (progressEvent: AxiosProgressEvent) => void,) {
return defHttp.uploadFile<UploadApiResult>(
{
url: url,
onUploadProgress,
},
params,
);
}

View File

@ -28,7 +28,8 @@ import ApiTree from './components/ApiTree.vue';
import ApiTreeSelect from './components/ApiTreeSelect.vue';
import ApiCascader from './components/ApiCascader.vue';
import ApiTransfer from './components/ApiTransfer.vue';
import { BasicUpload, ImageUpload } from '@/components/Upload';
import { BasicUpload, ImageUpload,VideoUpload,FileUpload } from '@/components/Upload';
import {Location } from '@/components/Map'
import { StrengthMeter } from '@/components/StrengthMeter';
import { IconPicker } from '@/components/Icon';
import { CountdownInput } from '@/components/CountDown';
@ -45,6 +46,9 @@ componentMap.set('InputTextArea', Input.TextArea);
componentMap.set('InputNumber', InputNumber);
componentMap.set('AutoComplete', AutoComplete);
componentMap.set('ImageUpload', ImageUpload);
componentMap.set("VideoUpload",VideoUpload);
componentMap.set("FileUpload",FileUpload);
componentMap.set("Location",Location);
componentMap.set('Select', Select);
componentMap.set('ApiSelect', ApiSelect);
componentMap.set('ApiTree', ApiTree);

View File

@ -128,6 +128,7 @@
const scheme = JSON.parse(data.scheme);
console.log(scheme);
console.log(props.formConfig);
console.log("subTableColumns",subTableColumns)
subTableDB.value = scheme.db;
let disDetail = false;
scheme.formInfo.tabList.forEach((tabElement, index) => {
@ -154,6 +155,9 @@
});
}
});
if (element.component === 'InputGuid') {
element.ifShow = false;
}
//
if (element.rules !== undefined) {
let myString = element.rules[0].pattern;
@ -194,13 +198,15 @@
element.columns.forEach((itemColumn) => {
itemColumn.children.forEach((itemColumnChild) => {
tableData.push(itemColumnChild);
subTableColumns.value.push({
key: itemColumnChild.field,
title: itemColumnChild.label,
dataIndex: itemColumnChild.field,
...itemColumnChild,
width: 120,
});
if (itemColumnChild.component != 'InputGuid') {
subTableColumns.value.push({
key: itemColumnChild.field,
title: itemColumnChild.label,
dataIndex: itemColumnChild.field,
...itemColumnChild,
width: 120,
});
}
});
});
scrollValue.value = { x: (subTableColumns.value.length - 1) * 140, y: 300 };
@ -301,7 +307,7 @@
for (const key in values) {
for (const fieKey in FieldsValue.value) {
if (key == fieKey) {
if (values[key] != undefined) {
if (!values[key]) {
values[key] = FieldsValue.value[key];
}
}

View File

@ -0,0 +1,4 @@
import { withInstall } from '@/utils';
import getLocation from './src/components/Location.vue'
export const Location = withInstall(getLocation);

View File

@ -0,0 +1,289 @@
<template>
<div>
<div class="mapContainer" :id="'mapContainer'+mapRandom">
<div class="refresh-button">
<ReloadOutlined @click="onrefresh"/>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import mapboxgl, { Map, Popup } from 'mapbox-gl';
import { ref, toRefs, watch,onMounted } from 'vue';
import { ReloadOutlined } from '@ant-design/icons-vue';
import type { UploadFile, UploadProps } from 'ant-design-vue';
import { Modal, Upload } from 'ant-design-vue';
import { on } from '@/utils/domUtils';
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
import { useMessage } from '@/hooks/web/useMessage';
import { isArray, isFunction, isObject, isString } from '@/utils/is';
import { warn } from '@/utils/log';
import { useI18n } from '@/hooks/web/useI18n';
import { useUploadType } from '../hooks/useUpload';
import { uploadContainerProps } from '../props';
import { isImgTypeByName } from '../helper';
import { UploadResultStatus } from '@/components/Upload/src/types/typing';
import { parse } from 'path';
defineOptions({ name: 'ImageUpload' });
const mapRandom = ref(parseInt(Math.random()*100000).toString())
const emit = defineEmits(['change', 'update:value', 'delete']);
const props = defineProps({
...uploadContainerProps,
});
const { t } = useI18n();
const { createMessage } = useMessage();
const { accept, helpText, maxNumber, maxSize } = toRefs(props);
const isInnerOperate = ref<boolean>(false);
const { getStringAccept } = useUploadType({
acceptRef: accept,
helpTextRef: helpText,
maxNumberRef: maxNumber,
maxSizeRef: maxSize,
});
const previewOpen = ref<boolean>(false);
const previewImage = ref<string>('');
const previewTitle = ref<string>('');
const fileList = ref<UploadProps['fileList']>([]);
const isLtMsg = ref<boolean>(true);
const isActMsg = ref<boolean>(true);
let map:Map;
onMounted(() => {
mapboxgl.accessToken = "pk.eyJ1Ijoic2hpY2hhbzEyMyIsImEiOiJja3FobnI1aDEwNGF6Mm9vOXVhNnBzZmFhIn0.2fZKiMqCQHxVY74QShMEGQ"
map = initMap();
map.on("load",function(){
refreshLocation();
})
})
watch(
() => props.value,
(v) => {
if (isInnerOperate.value) {
isInnerOperate.value = false;
return;
}
if (v) {
let value: string[] = [];
if (isArray(v)) {
value = v;
} else {
value.push(v);
}
fileList.value = value.map((item, i) => {
if (item && isString(item)) {
return {
uid: -i + '',
name: item.substring(item.lastIndexOf('/') + 1),
status: 'done',
url: item,
};
} else if (item && isObject(item)) {
return item;
} else {
return;
}
}) as UploadProps['fileList'];
}
},
);
const initMap = () => {
return new mapboxgl.Map({
container: 'mapContainer'+mapRandom.value,
language: 'zh-cmn',
projection: 'equirectangular', // wgs84
style: {
glyphs: 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf',
version: 8,
sources: {
'raster-tiles': {
type: 'raster',
tiles: [
`https://t0.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=b6585bc41ee16251dbe6b1af64f375d9`,
],
tileSize: 256,
},
},
layers: [
{
id: 'tdt-img-tiles',
type: 'raster',
source: 'raster-tiles',
minzoom: 0,
maxzoom: 18,
},
],
},
maxZoom: 22,
minZoom: 6,
zoom: 15,
center: [118.298906,35.135013],
});
};
const refreshLocation = () => {
map.addSource('points', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'Point',
'coordinates': [118.298906,35.135013]
}
}
]
}
});
// Add a circle layer
map.addLayer({
'id': 'circle',
'type': 'circle',
'source': 'points',
'paint': {
'circle-color': '#409EFF',
'circle-radius': 6,
'circle-stroke-width': 3,
'circle-stroke-color': '#ffffff'
}
});
};
const onrefresh = () => {
createMessage.success(t('component.map.refreshSuccess'));
}
function getBase64<T extends string | ArrayBuffer | null>(file: File) {
return new Promise<T>((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
resolve(reader.result as T);
};
reader.onerror = (error) => reject(error);
});
}
const handlePreview = async (file: UploadFile) => {
console.log("fileEEEEE",file);
if (!file.url && !file.preview) {
file.preview = await getBase64<string>(file.originFileObj!);
}
previewImage.value = file.url || file.preview || '';
previewOpen.value = true;
previewTitle.value =
file.name || previewImage.value.substring(previewImage.value.lastIndexOf('/') + 1);
};
const handleRemove = async (file: UploadFile) => {
if (fileList.value) {
const index = fileList.value.findIndex((item) => item.uid === file.uid);
index !== -1 && fileList.value.splice(index, 1);
const value = getValue();
isInnerOperate.value = true;
emit('change', value);
emit('delete', file);
}
};
const handleCancel = () => {
previewOpen.value = false;
previewTitle.value = '';
};
const beforeUpload = (file: File) => {
const { maxSize, accept } = props;
const { name } = file;
const isAct = isImgTypeByName(name);
if (!isAct) {
createMessage.error(t('component.upload.acceptUpload', [accept]));
isActMsg.value = false;
//
setTimeout(() => (isActMsg.value = true), 1000);
}
const isLt = file.size / 1024 / 1024 > maxSize;
if (isLt) {
createMessage.error(t('component.upload.maxSizeMultiple', [maxSize]));
isLtMsg.value = false;
//
setTimeout(() => (isLtMsg.value = true), 1000);
}
return (isAct && !isLt) || Upload.LIST_IGNORE;
};
async function customRequest(info: UploadRequestOption<any>) {
const { api } = props;
if (!api || !isFunction(api)) {
return warn('upload api must exist and be a function');
}
try {
const res = await props.api?.({
data: {
...(props.uploadParams || {}),
},
file: info.file,
name: props.name,
filename: props.filename,
});
info.onSuccess!(res.data);
const value = getValue();
isInnerOperate.value = true;
emit('change', value);
} catch (e: any) {
console.log(e);
info.onError!(e);
}
}
function getValue() {
const list = (fileList.value || [])
.filter((item) => item?.status === UploadResultStatus.DONE)
.map((item: any) => {
return item?.url || item?.response?.url;
});
return props.multiple ? list : list.length > 0 ? list[0] : '';
}
</script>
<style lang="less">
.ant-upload-select-picture-card i {
color: #999;
font-size: 32px;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
.mapContainer{
width:100%;
height:280px;
border-radius: 6px;
}
.refresh-button{
position:absolute;
top:6px;
right:6px;
width:30px;
height:30px;
border-radius: 4px;
background:#fff;
line-height: 30px;
text-align: center;
z-index:999;
}
</style>

View File

@ -0,0 +1,139 @@
import type { BasicColumn, ActionItem } from '@/components/Table';
import { FileBasicColumn, FileItem, PreviewFileItem, UploadResultStatus } from '../types/typing';
import { isImgTypeByName } from '../helper';
import { Progress, Tag } from 'ant-design-vue';
import TableAction from '@/components/Table/src/components/TableAction.vue';
import ThumbUrl from './ThumbUrl.vue';
import { useI18n } from '@/hooks/web/useI18n';
const { t } = useI18n();
// 文件上传列表
export function createTableColumns(): FileBasicColumn[] {
return [
{
dataIndex: 'thumbUrl',
title: t('component.upload.legend'),
width: 100,
customRender: ({ record }) => {
const { thumbUrl } = (record as FileItem) || {};
return thumbUrl && <ThumbUrl fileUrl={thumbUrl} />;
},
},
{
dataIndex: 'name',
title: t('component.upload.fileName'),
align: 'left',
customRender: ({ text, record }) => {
const { percent, status: uploadStatus } = (record as FileItem) || {};
let status: 'normal' | 'exception' | 'active' | 'success' = 'normal';
if (uploadStatus === UploadResultStatus.ERROR) {
status = 'exception';
} else if (uploadStatus === UploadResultStatus.UPLOADING) {
status = 'active';
} else if (uploadStatus === UploadResultStatus.SUCCESS) {
status = 'success';
}
return (
<div>
<p class="truncate mb-1 max-w-[280px]" title={text}>
{text}
</p>
<Progress percent={percent} size="small" status={status} />
</div>
);
},
},
{
dataIndex: 'size',
title: t('component.upload.fileSize'),
width: 100,
customRender: ({ text = 0 }) => {
return text && (text / 1024).toFixed(2) + 'KB';
},
},
{
dataIndex: 'status',
title: t('component.upload.fileStatue'),
width: 100,
customRender: ({ text }) => {
if (text === UploadResultStatus.SUCCESS) {
return <Tag color="green">{() => t('component.upload.uploadSuccess')}</Tag>;
} else if (text === UploadResultStatus.ERROR) {
return <Tag color="red">{() => t('component.upload.uploadError')}</Tag>;
} else if (text === UploadResultStatus.UPLOADING) {
return <Tag color="blue">{() => t('component.upload.uploading')}</Tag>;
}
return text || t('component.upload.pending');
},
},
];
}
export function createActionColumn(handleRemove: Function): FileBasicColumn {
return {
width: 120,
title: t('component.upload.operating'),
dataIndex: 'action',
fixed: false,
customRender: ({ record }) => {
const actions: ActionItem[] = [
{
label: t('component.upload.del'),
color: 'error',
onClick: handleRemove.bind(null, record),
},
];
return <TableAction actions={actions} outside={true} />;
},
};
}
// 文件预览列表
export function createPreviewColumns(): BasicColumn[] {
return [
{
dataIndex: 'url',
title: t('component.upload.legend'),
width: 100,
customRender: ({ record }) => {
const { url } = (record as PreviewFileItem) || {};
return isImgTypeByName(url) && <ThumbUrl fileUrl={url} />;
},
},
{
dataIndex: 'name',
title: t('component.upload.fileName'),
align: 'left',
},
];
}
export function createPreviewActionColumn({
handleRemove,
handleDownload,
}: {
handleRemove: Fn;
handleDownload: Fn;
}): BasicColumn {
return {
width: 160,
title: t('component.upload.operating'),
dataIndex: 'action',
fixed: false,
customRender: ({ record }) => {
const actions: ActionItem[] = [
{
label: t('component.upload.del'),
color: 'error',
onClick: handleRemove.bind(null, record),
},
{
label: t('component.upload.download'),
onClick: handleDownload.bind(null, record),
},
];
return <TableAction actions={actions} outside={true} />;
},
};
}

View File

@ -0,0 +1,32 @@
export function checkFileType(file: File, accepts: string[]) {
const newTypes = accepts.join('|');
// const reg = /\.(jpg|jpeg|png|gif|txt|doc|docx|xls|xlsx|xml)$/i;
const reg = new RegExp('\\.(' + newTypes + ')$', 'i');
return reg.test(file.name);
}
export function checkImgType(file: File) {
return isImgTypeByName(file.name);
}
export function isImgTypeByName(name: string) {
return /\.(jpg|jpeg|png|gif|webp)$/i.test(name);
}
export function isVideoTypeByName(name: string) {
return /\.(mp4|mov|avi)$/i.test(name);
}
export function getBase64WithFile(file: File) {
return new Promise<{
result: string;
file: File;
}>((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve({ result: reader.result as string, file });
reader.onerror = (error) => reject(error);
});
}

View File

@ -0,0 +1,61 @@
import { Ref, unref, computed } from 'vue';
import { useI18n } from '@/hooks/web/useI18n';
const { t } = useI18n();
export function useUploadType({
acceptRef,
helpTextRef,
maxNumberRef,
maxSizeRef,
}: {
acceptRef: Ref<string[]>;
helpTextRef: Ref<string>;
maxNumberRef: Ref<number>;
maxSizeRef: Ref<number>;
}) {
// 文件类型限制
const getAccept = computed(() => {
const accept = unref(acceptRef);
if (accept && accept.length > 0) {
return accept;
}
return [];
});
const getStringAccept = computed(() => {
return unref(getAccept)
.map((item) => {
if (item.indexOf('/') > 0 || item.startsWith('.')) {
return item;
} else {
return `.${item}`;
}
})
.join(',');
});
// 支持jpg、jpeg、png格式不超过2M最多可选择10张图片
const getHelpText = computed(() => {
const helpText = unref(helpTextRef);
if (helpText) {
return helpText;
}
const helpTexts: string[] = [];
const accept = unref(acceptRef);
if (accept.length > 0) {
helpTexts.push(t('component.upload.accept', [accept.join(',')]));
}
const maxSize = unref(maxSizeRef);
if (maxSize) {
helpTexts.push(t('component.upload.maxSize', [maxSize]));
}
const maxNumber = unref(maxNumberRef);
if (maxNumber && maxNumber !== Infinity) {
helpTexts.push(t('component.upload.maxNumber', [maxNumber]));
}
return helpTexts.join('');
});
return { getAccept, getStringAccept, getHelpText };
}

View File

@ -0,0 +1,118 @@
import type { PropType } from 'vue';
import { FileBasicColumn } from './types/typing';
import type { Options } from 'sortablejs';
import { Merge } from '@/utils/types';
type SortableOptions = Merge<
Omit<Options, 'onEnd'>,
{
onAfterEnd?: <T = any, R = any>(params: T) => R;
// ...可扩展
}
>;
type ListType = 'text' | 'picture' | 'picture-card';
export const basicProps = {
listType: {
type: String as PropType<ListType>,
default: 'picture-card',
},
helpText: {
type: String as PropType<string>,
default: '',
},
// 文件最大多少MB
maxSize: {
type: Number as PropType<number>,
default: 2,
},
// 最大数量的文件Infinity不限制
maxNumber: {
type: Number as PropType<number>,
default: 1,
},
// 根据后缀,或者其他
accept: {
type: Array as PropType<string[]>,
default: () => [],
},
multiple: {
type: Boolean as PropType<boolean>,
default: false,
},
uploadParams: {
type: Object as PropType<any>,
default: () => ({}),
},
api: {
type: Function as PropType<PromiseFn>,
default: null,
required: true,
},
name: {
type: String as PropType<string>,
default: 'file',
},
filename: {
type: String as PropType<string>,
default: null,
},
fileListOpenDrag: {
type: Boolean,
default: true,
},
fileListDragOptions: {
type: Object as PropType<SortableOptions>,
default: () => ({}),
},
};
export const uploadContainerProps = {
value: {
type: Array as PropType<string[]>,
default: () => [],
},
...basicProps,
showPreviewNumber: {
type: Boolean as PropType<boolean>,
default: true,
},
emptyHidePreview: {
type: Boolean as PropType<boolean>,
default: false,
},
};
export const previewProps = {
value: {
type: Array as PropType<string[]>,
default: () => [],
},
};
export const fileListProps = {
columns: {
type: Array as PropType<FileBasicColumn[]>,
default: null,
},
actionColumn: {
type: Object as PropType<FileBasicColumn>,
default: null,
},
dataSource: {
type: Array as PropType<any[]>,
default: null,
},
openDrag: {
type: Boolean,
default: false,
},
dragOptions: {
type: Object as PropType<SortableOptions>,
default: () => ({}),
},
};

View File

@ -0,0 +1,46 @@
import { BasicColumn } from '@/components/Table';
import { UploadApiResult } from '@/api/sys/model/uploadModel';
export enum UploadResultStatus {
DONE = 'done',
SUCCESS = 'success',
ERROR = 'error',
UPLOADING = 'uploading',
}
export interface FileItem {
thumbUrl?: string;
name: string;
size: string | number;
type?: string;
percent: number;
file: File;
status?: UploadResultStatus;
response?: UploadApiResult;
uuid: string;
}
export interface PreviewFileItem {
url: string;
name: string;
type: string;
}
export interface FileBasicColumn extends Omit<BasicColumn, 'customRender'> {
/**
* Renderer of the table cell. The return value should be a VNode, or an object for colSpan/rowSpan config
* @type Function | ScopedSlot
*/
customRender?: Function;
/**
* Title of this column
* @type any (string | slot)
*/
title: string;
/**
* Display field of the data record, could be set like a.b.c
* @type string
*/
dataIndex: string;
}

View File

@ -9,7 +9,7 @@
<template #closeIcon>
<CloseCircleOutlined />
</template>
<div class="title">上传shp</div>
<div class="title">上传数据</div>
<div class="content">
<a-steps
class="steps"
@ -45,6 +45,7 @@
</div>
</div>
<div class="upload-form">
<a-form
ref="formRef"
:model="uploadFrom"
@ -55,26 +56,74 @@
<a-form-item label="服务名称" name="serverName">
<a-input v-model:value="uploadFrom.serverName" placeholder="请输入服务名称" />
</a-form-item>
<a-form-item label="空间参考" name="spaceType">
<!-- <a-input v-model:value="uploadFrom.spaceType" /> -->
<a-select v-model:value="uploadFrom.spaceType" placeholder="请选择空间参考">
<a-select-option value="EPSG:4326">EPSG:4326</a-select-option>
<a-select-option value="EPSG:3857">EPSG:3857</a-select-option>
<a-select-option value="EPSG:900913">EPSG:900913</a-select-option>
<!-- 显示条件文件类型为Excel时 -->
<a-form-item label="图斑数据" name="hasFeature" v-if="!isShp">
<a-select v-model:value="uploadFrom.hasFeature" placeholder="请选择是否具有图斑数据">
<a-select-option value="1"></a-select-option>
<a-select-option value="0"></a-select-option>
</a-select>
</a-form-item>
<a-form-item label="表名" name="tableName">
<a-input v-model:value="uploadFrom.tableName" placeholder="请输入表名" />
<!-- 显示条件文件类型为shp 或者 类型为Excel时有图斑数据 -->
<a-form-item label="空间参考" name="spaceType" v-if="isShp || (!isShp && uploadFrom.hasFeature == '1')">
<a-select v-model:value="uploadFrom.spaceType" placeholder="请选择空间参考">
<a-select-option value="EPSG:4326">EPSG:4326</a-select-option>
<a-select-option value="3857">EPSG:3857</a-select-option>
<a-select-option value="900913">EPSG:900913</a-select-option>
</a-select>
</a-form-item>
<!-- 显示条件文件类型为Excel有图斑时 -->
<a-form-item label="数据类型" name="spaceType" v-if="!isShp && uploadFrom.hasFeature == '1'">
<a-select v-model:value="uploadFrom.layerType" placeholder="请选择数据类型">
<a-select-option value="point"></a-select-option>
<a-select-option value="linestring">线</a-select-option>
<a-select-option value="polygon"></a-select-option>
</a-select>
</a-form-item>
<a-form-item label="数据表名" name="tableName">
<a-row :gutter="12">
<a-col :span="20">
<a-input v-model:value="uploadFrom.tableName" placeholder="请输入表名" />
</a-col>
<a-col :span="4">
<!-- <a-tooltip title="从现有数据表中选择">
<a-button type="primary" :icon="h(PlusOutlined)" @click="handlerGetExistsTableList"/>
</a-tooltip> -->
<a-popover placement="topLeft">
<template #content>
<a-table :dataSource="dataSource" :columns="columns" :size="'small'" >
<template #bodyCell="{ column,record }">
<template v-if="column.key === 'operation'">
<a-button type="" :icon="h(PlusOutlined)" @click="handlerGetExistsTableList(record)" />
</template>
</template>
</a-table>
</template>
<template #title>
<span>从现有数据表中选择</span>
</template>
<a-button type="primary" :icon="h(PlusOutlined)" />
</a-popover>
</a-col>
</a-row>
</a-form-item>
</a-form>
<div class="upload-span-button">
<a-button type="primary" :icon="h(PlusOutlined)" @click="submitShp"></a-button>
<a-button type="primary" :icon="h(CloudUploadOutlined)" @click="submitShp"></a-button>
</div>
</div>
</div>
<div class="edit-info-div" v-show="current === 1">
<a-table
:columns="columns"
:columns="tablecolumns"
:data-source="dataList"
:pagination="false"
:bordered="true"
@ -112,6 +161,7 @@
>
</div>
</div>
<div class="submit-success" v-show="current === 2">
<div class="success-content">
<CheckCircleOutlined style="font-size: 100px; color: #1fd286; margin-bottom: 30px" />
@ -119,6 +169,11 @@
<div><a-button type="primary">查看数据</a-button></div>
</div>
</div>
<!-- 已有数据表 -->
<div class="exist-table-list" v-if="showExistTableList">
</div>
</div>
</a-modal>
</template>
@ -132,29 +187,54 @@
CheckCircleOutlined,
} from '@ant-design/icons-vue';
import './index.scss';
import { InboxOutlined } from '@ant-design/icons-vue';
import { InboxOutlined,CloudUploadOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import type { UploadChangeParam } from 'ant-design-vue';
import type { UploadProps } from 'ant-design-vue';
// import { uploadShp } from '@/api/sys/analysis.ts'
import axios from 'axios';
import { v4 as uuidv4 } from 'uuid';
import { FILETYPE } from '../util'
import { FILETYPE } from '../util'
import {ObjectToUrl} from '../src/tool'
const dataSource = reactive([
{
"tablename":"monitor"
},
{
"tablename":"monitor0527"
},
])
const columns = reactive([
{
title: '数据表名称',
dataIndex: 'tablename',
key: 'tablename',
},{
title: '选择数据表',
dataIndex: 'operation',
key: 'operation',
}
])
const current = ref(0);
const fileList = ref<UploadProps['fileList']>([]);
const props = defineProps(['openModal']);
const emits = defineEmits(['update:openModal']);
const uploadFrom = reactive({
serverName: '',
serverName: null,
hasFeature:null,
spaceType: null,
tableName: '',
layerType:null,
tableName: null,
});
const formRef = ref();
const dataList = ref([]);
const isShp = ref(false);
const isShp = ref<Boolean>(true);
const showExistTableList = ref<Boolean>(false)
// todo
const columns = [
const tablecolumns = [
{ title: 'Shp原始字段', dataIndex: 'name', key: 'name' },
{ title: '数据类型', dataIndex: 'type', key: 'type' },
{ title: '数据长度', dataIndex: 'length', key: 'length' },
@ -162,44 +242,146 @@ import { FILETYPE } from '../util'
{ title: '中文名称', dataIndex: 'initName', key: 'initName' },
{ title: '操作', dataIndex: 'operation', key: 'operation' },
];
const uploadFormRules = {
serverName: [{ required: true, message: '请输入服务名称', trigger: 'blur' }],
spaceType: [{ required: true, message: '请选择参考系', trigger: 'blur' }],
tableName: [{ required: true, message: '请输入表名', trigger: 'blur' }],
};
const beforeUpload: UploadProps['beforeUpload'] = (file) => {
console.log('beforeUpload',file)
file.type === FILETYPE.ZIP? isShp.value = true: isShp.value = false
const uploadFormRules = reactive({
serverName: [{ required: true, message: '请输入服务名称', trigger: 'blur' }],
hasFeature: [{ required: true, message: '请选择是否有图斑数据', trigger: 'blur' }],
spaceType: [{ required: true, message: '请选择参考系', trigger: 'blur' }],
layerType: [{ required: true, message: '请选数据类型', trigger: 'blur' }],
tableName: [{ required: true, message: '请输入表名', trigger: 'blur' }],
});
const beforeUpload:UploadProps['beforeUpload'] = (file) => {
file.type === FILETYPE.ZIP ? isShp.value = true: isShp.value = false
fileList.value = [file];
return false;
};
const handlerUploadFile = ()=>{
let url = "http://192.168.10.102:9500/api/Files/Upload"
const [proxyFile] = fileList.value
let file = proxyFile.originFileObj
let formData = new FormData();
formData.append('files', file)
// formData.append('serverName',uploadFrom.serverName)
// formData.append('spaceType',uploadFrom.spaceType)
// formData.append('tableName',uploadFrom.tableName)
axios.post(url,formData,{headers: {'Content-Type': 'multipart/form-data;charset=UTF-8','X-Token':"95a1a7a8"}}).then(res => {
alert(res.data.result[0].filePath);
handlerCreateLayer(res.data.result[0].filePath)
})
}
const handlerCreateLayer =(filePath)=>{
// upload 20240528\\2024052814563161320172.zip 20240528/2024052814563161320172.zip
filePath = filePath.replace(/\\/,'/');
let addForm = {
filePath:filePath,
tableName:uploadFrom.tableName,
srid:uploadFrom.spaceType
}
let params = ObjectToUrl(addForm);
axios.post("http://192.168.10.102:9500/api/PolygonalShape/CreateGISLayer"+params,{},{headers:{'Content-Type': 'multipart/form-data;charset=UTF-8','X-Token':"95a1a7a8"}}).then(res=>{
console.log("helloworld",res);
})
}
const submitShp = () => {
formRef.value.validate().then(() => {
if(fileList.value?.length < 1){
message.warning('请选择shp文件')
message.warning('请选择需要上传的文件')
return
}
// FormData()
let formData = new FormData();
const [proxyFile] = fileList.value
let file = proxyFile.originFileObj
const [proxyFile] = fileList.value
let file = proxyFile.originFileObj
formData.append('file', file)
formData.append('serverName',uploadFrom.serverName)
formData.append('spaceType',uploadFrom.spaceType)
formData.append('tableName',uploadFrom.tableName)
let url = ""
isShp.value? url = 'http://221.2.83.254:9006/geoserver/uploadFile': url = 'http://221.2.83.254:9006/geoserver/uploadExcelFile'
axios.post(url,formData,{headers: {'Content-Type': 'multipart/form-data;charset=UTF-8'}}).then(res => {
// isShp.value ? url = "http://192.168.10.102:9500/api/Files/Upload" : url = "http://192.168.10.102:9500/api/Files/Upload"
// let data = [
// {
// "length": 1024,
// "name": "name",
// "type": "varchar"
// },
// {
// "length": 1024,
// "name": "num",
// "type": "varchar"
// },
// {
// "length": 1024,
// "name": "type",
// "type": "varchar"
// },
// {
// "length": 1024,
// "name": "shebeiid",
// "type": "varchar"
// },
// {
// "length": 1024,
// "name": "forestryty",
// "type": "varchar"
// },
// {
// "length": "",
// "name": "geom",
// "type": "geometry"
// },
// {
// "length": 1024,
// "name": "road",
// "type": "varchar"
// },
// {
// "length": 1024,
// "name": "checksite",
// "type": "varchar"
// },
// {
// "length": 1024,
// "name": "lng",
// "type": "varchar"
// },
// {
// "length": 1024,
// "name": "lat",
// "type": "varchar"
// }
// ]
axios.post(url,formData,{headers: {'Content-Type': 'multipart/form-data;charset=UTF-8'}}).then(res => {
let data = res.data.data.heads
let showData = data.map(item => {
return {...item,refName:item.name.toLowerCase(),initName:item.name,key:uuidv4()}
})
dataList.value = showData
current.value++
}).catch(err => {
console.log(err)
})
@ -214,6 +396,7 @@ const closeModal = () => {
fileList.value = []
current.value = 0
}
const deleteListItem = (record) => {
dataList.value = dataList.value.filter(item => item.key !== record.key)
}
@ -230,22 +413,27 @@ const insertListItem = () => {
const submitDataList = () => {
let refRelation = {}
// let refRelation = {}
dataList.value.forEach((item,index)=>{
refRelation[item.refName] = item.initName;
})
// dataList.value.forEach((item,index)=>{
// refRelation[item.refName] = item.initName;
// })
console.log("refRelation",refRelation);
// console.log("refRelation",refRelation);
let exportForm = {
"newHeads": dataList.value,
"refRelation": JSON.stringify(refRelation),
}
// let exportForm = {
// "newHeads": dataList.value,
// "refRelation": JSON.stringify(refRelation),
// }
// console.log(dataList.value)
// current.value++
current.value++
}
//
const handlerGetExistsTableList = (record )=>{
uploadFrom.tableName = record.tablename
}
</script>
@ -336,5 +524,14 @@ const submitDataList = () => {
flex-direction: column;
}
}
.exist-table-list{
width:100%;
height: calc( 100% - 60px);
position:absolute;
top:60px;
left:0px;
background:#fff;
border-radius: 12px;
}
}
</style>

View File

@ -36,7 +36,13 @@
//
import MapboxDraw from '@mapbox/mapbox-gl-draw';
import { generateUUID,getGeometryCenter } from './src/tool'
//
import { SwitchLayerControl,MeasureControl } from 'mapbox-extensions'
import 'mapbox-extensions/dist/index.css'
import U from 'mapbox-gl-utils';
import 'mapbox-gl/dist/mapbox-gl.css';
import './src/index.less';
@ -156,6 +162,23 @@
});
window.handlerCopyFeature = handlerCopyFeature;
map.addControl(new MeasureControl({
horizontal : true, //default false
btnBgColor : '#ffffff', //default '#ffffff'
btnActiveColor:'#ddd', //default '#ddd'
geometryClick:true, //defualt false
enableModes:['Point','LineString','Polygon'],//default all
onStart:()=>{},
onStop:()=>{},
measurePointOptions:{
},
measureLineStringOptions:{
},
measurePolygonOptions:{
}
}),"top-left")
});
});
//
@ -242,57 +265,66 @@
//
const handlerInitDrawTool = (feature, bool) => {
if (feature.features.length > 0) {
feature.features.forEach((item) => {
if (item.geometry.type == 'MultiPolygon') {
let arr: any = ref([]);
item.geometry.coordinates.forEach((val) => {
arr.value.push(val[0]);
});
item.geometry.coordinates = arr.value;
item.geometry.type = 'Polygon';
}
});
}
// if (feature.features.length > 0) {
// feature.features.forEach((item) => {
// if (item.geometry.type == 'MultiPolygon') {
// let arr: any = ref([]);
// item.geometry.coordinates.forEach((val) => {
// arr.value.push(val[0]);
// });
// item.geometry.coordinates = arr.value;
// item.geometry.type = 'Polygon';
// }
// });
// }
geojson.geojson = feature;
console.log('drawTool', drawTool);
console.log('feature', feature);
if (drawTool) {
drawTool.deleteAll();
if (feature.features) {
drawTool.set(geojson.geojson);
geojson.geojson = feature;
if (drawTool) {
drawTool.deleteAll();
if (feature.features) {
drawTool.set(geojson.geojson);
}
} else {
drawTool = new MapboxDraw({
modes: {
...MapboxDraw.modes,
draw_point: SnapPointMode,
draw_polygon: SnapPolygonMode,
draw_line_string: SnapLineMode,
direct_select: SnapDirectSelect,
},
styles: customDrawStyles,
userProperties: true,
snap: true,
snapOptions: {
snapPx: 12, // defaults to 15
snapToMidPoints: true, // defaults to false
snapVertexPriorityDistance: 0.0025, // defaults to 1.25
},
guides: false,
});
map.addControl(drawTool, 'top-right');
if (feature.features) {
drawTool.set(geojson.geojson);
}
}
} else {
drawTool = new MapboxDraw({
modes: {
...MapboxDraw.modes,
draw_point: SnapPointMode,
draw_polygon: SnapPolygonMode,
draw_line_string: SnapLineMode,
direct_select: SnapDirectSelect,
},
styles: customDrawStyles,
userProperties: true,
snap: true,
snapOptions: {
snapPx: 12, // defaults to 15
snapToMidPoints: true, // defaults to false
snapVertexPriorityDistance: 0.0025, // defaults to 1.25
},
guides: false,
});
map.addControl(drawTool, 'top-right');
if (feature.features) {
drawTool.set(geojson.geojson);
}
}
//
if (bool) {
//
// if (bool) {
// drawing.value = true;
// } else {
// drawing.value = false;
// }
drawing.value = true;
} else {
drawing.value = false;
}
};
//
@ -386,7 +418,7 @@
const handlerLocation = (lngLat) => {
map.flyTo({
center: lngLat,
zoom: 16,
zoom: 17,
speed: 10, //
curve: 1, // 线
easing(t) {
@ -476,42 +508,40 @@
const handlerDraw = (features = null, bool = false) => {
console.log("features",features);
let geo = {
type: 'FeatureCollection',
features: [],
};
console.log('features', features);
console.log('bool', bool);
if (features == null) {
bool = true;
} else {
if (features.length > 0) {
for (let i = 0; i < features.length; i++) {
try {
let featureTemp = WktToGeojson(features[i].value);
let feature = {
id: 'cd1d93c0e4a6747ff597f' + parseInt(1000000000 * Math.random()).toString(),
type: 'Feature',
properties: {},
geometry: featureTemp,
id: generateUUID(),
type: 'Feature',
properties: {},
geometry: featureTemp,
};
geo.features.push(feature);
//
if(i == 0){
let lngLat = getGeometryCenter(feature);
handlerLocation(lngLat);
}
} catch (e) {
console.log('WKT解析错误请检查WKT数据格式是否有误');
}
}
}
}
handlerInitDrawTool(geo, bool);
};
defineExpose({
@ -519,6 +549,7 @@
handlerLocation,
handlerCancleDraw,
});
</script>
<style>
@ -526,10 +557,12 @@
width: 100%;
height: 100%;
}
.map-box {
width: 100%;
height: 100%;
}
.layer-control-center {
position: absolute;
padding: 10px;
@ -538,20 +571,23 @@
background: #ffffff;
border-radius: 12px;
}
.layer-control-center p {
margin: 0px;
}
.draw-control-center {
position: absolute;
padding: 7px;
padding: 8px;
top: 15px;
right: 15px;
background: #ffffff;
border-radius: 12px;
}
.draw-control-center .draw-btn {
float: left;
margin: 0px 6px;
margin: 0px 7px;
padding: 5px;
border-radius: 5px;
}
@ -560,9 +596,11 @@
background-color: rgb(0 0 0/5%);
cursor: pointer;
}
.mapboxgl-ctrl-group:not(:empty) {
box-shadow: none;
}
.mapboxgl-ctrl-group {
padding: 10px;
border-radius: 12px;
@ -575,17 +613,20 @@
height: 20px !important;
float: left;
}
.mapboxgl-ctrl-top-right {
}
.mapboxgl-ctrl-group button + button {
border: 0px;
margin: 0px 10px;
margin: 0px 6px;
}
.mapbox-gl-draw_ctrl-draw-btn:hover {
transform: scale(1.2);
}
.mapbox-gl-draw_polygon {
background-image: url(/polygon.png);
background-size: 100% 100%;
@ -603,7 +644,7 @@
background-size: 100% 100%;
width: 100px;
height: 100px;
margin: 0px 10px;
margin: 0px 6px;
}
.mapbox-gl-draw_trash {
@ -626,5 +667,15 @@
width: 100px;
height: 100px;
}
.jas-ctrl-measure{
position:relative;
top:6px;
left:190px;
}
.jas-ctrl-measure-item{
height:22px;
}
</style>

View File

@ -225,70 +225,91 @@
popup.remove();
createMessage.success('复制成功!');
};
</script>
<style>
.mapboxgl-ctrl-group:not(:empty) {
box-shadow: none;
}
.mapboxgl-ctrl-group {
background: none !important;
}
.mapbox-gl-draw_ctrl-draw-btn {
width: 40px !important;
height: 40px !important;
float: left;
border-radius: 50%;
}
.mapboxgl-ctrl-top-right {
}
.mapboxgl-ctrl-group button + button {
border: 0px;
margin: 0px 3px;
}
.mapbox-gl-draw_ctrl-draw-btn:hover {
transform: scale(1.2);
}
.mapbox-gl-draw_polygon {
background-image: url(/polygon.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.mapbox-gl-draw_point {
background-image: url(/point.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.mapbox-gl-draw_line {
background-image: url(/line.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.mapbox-gl-draw_trash {
background-image: url(/del.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.mapbox-gl-draw_combine {
background-image: url(/combine.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.mapbox-gl-draw_uncombine {
background-image: url(/uncombine.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.draw-control-center .draw-btn {
float: left;
margin: 0px 6px;
padding: 5px;
border-radius: 5px;
}
.draw-control-center .draw-btn:hover {
background-color: rgb(0 0 0/5%);
cursor: pointer;
}
.mapboxgl-ctrl-group:not(:empty) {
box-shadow: none;
}
.mapboxgl-ctrl-group {
padding: 10px;
border-radius: 12px;
position: relative;
right: 140px;
top: 5px;
}
.mapbox-gl-draw_ctrl-draw-btn {
width: 20px !important;
height: 20px !important;
float: left;
}
.mapboxgl-ctrl-top-right {
}
.mapboxgl-ctrl-group button + button {
border: 0px;
margin: 0px 6px;
}
.mapbox-gl-draw_ctrl-draw-btn:hover {
transform: scale(1.2);
}
.mapbox-gl-draw_polygon {
background-image: url(/polygon.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.mapbox-gl-draw_point {
background-image: url(/point.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.mapbox-gl-draw_line {
background-image: url(/line.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
margin: 0px 6px;
}
.mapbox-gl-draw_trash {
background-image: url(/del.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.mapbox-gl-draw_combine {
background-image: url(/combine.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.mapbox-gl-draw_uncombine {
background-image: url(/uncombine.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
</style>

View File

@ -42,6 +42,7 @@
</a-button>
<a-button type="primary" @click="handlerAddToLayerList">
=======
</a-button> -->
<a-button type="primary">
<template #icon>
@ -86,14 +87,19 @@
</template>
<script setup lang="ts">
import { PlusOutlined } from '@ant-design/icons-vue'
import { errorImage } from '../../util.js'
import { ref,defineEmits } from "vue"
import { ref,defineEmits,reactive } from "vue"
import MapboxMap from '@/components/MapboxMaps/index.vue'
import { DrawingType } from '@/enums/mapEnum';
import { useMessage } from '@/hooks/web/useMessage';
const { createMessage } = useMessage();
const emits = defineEmits(["handlerAddToLayerList"])
const data = ref('vector-data')
const sort = ref('default')

View File

@ -8,4 +8,5 @@ const GeojsonToWkt = (geojsonData)=> {
return WKT.convert(geojsonData)
}
export {WktToGeojson,GeojsonToWkt}

View File

@ -1,11 +1,11 @@
// 生成UUID
import { ControlOutlined } from '@ant-design/icons-vue';
import * as turf from '@turf/turf'
// js生成UUID
const generateUUID = ()=>{
var d = new Date().getTime(); //Timestamp
var d2 = (performance && performance.now && (performance.now()*1000)) || 0;
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16;
if(d > 0) {
@ -19,4 +19,42 @@ const generateUUID = ()=>{
});
}
export { generateUUID }
// js 针对后端post接口参数拼接到url的情况 将json参数转换为 ?key1=value1&key2=value2
const ObjectToUrl = (obj)=>{
let params = "?";
for(let item in obj){
params+=item+"="+obj[item]+"&"
}
return params;
}
// turf获取几何图形的中心
const getGeometryCenter = (geometry)=>{
let coordinates = [];
switch(geometry.geometry.type.toUpperCase()){
case "POINT":
break;
case "MULTIPOINT":
break;
case "LINESTRING":
break;
case "MULTILINESTRING":
break;
case "POLYGON":
coordinates = geometry.geometry.coordinates
break;
case "MULTIPOLYGON":
coordinates = geometry.geometry.coordinates[0]
break;
}
let polygon = turf.polygon(coordinates);
let center = turf.centerOfMass(polygon);
return center.geometry.coordinates;
}
export { generateUUID,ObjectToUrl,getGeometryCenter }

View File

@ -246,6 +246,7 @@
isAddSign: false,
isTransfer: false,
isBatchAudit: false,
IsSingleTask: false,
autoAgree: '',
noAuditor: '1',
rejectType: '1',

View File

@ -26,6 +26,9 @@
<a-form-item label="允许批量审核">
<a-switch v-model:checked="node.isBatchAudit" @change="updateWfData('isBatchAudit')" />
</a-form-item>
<a-form-item label="允许单任务">
<a-switch v-model:checked="node.IsSingleTask" @change="updateWfData('IsSingleTask')" />
</a-form-item>
<a-form-item label="自动同意规则">
<a-select
v-model:value="node.autoAgree"

View File

@ -1,6 +1,10 @@
import { withInstall } from '@/utils';
import basicUpload from './src/BasicUpload.vue';
import uploadImage from './src/components/ImageUpload.vue';
import uploadVideo from './src/components/VideoUpload.vue';
import uploadFile from './src/components/FileUpload.vue'
export const ImageUpload = withInstall(uploadImage);
export const BasicUpload = withInstall(basicUpload);
export const VideoUpload = withInstall(uploadVideo);
export const FileUpload = withInstall(uploadFile);

View File

@ -0,0 +1,264 @@
<template>
<div>
<UploadDragger
v-bind="$attrs"
:list-type="listType"
:accept="getStringAccept"
:multiple="multiple"
:showUploadList="false"
:maxCount="maxNumber"
:before-upload="beforeUpload"
:custom-request="customRequest"
@preview="handlePreview"
@remove="handleRemove"
>
<!-- <div v-if="fileList && fileList.length < maxNumber">
<plus-outlined />
<div style="margin-top: 8px">{{ t('component.upload.upload') }}</div>
</div> -->
<p class="ant-upload-drag-icon">
<inbox-outlined></inbox-outlined>
</p>
<p class="ant-upload-text">单击或拖动文件到此区域进行上传</p>
<p class="ant-upload-hint">
支持单次或批量上传
</p>
</UploadDragger>
<div class="file-item" v-for="(item,index) in fileList" :key="index">
{{ item.name }}
<span class="delete-btn" @click="handlerDelete(index)"><DeleteOutlined/></span>
</div>
<Modal :open="previewOpen" :title="previewTitle" :footer="null" @cancel="handleCancel">
<img alt="" style="width: 100%" :src="previewImage" />
</Modal>
</div>
</template>
<script lang="ts" setup>
import { ref, toRefs, watch } from 'vue';
import { PlusOutlined,InboxOutlined,DeleteOutlined } from '@ant-design/icons-vue';
import type { UploadFile, UploadProps } from 'ant-design-vue';
import { Modal, UploadDragger } from 'ant-design-vue';
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
import { useMessage } from '@/hooks/web/useMessage';
import { isArray, isFunction, isObject, isString } from '@/utils/is';
import { warn } from '@/utils/log';
import { useI18n } from '@/hooks/web/useI18n';
import { useUploadType } from '../hooks/useUpload';
import { uploadContainerProps } from '../props';
import { isImgTypeByName } from '../helper';
import { UploadResultStatus } from '@/components/Upload/src/types/typing';
import { fileUploadApi } from '@/api/sys/upload';
defineOptions({ name: 'ImageUpload' });
const emit = defineEmits(['change', 'update:value', 'delete']);
const props = defineProps({
...uploadContainerProps,
});
const { t } = useI18n();
const { createMessage } = useMessage();
const { accept, helpText, maxNumber, maxSize } = toRefs(props);
const isInnerOperate = ref<boolean>(false);
const { getStringAccept } = useUploadType({
acceptRef: accept,
helpTextRef: helpText,
maxNumberRef: maxNumber,
maxSizeRef: maxSize,
});
const previewOpen = ref<boolean>(false);
const previewImage = ref<string>('');
const previewTitle = ref<string>('');
const fileList = ref<UploadProps['fileList']>([]);
const isLtMsg = ref<boolean>(true);
const isActMsg = ref<boolean>(true);
watch(
() => props.value,
(v) => {
if (isInnerOperate.value) {
isInnerOperate.value = false;
return;
}
if (v) {
let value: string[] = [];
if (isArray(v)) {
value = v;
} else {
value.push(v);
}
fileList.value = value.map((item, i) => {
if (item && isString(item)) {
return {
uid: -i + '',
name: item.substring(item.lastIndexOf('/') + 1),
status: 'done',
url: item,
};
} else if (item && isObject(item)) {
return item;
} else {
return;
}
}) as UploadProps['fileList'];
}
let arr = props.value?.split(",") as [];
fileList.value = [];
const { server } = props
arr?.forEach((item,index)=>{
if(item){
fileList.value?.push({
uid: '-1',
name: item,
status: 'done',
url: server+item
})
}
})
},
);
function getBase64<T extends string | ArrayBuffer | null>(file: File) {
return new Promise<T>((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
resolve(reader.result as T);
};
reader.onerror = (error) => reject(error);
});
}
const handlePreview = async (file: UploadFile) => {
console.log("fileEEEEE",file);
if (!file.url && !file.preview) {
file.preview = await getBase64<string>(file.originFileObj!);
}
previewImage.value = file.url || file.preview || '';
previewOpen.value = true;
previewTitle.value =
file.name || previewImage.value.substring(previewImage.value.lastIndexOf('/') + 1);
};
const handleRemove = async (file: UploadFile) => {
if (fileList.value) {
const index = fileList.value.findIndex((item) => item.uid === file.uid);
index !== -1 && fileList.value.splice(index, 1);
const value = getValue();
isInnerOperate.value = true;
emit('change', value);
emit('delete', file);
}
};
const handlerDelete = (index) => {
fileList.value.splice(index,1);
let value = getValue();
emit("change",value);
}
const handleCancel = () => {
previewOpen.value = false;
previewTitle.value = '';
};
const beforeUpload = (file: File) => {
const { maxSize, accept } = props;
const { name } = file;
// const isAct = isImgTypeByName(name);
const isAct = true;
if (!isAct) {
createMessage.error(t('component.upload.acceptUpload', [accept]));
isActMsg.value = false;
//
setTimeout(() => (isActMsg.value = true), 1000);
}
const isLt = file.size / 1024 / 1024 > maxSize;
if (isLt) {
createMessage.error(t('component.upload.maxSizeMultiple', [maxSize]));
isLtMsg.value = false;
//
setTimeout(() => (isLtMsg.value = true), 1000);
}
return (isAct && !isLt) || Upload.LIST_IGNORE;
};
async function customRequest(info: UploadRequestOption<any>) {
const { api,server,action } = props;
// if (!api || !isFunction(api)) {
// return warn('upload api must exist and be a function');
// }
try {
const res = await fileUploadApi?.({
data: {
...(props.uploadParams || {}),
},
file: info.file,
name: props.name,
filename: props.filename,
},server+action);
fileList.value?.push({
uid: '-1',
name: info.file.name,
status: 'done',
url: server+"/"+res.data.result[0].filePath,
})
info.onSuccess!();
const value = getValue();
// isInnerOperate.value = true;
emit('change', value);
} catch (e: any) {
info.onError!(e);
}
}
function getValue() {
let path = "";
const {server} = props;
fileList.value?.forEach((item,index)=>{
path+=item.url?.replace(server,"")+",";
})
return path;
}
</script>
<style lang="less">
.ant-upload-select-picture-card i {
color: #999;
font-size: 32px;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
.file-item{
width:100%;
height:40px;
padding:10px;
border-radius:6px;
border:1px dashed #d9d9d9;
margin:10px 0px;
}
.delete-btn{
float:right;
color:#d9d9d9;
cursor:pointer;
}
.delete-btn:hover{
color:#999;
}
</style>

View File

@ -1,11 +1,22 @@
<template>
<div>
<div class="video-item" v-for="(item,index) in fileList" :key="index">
<div class="video-delete-btn" @click="handlerDelete(index)">
<CloseOutlined/>
</div>
<a-image
width="100px"
:src="item.url"
></a-image>
</div>
<Upload
v-bind="$attrs"
v-model:file-list="fileList"
:list-type="listType"
:accept="getStringAccept"
:multiple="multiple"
:showUploadList="false"
:maxCount="maxNumber"
:before-upload="beforeUpload"
:custom-request="customRequest"
@ -17,16 +28,18 @@
<div style="margin-top: 8px">{{ t('component.upload.upload') }}</div>
</div>
</Upload>
<Modal :open="previewOpen" :title="previewTitle" :footer="null" @cancel="handleCancel">
<img alt="" style="width: 100%" :src="previewImage" />
</Modal>
</div>
</template>
<script lang="ts" setup>
import { ref, toRefs, watch } from 'vue';
import { PlusOutlined } from '@ant-design/icons-vue';
import type { UploadFile, UploadProps } from 'ant-design-vue';
import { ref, toRefs, watch,reactive, onMounted } from 'vue';
import { PlusOutlined,CloseOutlined } from '@ant-design/icons-vue';
import type { UploadFile, UploadProps,UploadChangeParam } from 'ant-design-vue';
import { Modal, Upload } from 'ant-design-vue';
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
import { useMessage } from '@/hooks/web/useMessage';
@ -37,6 +50,8 @@
import { uploadContainerProps } from '../props';
import { isImgTypeByName } from '../helper';
import { UploadResultStatus } from '@/components/Upload/src/types/typing';
import { actions } from '@/views/demo/page/account/center/data';
import { fileUploadApi } from '@/api/sys/upload';
defineOptions({ name: 'ImageUpload' });
@ -46,29 +61,32 @@
});
const { t } = useI18n();
const { createMessage } = useMessage();
const { accept, helpText, maxNumber, maxSize } = toRefs(props);
const { accept, helpText, maxNumber, maxSize} = toRefs(props);
const isInnerOperate = ref<boolean>(false);
const { getStringAccept } = useUploadType({
acceptRef: accept,
helpTextRef: helpText,
maxNumberRef: maxNumber,
maxSizeRef: maxSize,
maxSizeRef: maxSize
});
const previewOpen = ref<boolean>(false);
const previewImage = ref<string>('');
const previewTitle = ref<string>('');
const fileList = ref<UploadProps['fileList']>([]);
const imageList = reactive([])
const isLtMsg = ref<boolean>(true);
const isActMsg = ref<boolean>(true);
watch(
() => props.value,
(v) => {
() => props.value,(v) => {
if (isInnerOperate.value) {
isInnerOperate.value = false;
return;
}
if (v) {
let value: string[] = [];
if (isArray(v)) {
@ -76,6 +94,7 @@
} else {
value.push(v);
}
fileList.value = value.map((item, i) => {
if (item && isString(item)) {
return {
@ -90,35 +109,75 @@
return;
}
}) as UploadProps['fileList'];
}
let arr = props.value?.split(",") as [];
fileList.value = [];
const { server } = props
arr.forEach((item,index)=>{
if(item){
fileList.value?.push({
uid: '-1',
name: item,
status: 'done',
url: server+item
})
console.log("fileListItem",fileList.value)
}
})
console.log("ImagefileList",fileList.value);
},
);
function getBase64<T extends string | ArrayBuffer | null>(file: File) {
return new Promise<T>((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
resolve(reader.result as T);
};
reader.onerror = (error) => reject(error);
});
}
// function getBase64<T extends string | ArrayBuffer | null>(file: File) {
// return new Promise<T>((resolve, reject) => {
// const reader = new FileReader();
// reader.readAsDataURL(file);
// reader.onload = () => {
// resolve(reader.result as T);
// };
// reader.onerror = (error) => reject(error);
// });
// }
const handlePreview = async (file: UploadFile) => {
const { server } = props
if (!file.url && !file.preview) {
file.preview = await getBase64<string>(file.originFileObj!);
// file.preview = await getBase64<string>(file.originFileObj!);
}
previewImage.value = file.url || file.preview || '';
console.log("file",file);
previewOpen.value = true;
previewTitle.value =
file.name || previewImage.value.substring(previewImage.value.lastIndexOf('/') + 1);
};
// const handleChange = (info: UploadChangeParam) => {
// if (info.file.status === 'uploading') {
// return;
// }
// if (info.file.status === 'done') {
// console.log("donw",info);
// }
// if (info.file.status === 'error') {
// }
// };
const handlerDelete = (index) => {
fileList.value.splice(index,1);
let value = getValue();
emit("change",value);
}
const handleRemove = async (file: UploadFile) => {
if (fileList.value) {
const index = fileList.value.findIndex((item) => item.uid === file.uid);
index !== -1 && fileList.value.splice(index, 1);
const value = getValue();
isInnerOperate.value = true;
emit('change', value);
@ -152,47 +211,118 @@
};
async function customRequest(info: UploadRequestOption<any>) {
const { api } = props;
if (!api || !isFunction(api)) {
return warn('upload api must exist and be a function');
}
const { api,server,action } = props;
// if (!api || !isFunction(api)) {
// return warn('upload api must exist and be a function');
// }
try {
const res = await props.api?.({
const res = await fileUploadApi?.({
data: {
...(props.uploadParams || {}),
},
file: info.file,
name: props.name,
filename: props.filename,
});
info.onSuccess!(res.data);
},server+action);
fileList.value?.push({
uid: '-1',
name: info.file.name,
status: 'done',
url: server+"/"+res.data.result[0].filePath,
})
info.onSuccess!();
const value = getValue();
isInnerOperate.value = true;
// isInnerOperate.value = true;
emit('change', value);
} catch (e: any) {
console.log(e);
info.onError!(e);
}
}
function getValue() {
const list = (fileList.value || [])
.filter((item) => item?.status === UploadResultStatus.DONE)
.map((item: any) => {
return item?.url || item?.response?.url;
});
return props.multiple ? list : list.length > 0 ? list[0] : '';
// fileList.value.forEach((item,index)=>{
// item.url?.splice(server,"");
// saveData+=item.url+","
// })
// return saveData;
let path = "";
const {server} = props;
fileList.value?.forEach((item,index)=>{
path+=item.url?.replace(server,"")+",";
})
return path;
// const list = (fileList.value || [])
// .filter((item) => item?.status === UploadResultStatus.DONE)
// .map((item: any) => {
// return item?.url || item?.response?.url;
// });
// return props.multiple ? list : list.length > 0 ? list[0] : '';
}
</script>
<style lang="less">
.ant-upload-select-picture-card i {
color: #999;
font-size: 32px;
}
.ant-upload-select-picture-card i {
color: #999;
font-size: 32px;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
.video-item{
position:relative;
width:100px;
height:100px;
margin-right:10px;
margin-bottom:10px;
float:left;
overflow: hidden;
border-radius: 6px;
background:#fff;
text-align: center;
cursor:pointer;
}
.video-delete-btn{
position:absolute;
top:-5px;
right:-5px;
width:30px;
height:30px;
border-bottom-left-radius: 80%;
background:rgb(0 0 0 / 20%);
color:#fff;
line-height: 30px;
text-align: center;
}
.video-item img{
width:80px;
height:80px;
}
.video-item p{
overflow: hidden;
color:#777!important;
font-size:12px;
text-overflow:ellipsis;
white-space: nowrap;
}
.ant-upload-wrapper {
width:100px!important;
}
.video-player{
width:500px;
margin:10px;
}
</style>

View File

@ -187,7 +187,7 @@
item.percent = complete;
},
);
let data = ret != undefined ? ret.data : {};
const { data } = ret;
item.status = UploadResultStatus.SUCCESS;
item.response = data;
return {
@ -206,7 +206,9 @@
//
async function handleStartUpload() {
const { maxNumber } = props;
const { maxNumber,action } = props;
alert(action);
if ((fileListRef.value.length + props.previewFileList?.length ?? 0) > maxNumber) {
return createMessage.warning(t('component.upload.maxNumber', [maxNumber]));
}

View File

@ -0,0 +1,301 @@
<template>
<div>
<div class="video-item" v-for="(item,index) in fileList" :key="index">
<div class="video-delete-btn" @click="handlerDelete(index)">
<CloseOutlined/>
</div>
<img src="./video.png" @click="handlePreview(item)" alt="">
<p>{{ item.name}}</p>
</div>
<Upload
v-bind="$attrs"
:list-type="listType"
:accept="getStringAccept"
:multiple="multiple"
:showUploadList="false"
:maxCount="maxNumber"
:before-upload="beforeUpload"
:custom-request="customRequest"
@preview="handlePreview"
@remove="handleRemove"
>
<div v-if="fileList && fileList.length < maxNumber">
<plus-outlined />
<div style="margin-top: 8px">{{ t('component.upload.upload') }}</div>
</div>
</Upload>
<Modal :open="previewOpen" :title="previewTitle" :footer="null" @cancel="handleCancel">
<!-- <img alt="" style="width: 100%" :src="previewImage" /> -->
<video :src="previewImage" class="video-player" controls muted autoplay></video>
</Modal>
</div>
</template>
<script lang="ts" setup>
import { ref, toRefs, watch,reactive, onMounted } from 'vue';
import { PlusOutlined,CloseOutlined } from '@ant-design/icons-vue';
import type { UploadFile, UploadProps } from 'ant-design-vue';
import { Modal, Upload } from 'ant-design-vue';
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
import { useMessage } from '@/hooks/web/useMessage';
import { isArray, isFunction, isObject, isString } from '@/utils/is';
import { warn } from '@/utils/log';
import { useI18n } from '@/hooks/web/useI18n';
import { useUploadType } from '../hooks/useUpload';
import { uploadContainerProps } from '../props';
import { isVideoTypeByName } from '../helper';
import { UploadResultStatus } from '@/components/Upload/src/types/typing';
import { fileUploadApi } from '@/api/sys/upload';
defineOptions({ name: 'VideoUpload' });
const emit = defineEmits(['change', 'update:value', 'delete']);
const props = defineProps({
...uploadContainerProps,
});
const { t } = useI18n();
const { createMessage } = useMessage();
const { accept, helpText, maxNumber, maxSize } = toRefs(props);
const isInnerOperate = ref<boolean>(false);
const { getStringAccept } = useUploadType({
acceptRef: accept,
helpTextRef: helpText,
maxNumberRef: maxNumber,
maxSizeRef: maxSize,
});
const previewOpen = ref<boolean>(false);
const previewImage = ref<string>('');
const previewTitle = ref<string>('');
const fileList = ref<UploadProps['fileList']>([]);
const isLtMsg = ref<boolean>(true);
const isActMsg = ref<boolean>(true);
const showUploadList = reactive({
showRemoveIcon: true,
showPreviewIcon: true
})
watch(
() => props.value,
(v) => {
if (isInnerOperate.value) {
isInnerOperate.value = false;
return;
}
if (v) {
let value: string[] = [];
if (isArray(v)) {
value = v;
} else {
value.push(v);
}
fileList.value = value.map((item, i) => {
if (item && isString(item)) {
return {
uid: -i + '',
name: item.substring(item.lastIndexOf('/') + 1),
status: 'done',
url: item,
};
} else if (item && isObject(item)) {
return item;
} else {
return;
}
}) as UploadProps['fileList'];
}
let arr = props.value?.split(",") as [];
fileList.value = [];
const { server } = props
arr.forEach((item,index)=>{
if(item){
fileList.value?.push({
uid: '-1',
name: item,
status: 'done',
url: server+item
})
console.log("fileListItem",fileList.value)
}
})
console.log("fileList",fileList.value);
},
);
onMounted(()=>{
})
function getBase64<T extends string | ArrayBuffer | null>(file: File) {
return new Promise<T>((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
resolve(reader.result as T);
};
reader.onerror = (error) => reject(error);
});
}
const handlePreview = async (file: UploadFile) => {
previewImage.value = file.url || file.preview || '';
previewOpen.value = true;
previewTitle.value =
file.name || previewImage.value.substring(previewImage.value.lastIndexOf('/') + 1);
};
const handlerDelete = (index) => {
fileList.value.splice(index,1);
let value = getValue();
emit("change",value);
}
const handleRemove = async (file: UploadFile) => {
if (fileList.value) {
const index = fileList.value.findIndex((item) => item.uid === file.uid);
index !== -1 && fileList.value.splice(index, 1);
const value = getValue();
isInnerOperate.value = true;
emit('change', value);
emit('delete', file);
}
};
const handleCancel = () => {
previewOpen.value = false;
previewTitle.value = '';
};
const beforeUpload = (file: File) => {
const { maxSize, accept } = props;
const { name } = file;
const isAct = isVideoTypeByName(name);
if (!isAct) {
createMessage.error(t('component.upload.acceptUpload', [accept]));
isActMsg.value = false;
//
setTimeout(() => (isActMsg.value = true), 1000);
}
const isLt = file.size / 1024 / 1024 > maxSize;
if (isLt) {
createMessage.error(t('component.upload.maxSizeMultiple', [maxSize]));
isLtMsg.value = false;
//
setTimeout(() => (isLtMsg.value = true), 1000);
}
return (isAct && !isLt) || Upload.LIST_IGNORE;
};
async function customRequest(info: UploadRequestOption<any>) {
const { api,action,server } = props;
// if (!api || !isFunction(api)) {
// return warn('upload api must exist and be a function');
// }
try {
const res = await fileUploadApi?.({
data: {
...(props.uploadParams || {}),
},
file: info.file,
name: props.name,
filename: props.filename,
},server+action);
fileList.value?.push({
uid: '-1',
name: info.file.name,
status: 'done',
url: server+"/"+res.data.result[0].filePath,
})
// info.onSuccess!();
const value = getValue();
isInnerOperate.value = true;
emit('change', value);
} catch (e: any) {
info.onError!(e);
}
}
function getValue() {
const { server } = props;
let saveData = "";
fileList.value.forEach((item,index)=>{
console.log("fileListItem",item);
saveData+=item.url?.replace(server,"")+","
})
return saveData;
}
</script>
<style lang="less" scoped>
.ant-upload-select-picture-card i {
color: #999;
font-size: 32px;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
.video-item{
position:relative;
width:100px;
height:100px;
margin-right:10px;
margin-bottom:10px;
float:left;
overflow: hidden;
border-radius: 6px;
background:#fff;
text-align: center;
cursor:pointer;
}
.video-delete-btn{
position:absolute;
top:-5px;
right:-5px;
width:30px;
height:30px;
border-bottom-left-radius: 80%;
background:rgb(0 0 0 / 20%);
color:#fff;
line-height: 30px;
text-align: center;
}
.video-item img{
width:80px;
height:80px;
}
.video-item p{
overflow: hidden;
color:#777!important;
font-size:12px;
text-overflow:ellipsis;
white-space: nowrap;
}
.ant-upload-wrapper {
width:100px!important;
}
.video-player{
width:500px;
margin:10px;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -14,6 +14,11 @@ export function isImgTypeByName(name: string) {
return /\.(jpg|jpeg|png|gif|webp)$/i.test(name);
}
export function isVideoTypeByName(name: string) {
return /\.(mp4|mov|avi)$/i.test(name);
}
export function getBase64WithFile(file: File) {
return new Promise<{
result: string;

View File

@ -24,6 +24,14 @@ export const basicProps = {
type: String as PropType<string>,
default: '',
},
action: {
type: String as PropType<string>,
default: '',
},
server: {
type: String as PropType<string>,
default: '',
},
// 文件最大多少MB
maxSize: {
type: Number as PropType<number>,
@ -54,7 +62,7 @@ export const basicProps = {
},
name: {
type: String as PropType<string>,
default: 'file',
default: 'files',
},
filename: {
type: String as PropType<string>,
@ -64,7 +72,6 @@ export const basicProps = {
type: Boolean,
default: true,
},
fileListDragOptions: {
type: Object as PropType<SortableOptions>,
default: () => ({}),

View File

@ -124,5 +124,9 @@
"redoTip": "点击图片可刷新",
"dragText": "请按住滑块拖动",
"successText": "验证通过"
},
"map":{
"refreshSuccess":"获取位置成功!",
"refreshError":"获取位置失败!"
}
}

View File

@ -14,6 +14,7 @@
import MapboxMaps from '@/components/MapboxMaps/MapboxMap.vue';
// import MapboxMaps from '@/components/MapboxMaps/MapComponent.vue';
import {ref,reactive} from 'vue';
import { DrawingType } from '@/enums/mapEnum';
@ -27,7 +28,7 @@
const layers = reactive([
{
id:1,
name:"沂水县道路中心线1",
name:"沂水县道路中心线",
checked:false,
layer:{
'id': 'roadnetLine1',
@ -58,39 +59,6 @@
'line-width': 1
}
}
},{
id:2,
name:"沂水县道路中心线2",
checked:false,
layer:{
'id': 'roadnetLine2',
'type': 'line',
'source': {
type: 'vector',
tiles: [ 'http://192.168.10.102:9020/api/DroneCaseinfo/QueryVectorTileByTable?z={z}&x={x}&y={y}&table=yishuixian&X-Token=1ded3fe7'],
minzoom: 1,
maxzoom: 20
},
"source-layer": "yishuixian",
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': [
"case",
["==", ["get", "handle_status_id"], 0],
"#E6A23C",
["==", ["get", "handle_status_id"], 1],
"#409EFF",
["==", ["get", "handle_status_id"], 2],
"#67C23A",
//
"#E6A23C",
],
'line-width': 1
}
}
}
])
@ -104,12 +72,11 @@
// const feature ="LINESTRING (118.55483239594203 35.81329409678203, 118.54889167836416 35.806406839795216, 118.55647247134772 35.80285975465173, 118.56157492816281 35.803303140294986)"
// const feature = "POLYGON ((118.54774514802972 35.80786133598188, 118.54515277045988 35.79816597053564, 118.55919536113471 35.80085134034624, 118.56021460056033 35.80462789316549, 118.5595188628206 35.80695604583504, 118.5580066425723 35.80815336506183, 118.54774514802972 35.80786133598188))"
let drawFeatures = [
{
"columnName": "mapgeom",
"value": "POLYGON ((118.55901684631719 35.8045110934671, 118.55946931550466 35.80449259041045, 118.55946551324392 35.80463444717644, 118.559024450841 35.80464061486234, 118.55901684631719 35.8045110934671))"
"value": "MULTIPOLYGON (((118.55901684631719 35.8045110934671, 118.55946931550466 35.80449259041045, 118.55946551324392 35.80463444717644, 118.559024450841 35.80464061486234, 118.55901684631719 35.8045110934671)))"
}, {
"columnName": "mapgeom",
"value": "POLYGON ((118.5591119028685 35.804344565958516, 118.5594579087177 35.804344565958516, 118.55945410645693 35.80424279914757, 118.55910049608158 35.80423663146167, 118.5591119028685 35.804344565958516))"
@ -139,25 +106,21 @@ let drawFeatures = [
setTimeout(function(){
MapboxComponent.value.handlerDraw()
// MapboxComponent.value.handlerDraw()
},6000)
//
setTimeout(function(){
MapboxComponent.value.handlerLocation([118.556717,35.80391]);
},6000)
// setTimeout(function(){
// MapboxComponent.value.handlerLocation([118.556717,35.80391]);
// },6000)
const mapDrawControl: DrawingType[] = [DrawingType.Polygon, DrawingType.Line];
const mapOnLoad = (map) => {
//
// map
console.log('map::: ', map);
// mapU

View File

@ -162,12 +162,38 @@
let subTableId = ref(null);
let subTableData = ref([]);
let subTableList = ref([]);
if (props.formConfig.schemas) {
props.formConfig.schemas.forEach((item) => {
if (item.type === 'subTable') {
subTableId.value = item.field;
let tableData = [];
item.columns.forEach((itemColumn) => {
// if (props.formConfig.schemas) {
// props.formConfig.schemas.forEach((item) => {
// if (item.type === 'subTable') {
// subTableId.value = item.field;
// let tableData = [];
// item.columns.forEach((itemColumn) => {
// itemColumn.children.forEach((itemColumnChild) => {
// tableData.push(itemColumnChild);
// subTableColumns.value.push({
// key: itemColumnChild.field,
// title: itemColumnChild.label,
// dataIndex: itemColumnChild.field,
// width: 120,
// ...itemColumnChild,
// });
// });
// });
// scrollValue.value = { x: (subTableColumns.value.length - 1) * 140, y: 300 };
// subTableData.value = tableData;
// }else{
// }
// });
// }
console.log("props.schema",props.schema)
if (props.schema) {
if(props.schema.type === "subTable"){
subTableId.value = props.schema.field
let tableData = [];
props.schema.columns.forEach((itemColumn) => {
itemColumn.children.forEach((itemColumnChild) => {
tableData.push(itemColumnChild);
subTableColumns.value.push({
@ -181,8 +207,7 @@
});
scrollValue.value = { x: (subTableColumns.value.length - 1) * 140, y: 300 };
subTableData.value = tableData;
}
});
}
}
const addListItem = () => {
@ -201,6 +226,9 @@
const delListItem = (column, record) => {
subTableList.value = subTableList.value.filter((item) => item.key != record.key);
};
</script>
<style>

View File

@ -1146,6 +1146,57 @@ const componentAttrs: IBaseComponentProps = {
component: 'Input',
},
],
ImageUpload: [
{
name: 'server',
label: '文件服务器地址',
component: 'Input',
},
{
name: 'action',
label: '文件上传接口',
component: 'Input',
},
{
name: 'name',
label: '附件参数名',
component: 'Input',
},
],
VideoUpload: [
{
name: 'server',
label: '文件服务器地址',
component: 'Input',
},
{
name: 'action',
label: '文件上传接口',
component: 'Input',
},
{
name: 'name',
label: '附件参数名',
component: 'Input',
},
],
FileUpload: [
{
name: 'server',
label: '文件服务器地址',
component: 'Input',
},
{
name: 'action',
label: '文件上传接口',
component: 'Input',
},
{
name: 'name',
label: '附件参数名',
component: 'Input',
},
],
// ColorPicker: [
// {
// name: 'defaultValue',

View File

@ -64,6 +64,7 @@
* @param jsonData
*/
const showModal = (jsonData: IFormConfig) => {
console.log("formModel",state.formModel);
console.log('showModal-', jsonData);
formatRules(jsonData.schemas);
state.formConfig = jsonData as any;

View File

@ -5,7 +5,7 @@ import { IVFormComponent } from '../typings/v-form-component';
import { isArray } from 'lodash-es';
import { componentMap as VbenCmp, add } from '@/components/Form/src/componentMap';
import { ComponentType } from '@/components/Form/src/types';
import { uploadApi,fileUploadApi } from '@/api/sys/upload';
import { componentMap as Cmp } from '../components';
import { Component } from 'vue';
import { getDeptList, getAccountList, getPosGroupList } from '@/api/demo/system';
@ -532,7 +532,63 @@ export const baseComponents: IVFormComponent[] = [
colProps: { span: 24 },
field: '',
componentProps: {},
},
},{
component: 'FileUpload',
label: '文件上传',
icon: 'ant-design:file-add-outlined',
field: '',
colProps: { span: 24 },
componentProps: {
api:fileUploadApi,
maxNumber:10,
maxSize: 2,
name:"files",
action:"/api/Files/Upload",
server:"http://192.168.10.102:9023"
},
},{
component: 'ImageUpload',
label: '图片上传',
icon: 'ant-design:file-image-outlined',
field: '',
colProps: { span: 24 },
componentProps: {
api:fileUploadApi,
maxNumber:10,
accept: ['png', 'jpeg', 'jpg'],
maxSize: 2,
name:"files",
action:"/api/Files/Upload",
server:"http://192.168.10.102:9023"
},
},{
component: 'VideoUpload',
label: '视频上传',
icon: 'ant-design:video-camera-outlined',
field: '',
colProps: { span: 24 },
componentProps: {
api:fileUploadApi,
maxNumber:10,
accept: ['mp4', 'mov', 'avi'],
maxSize: 100,
name:"files",
action:"/api/Files/Upload",
server:"http://192.168.10.102:9023"
},
},{
component: 'Location',
label: '获取位置',
icon: 'ant-design:environment-outlined',
field: '',
colProps: { span: 24 },
componentProps: {
api:()=>1,
maxNumber:10,
accept: ['mp4', 'mov', 'avi'],
maxSize: 100,
},
}
];
// https://next.antdv.com/components/transfer-cn

View File

@ -1,5 +1,12 @@
<template>
<PageWrapper :class="prefixCls">
<PageWrapper :class="prefixCls" v-loading="loadingRef" loading-tip="加载中...">
<Loading
:loading="compState.loading"
:absolute="compState.absolute"
:theme="compState.theme"
:background="compState.background"
:tip="compState.tip"
/>
<div class="btn-box">
<a-button type="primary" :icon="h(SendOutlined)" @click="handleSubmit" class="ml-2"
>提交
@ -68,7 +75,7 @@
</template>
<script lang="ts" setup>
import { h, ref, reactive, onBeforeMount } from 'vue';
import { h, ref, reactive, onBeforeMount, onMounted } from 'vue';
import { ProcessViewer } from '@/components/ProcessViewer/index';
import { PageWrapper } from '@/components/Page';
import { FormViewer } from '@/components/FormViewer';
@ -81,6 +88,7 @@
import { buildGUID } from '@/utils/uuid';
import { IFormConfig } from '@/views/demo/form-design/typings/v-form-component';
import { useMessage } from '@/hooks/web/useMessage';
import { Loading } from '/@/components/Loading';
const { createMessage } = useMessage();
const formBoxRef = ref<any>();
@ -152,7 +160,28 @@
processVisble.value = true;
}
}
const compState = reactive<{
absolute?: boolean;
loading?: boolean;
theme?: 'dark' | 'light';
background?: string;
tip?: string;
}>({
absolute: false,
loading: false,
theme: 'dark',
background: 'rgba(111,111,111,.7)',
tip: '加载中...',
});
function openLoading(absolute: boolean) {
compState.absolute = absolute;
compState.loading = true;
setTimeout(() => {
compState.loading = false;
}, 1000);
}
async function getDetailInfo() {
openLoading(false);
let data = await getDetail({ code: props.code });
flowContent.value = data.scheme.flowContent;
formData.userId = userInfo.id;
@ -195,7 +224,6 @@
querys.pkeyValue = processId;
}
for (var item in res) {
console.log(res[item]);
if (res[item] == undefined) {
res[item] = '';
if (item.search('_input_guid') != -1 && !props.isUpdate) {
@ -204,14 +232,12 @@
} else {
if (props.isUpdate) {
if (item.search('_input_guid') != -1) {
console.log(res[item]);
querys.pkeyValue = res[item];
}
}
}
}
querys.data = JSON.stringify(res);
console.log(querys);
const formValue = await functionsaveForm(querys);
if (formValue) {
handleCreateFlow(processId, querys.pkeyValue);
@ -239,17 +265,20 @@
processId: processId,
InstanceInfo: JSON.stringify(commit),
};
let data;
if (!designerData.isDraft) {
await saveDraft(querys);
let draft = await saveDraft(querys);
querys.schemeCode = '';
designerData.isDraft = true;
}
const data = await create(querys);
if (data) {
closePreview();
return createMessage.success('发起流程成功');
} else {
return createMessage.error('发起流程失败');
if (draft) {
data = await create(querys);
if (data) {
closePreview();
return createMessage.success('发起流程成功');
} else {
return createMessage.error('发起流程失败');
}
}
}
}
async function getFormHistory() {

View File

@ -186,6 +186,7 @@
getTitle.value = '新增';
data.btnList.forEach((element) => {
if (element.prop === 'Add' && element.isWFlow) {
alert("Add");
flowCode.value = element.wFlowCode;
}
});

View File

@ -141,6 +141,11 @@
item.csType = element.data[currentIndex].csType;
}
});
if (item.csType == 'int') {
item.componentProps.options.forEach((optionChild) => {
optionChild.value = Number(optionChild.value);
});
}
}
// csType
if (item.type == 'subTable') {

View File

@ -150,6 +150,7 @@
import { auditInfo } from './page';
import { IFormConfig } from '@/views/demo/form-design/typings/v-form-component';
import { useMessage } from '@/hooks/web/useMessage';
import { buildGUID } from '@/utils/uuid';
const { createMessage } = useMessage();
const formBoxRef = ref<any>();
@ -511,8 +512,11 @@
.then(async (res) => {
res[designerData.formCurrentNode.formRelationId] = instanceInfo.pkeyValue;
for (var item in res) {
if (res[item] == null) {
if (!res[item]) {
res[item] = '';
if (item.search('_input_guid') != -1) {
res[item] = buildGUID();
}
}
}
querys.data = JSON.stringify(res);