mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-11-12 20:23:52 +08:00
版本预发布
This commit is contained in:
105
web/src/components/CitySelector/citySelector.vue
Normal file
105
web/src/components/CitySelector/citySelector.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<n-cascader
|
||||
v-bind="$props"
|
||||
:value="valueLabel"
|
||||
:options="dataOptions"
|
||||
:placeholder="placeholder"
|
||||
:check-strategy="checkStrategy"
|
||||
clearable
|
||||
cascade
|
||||
:on-update:value="onValueChange"
|
||||
:on-load="handleLoad"
|
||||
:on-focus="focusLoad"
|
||||
remote
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { GetCityLabel, ProvincesSelect } from '@/api/apply/provinces';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import type { CascaderOption } from 'naive-ui';
|
||||
const emits = defineEmits(['update:value', 'update:label']);
|
||||
import { basicProps } from './props';
|
||||
const props = defineProps({
|
||||
...basicProps,
|
||||
});
|
||||
|
||||
const valueLabel = ref<string | null>(null);
|
||||
const dataOptions = ref([]);
|
||||
const placeholder = computed(() => {
|
||||
if (props.dataType === 'p') {
|
||||
return '请选择省份';
|
||||
} else if (props.dataType === 'pc') {
|
||||
return '请选择省市';
|
||||
} else {
|
||||
return '请选择省市区';
|
||||
}
|
||||
});
|
||||
|
||||
function onValueChange(
|
||||
value: string | number | Array<string | number> | null,
|
||||
option: CascaderOption | Array<CascaderOption | null> | null,
|
||||
pathValues: Array<CascaderOption | null>
|
||||
) {
|
||||
const tempPathValues = pathValues
|
||||
? pathValues.map((it: CascaderOption | null) => ({
|
||||
label: it?.label,
|
||||
value: it?.value,
|
||||
level: it?.level,
|
||||
}))
|
||||
: null;
|
||||
|
||||
emits('update:value', value);
|
||||
valueLabel.value = getLabel(tempPathValues);
|
||||
}
|
||||
|
||||
function getLabel(values): string | null {
|
||||
if (values === null || values === undefined) {
|
||||
return null;
|
||||
}
|
||||
let label = '';
|
||||
const length = values.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const item = values[i];
|
||||
label += item.label;
|
||||
if (i + 1 < length) {
|
||||
label += props.separator;
|
||||
}
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
async () => {
|
||||
if (props.value === 0) {
|
||||
valueLabel.value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (valueLabel.value === null) {
|
||||
valueLabel.value = await GetCityLabel({ id: props.value, spilt: props.separator });
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
async function load(option) {
|
||||
const data = await ProvincesSelect({ dataType: props.dataType, ...option });
|
||||
return data.list;
|
||||
}
|
||||
|
||||
async function handleLoad(option: CascaderOption) {
|
||||
option.children = await load({ dataType: props.dataType, ...option });
|
||||
return;
|
||||
}
|
||||
|
||||
async function focusLoad() {
|
||||
if (dataOptions.value.length === 0) {
|
||||
dataOptions.value = await load({ dataType: props.dataType });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
22
web/src/components/CitySelector/props.ts
Normal file
22
web/src/components/CitySelector/props.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import type { PropType } from 'vue';
|
||||
import { NCascader } from 'naive-ui';
|
||||
|
||||
export const basicProps = {
|
||||
...NCascader.props,
|
||||
defaultValue: {
|
||||
type: [Number, String, Array],
|
||||
default: null,
|
||||
},
|
||||
value: {
|
||||
type: [Number, String, Array],
|
||||
default: null,
|
||||
},
|
||||
dataType: {
|
||||
type: String as PropType<'p' | 'pc' | 'pca'>,
|
||||
default: 'pca',
|
||||
},
|
||||
checkStrategy: {
|
||||
type: String as PropType<'child' | 'all'>,
|
||||
default: 'child',
|
||||
},
|
||||
};
|
||||
@@ -1,11 +1,15 @@
|
||||
<template>
|
||||
<QuillEditor
|
||||
ref="quillEditor"
|
||||
:options="options"
|
||||
toolbar="full"
|
||||
v-model:content="content"
|
||||
@ready="readyQuill"
|
||||
class="quillEditor"
|
||||
:id="quillEditorId"
|
||||
:id="id"
|
||||
:modules="modules"
|
||||
@focus="onEditorFocus"
|
||||
@blur="onEditorBlur"
|
||||
@update:content="onUpdateContent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -13,40 +17,27 @@
|
||||
import { ref, watch, onMounted } from 'vue';
|
||||
import { QuillEditor } from '@vueup/vue-quill';
|
||||
import '@vueup/vue-quill/dist/vue-quill.snow.css';
|
||||
import ImageUploader from 'quill-image-uploader';
|
||||
import MagicUrl from 'quill-magic-url';
|
||||
import { getRandomString } from '@/utils/charset';
|
||||
import { UploadImage } from '@/api/base';
|
||||
import componentSetting from '@/settings/componentSetting';
|
||||
import { isNullOrUnDef } from '@/utils/is';
|
||||
import { useMessage } from 'naive-ui';
|
||||
|
||||
export interface Props {
|
||||
value: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const emit = defineEmits(['update:value']);
|
||||
const quillEditorId = ref('quillEditorId-' + getRandomString(16, true));
|
||||
const message = useMessage();
|
||||
const initFinish = ref(false);
|
||||
const quillEditor = ref();
|
||||
const content = ref();
|
||||
const props = withDefaults(defineProps<Props>(), { value: '' });
|
||||
const options = ref({
|
||||
modules: {
|
||||
toolbar: [
|
||||
['bold', 'italic', 'underline', 'strike'], // toggled buttons
|
||||
['blockquote', 'code-block'],
|
||||
|
||||
[{ header: 1 }, { header: 2 }], // custom button values
|
||||
[{ list: 'ordered' }, { list: 'bullet' }],
|
||||
[{ script: 'sub' }, { script: 'super' }], // superscript/subscript
|
||||
[{ indent: '-1' }, { indent: '+1' }], // outdent/indent
|
||||
[{ direction: 'rtl' }], // text direction
|
||||
|
||||
[{ size: ['small', false, 'large', 'huge'] }], // custom dropdown
|
||||
[{ header: [1, 2, 3, 4, 5, 6, false] }],
|
||||
|
||||
[{ color: [] }, { background: [] }], // dropdown with defaults from theme
|
||||
[{ font: [] }],
|
||||
[{ align: [] }],
|
||||
['clean'],
|
||||
['image'],
|
||||
],
|
||||
},
|
||||
theme: 'snow',
|
||||
placeholder: '输入您要编辑的内容!',
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
value: '',
|
||||
id: 'quillEditorId-' + getRandomString(16, true),
|
||||
});
|
||||
|
||||
function readyQuill() {
|
||||
@@ -54,20 +45,41 @@
|
||||
}
|
||||
|
||||
watch(
|
||||
() => content.value,
|
||||
(_newValue, _oldValue) => {
|
||||
if (quillEditor.value !== undefined) {
|
||||
emit('update:value', quillEditor.value.getHTML());
|
||||
() => props.value,
|
||||
(newValue) => {
|
||||
if (!initFinish.value) {
|
||||
quillEditor.value?.setHTML(newValue);
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true, // 深度监听
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
function onEditorFocus(val) {
|
||||
initFinish.value = true;
|
||||
console.log(val);
|
||||
}
|
||||
|
||||
function onEditorBlur(val) {
|
||||
console.log(val);
|
||||
}
|
||||
|
||||
function onUpdateContent() {
|
||||
emit('update:value', quillEditor.value.getHTML());
|
||||
}
|
||||
|
||||
function checkFileType(map: string[], fileType: string) {
|
||||
if (isNullOrUnDef(map)) {
|
||||
return true;
|
||||
}
|
||||
return map.includes(fileType);
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// 兼容表单分组 n-form-item-blank
|
||||
let dom = document.getElementById(quillEditorId.value);
|
||||
let dom = document.getElementById(props.id);
|
||||
if (dom && dom.parentNode) {
|
||||
const parent = dom.parentNode as Element;
|
||||
if ('n-form-item-blank' === parent.className) {
|
||||
@@ -75,10 +87,64 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const modules = [
|
||||
{
|
||||
name: 'imageUploader',
|
||||
module: ImageUploader,
|
||||
options: {
|
||||
upload: (file) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!checkFileType(componentSetting.upload.imageType, file.type)) {
|
||||
message.error(`只能上传图片类型为${componentSetting.upload.imageType.join(',')}`);
|
||||
reject('Upload failed');
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
UploadImage(formData)
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
resolve(res.fileUrl);
|
||||
})
|
||||
.catch((err) => {
|
||||
reject('Upload failed');
|
||||
console.error('Error:', err);
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'magicUrl',
|
||||
module: MagicUrl,
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.ql-container {
|
||||
<style lang="less" scoped>
|
||||
:deep(.ql-container) {
|
||||
height: auto;
|
||||
}
|
||||
:deep(.ql-container.ql-snow) {
|
||||
border: none;
|
||||
}
|
||||
:deep(.ql-toolbar.ql-snow) {
|
||||
border: none;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
:deep(.ql-editor.ql-blank::before) {
|
||||
color: #afb4bd;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
}
|
||||
.dark .priview-content {
|
||||
background: #5a5a5a;
|
||||
color: #fff;
|
||||
}
|
||||
.light .priview-content {
|
||||
background: #fff;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
v-bind="getComponentProps(schema)"
|
||||
:is="schema.component"
|
||||
v-model:value="formModel[schema.field]"
|
||||
:class="{ isFull: schema.isFull != false && getProps.isFull }"
|
||||
:class="{ isFull: schema.isFull !== false && getProps.isFull }"
|
||||
/>
|
||||
<!--组件后面的内容-->
|
||||
<template v-if="schema.suffix">
|
||||
@@ -75,8 +75,8 @@
|
||||
</n-gi>
|
||||
<!--提交 重置 展开 收起 按钮-->
|
||||
<n-gi
|
||||
:span="isInline ? '' : 24"
|
||||
:suffix="isInline ? true : false"
|
||||
:span="isInline ? 1 : 24"
|
||||
:suffix="!!isInline"
|
||||
#="{ overflow }"
|
||||
v-if="getProps.showActionButtonGroup"
|
||||
>
|
||||
@@ -134,7 +134,7 @@
|
||||
import type { GridProps } from 'naive-ui/lib/grid';
|
||||
import type { FormSchema, FormProps, FormActionType } from './types/form';
|
||||
|
||||
import { isArray } from '@/utils/is/index';
|
||||
import { isArray } from '@/utils/is';
|
||||
import { deepMerge } from '@/utils';
|
||||
|
||||
export default defineComponent({
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="tableAction">
|
||||
<div class="flex items-center justify-center">
|
||||
<template v-for="(action, index) in getActions" :key="`${index}-${action.label}`">
|
||||
<n-button v-bind="action" class="mx-2">
|
||||
<n-button v-bind="action" class="mx-1">
|
||||
{{ action.label }}
|
||||
<template #icon v-if="action.hasOwnProperty('icon')">
|
||||
<n-icon :component="action.icon" />
|
||||
@@ -16,16 +16,14 @@
|
||||
@select="select"
|
||||
>
|
||||
<slot name="more"></slot>
|
||||
<n-button v-bind="getMoreProps" class="mx-2" v-if="!$slots.more" icon-placement="right">
|
||||
<n-button v-bind="getMoreProps" class="mx-1" v-if="!$slots.more" icon-placement="right">
|
||||
<div class="flex items-center">
|
||||
<span>更多</span>
|
||||
<n-icon size="14" class="ml-1">
|
||||
<DownOutlined />
|
||||
</n-icon>
|
||||
</div>
|
||||
<!-- <template #icon>-->
|
||||
<!-- -->
|
||||
<!-- </template>-->
|
||||
<!-- <template #icon> </template>-->
|
||||
</n-button>
|
||||
</n-dropdown>
|
||||
</div>
|
||||
@@ -33,7 +31,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed, toRaw } from 'vue';
|
||||
import { computed, defineComponent, PropType, toRaw } from 'vue';
|
||||
import { ActionItem } from '@/components/Table';
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
import { isBoolean, isFunction } from '@/utils/is';
|
||||
@@ -87,7 +85,7 @@
|
||||
return {
|
||||
size: 'small',
|
||||
text: actionText,
|
||||
type: actionType,
|
||||
type: getBtnType(action), //actionType,
|
||||
...action,
|
||||
...popConfirm,
|
||||
onConfirm: popConfirm?.confirm,
|
||||
@@ -110,6 +108,28 @@
|
||||
return isIfShow;
|
||||
}
|
||||
|
||||
function getBtnType(action) {
|
||||
if (action.type !== undefined && action.type !== '') {
|
||||
return action.type;
|
||||
}
|
||||
switch (action.label) {
|
||||
case '编辑':
|
||||
return 'primary';
|
||||
case '启用':
|
||||
case '已禁用':
|
||||
return 'warning';
|
||||
case '已启用':
|
||||
case '禁用':
|
||||
return 'success';
|
||||
case '删除':
|
||||
return 'error';
|
||||
case '查看详情':
|
||||
return 'default';
|
||||
default:
|
||||
return 'primary';
|
||||
}
|
||||
}
|
||||
|
||||
const getActions = computed(() => {
|
||||
return (toRaw(props.actions) || [])
|
||||
.filter((action) => {
|
||||
@@ -121,7 +141,7 @@
|
||||
return {
|
||||
size: 'small',
|
||||
text: actionText,
|
||||
type: actionType,
|
||||
type: getBtnType(action), //actionType,
|
||||
...action,
|
||||
...(popConfirm || {}),
|
||||
onConfirm: popConfirm?.confirm,
|
||||
|
||||
@@ -215,7 +215,6 @@
|
||||
}
|
||||
//勾选列
|
||||
function onSelection(e) {
|
||||
console.log('onSelection:' + JSON.stringify(e));
|
||||
let checkList = table.getCacheColumns();
|
||||
if (e) {
|
||||
checkList.unshift({ type: 'selection', key: 'selection' });
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ref, ComputedRef, unref, computed, onMounted, watchEffect, watch } from 'vue';
|
||||
import type { BasicTableProps } from '../types/table';
|
||||
import type { PaginationProps } from '../types/pagination';
|
||||
import { isBoolean, isFunction, isArray } from '@/utils/is';
|
||||
import { isBoolean, isFunction } from '@/utils/is';
|
||||
import { APISETTING } from '../const';
|
||||
|
||||
export function useDataSource(
|
||||
@@ -31,8 +31,8 @@ export function useDataSource(
|
||||
return rowKey
|
||||
? rowKey
|
||||
: () => {
|
||||
return 'key';
|
||||
};
|
||||
return 'key';
|
||||
};
|
||||
});
|
||||
|
||||
const getDataSourceRef = computed(() => {
|
||||
|
||||
@@ -1,82 +1,84 @@
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<div class="upload">
|
||||
<div class="upload-card">
|
||||
<!--图片列表-->
|
||||
<div
|
||||
class="upload-card-item"
|
||||
:style="getCSSProperties"
|
||||
v-for="(item, index) in imgList"
|
||||
:key="`img_${index}`"
|
||||
>
|
||||
<div class="upload-card-item-info">
|
||||
<div class="img-box">
|
||||
<template v-if="fileType === 'image'">
|
||||
<img :src="item" @error="errorImg($event)" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<n-avatar :style="fileAvatarCSS">{{ getFileExt(item) }}</n-avatar>
|
||||
</template>
|
||||
</div>
|
||||
<div class="img-box-actions">
|
||||
<template v-if="fileType === 'image'">
|
||||
<n-icon size="18" class="mx-2 action-icon" @click="preview(item)">
|
||||
<EyeOutlined />
|
||||
<div>
|
||||
<div class="w-full">
|
||||
<div class="upload">
|
||||
<div class="upload-card">
|
||||
<!--图片列表-->
|
||||
<div
|
||||
class="upload-card-item"
|
||||
:style="getCSSProperties"
|
||||
v-for="(item, index) in imgList"
|
||||
:key="`img_${index}`"
|
||||
>
|
||||
<div class="upload-card-item-info">
|
||||
<div class="img-box">
|
||||
<template v-if="fileType === 'image'">
|
||||
<img :src="item" @error="errorImg($event)" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<n-avatar :style="fileAvatarCSS">{{ getFileExt(item) }}</n-avatar>
|
||||
</template>
|
||||
</div>
|
||||
<div class="img-box-actions">
|
||||
<template v-if="fileType === 'image'">
|
||||
<n-icon size="18" class="mx-2 action-icon" @click="preview(item)">
|
||||
<EyeOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<template v-else>
|
||||
<n-icon size="18" class="mx-2 action-icon" @click="download(item)">
|
||||
<CloudDownloadOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<n-icon size="18" class="mx-2 action-icon" @click="remove(index)">
|
||||
<DeleteOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<template v-else>
|
||||
<n-icon size="18" class="mx-2 action-icon" @click="download(item)">
|
||||
<CloudDownloadOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<n-icon size="18" class="mx-2 action-icon" @click="remove(index)">
|
||||
<DeleteOutlined />
|
||||
</n-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--上传图片-->
|
||||
<div
|
||||
class="upload-card-item upload-card-item-select-picture"
|
||||
:style="getCSSProperties"
|
||||
v-if="imgList.length < maxNumber"
|
||||
>
|
||||
<n-upload
|
||||
v-bind="$props"
|
||||
:file-list-style="{ display: 'none' }"
|
||||
@before-upload="beforeUpload"
|
||||
@finish="finish"
|
||||
<!--上传图片-->
|
||||
<div
|
||||
class="upload-card-item upload-card-item-select-picture"
|
||||
:style="getCSSProperties"
|
||||
v-if="imgList.length < maxNumber"
|
||||
>
|
||||
<div class="flex flex-col justify-center">
|
||||
<n-icon size="18" class="m-auto">
|
||||
<PlusOutlined />
|
||||
</n-icon>
|
||||
<span class="upload-title">{{ uploadTitle }}</span>
|
||||
</div>
|
||||
</n-upload>
|
||||
<n-upload
|
||||
v-bind="$props"
|
||||
:file-list-style="{ display: 'none' }"
|
||||
@before-upload="beforeUpload"
|
||||
@finish="finish"
|
||||
>
|
||||
<div class="flex flex-col justify-center">
|
||||
<n-icon size="18" class="m-auto">
|
||||
<PlusOutlined />
|
||||
</n-icon>
|
||||
<span class="upload-title">{{ uploadTitle }}</span>
|
||||
</div>
|
||||
</n-upload>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--上传图片-->
|
||||
<n-space>
|
||||
<n-alert title="提示" type="info" v-if="helpText" class="flex w-full">
|
||||
{{ helpText }}
|
||||
</n-alert>
|
||||
</n-space>
|
||||
</div>
|
||||
|
||||
<!--上传图片-->
|
||||
<n-space>
|
||||
<n-alert title="提示" type="info" v-if="helpText" class="flex w-full">
|
||||
{{ helpText }}
|
||||
</n-alert>
|
||||
</n-space>
|
||||
<!--预览图片-->
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
preset="card"
|
||||
title="预览"
|
||||
:bordered="false"
|
||||
:style="{ width: '520px' }"
|
||||
>
|
||||
<img :src="previewUrl" />
|
||||
</n-modal>
|
||||
</div>
|
||||
|
||||
<!--预览图片-->
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
preset="card"
|
||||
title="预览"
|
||||
:bordered="false"
|
||||
:style="{ width: '520px' }"
|
||||
>
|
||||
<img :src="previewUrl" />
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -87,7 +89,7 @@
|
||||
import { ResultEnum } from '@/enums/httpEnum';
|
||||
import componentSetting from '@/settings/componentSetting';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
import { isJsonString, isNullOrUnDef } from '@/utils/is';
|
||||
import { isArray, isJsonString, isNullOrUnDef } from '@/utils/is';
|
||||
import { getFileExt } from '@/utils/urlUtils';
|
||||
import { errorImg } from '@/utils/hotgo';
|
||||
const globSetting = useGlobSetting();
|
||||
@@ -131,6 +133,10 @@
|
||||
() => {
|
||||
loadValue(props.value);
|
||||
return;
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -139,12 +145,16 @@
|
||||
() => {
|
||||
loadValue(props.values);
|
||||
return;
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
// 加载默认
|
||||
function loadValue(value: any) {
|
||||
if (value === null) {
|
||||
if (value === undefined || value === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -163,6 +173,10 @@
|
||||
data = value;
|
||||
}
|
||||
|
||||
if (!isArray(data) || data.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
state.imgList = data.map((item) => {
|
||||
return getImgUrl(item);
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ export const basicProps = {
|
||||
},
|
||||
accept: {
|
||||
type: String,
|
||||
default: '.jpg,.png,.jpeg,.svg,.gif',
|
||||
default: '.jpg,.png,.jpeg,.svg,.gif,.webp',
|
||||
},
|
||||
helpText: {
|
||||
type: String as PropType<string>,
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
<template>
|
||||
<BasicUpload
|
||||
:action="`${uploadUrl}${urlPrefix}/upload/file`"
|
||||
:headers="uploadHeaders"
|
||||
:data="{ type: 0 }"
|
||||
name="file"
|
||||
:width="100"
|
||||
:height="100"
|
||||
fileType="file"
|
||||
:maxNumber="maxNumber"
|
||||
@uploadChange="uploadChange"
|
||||
v-model:value="image"
|
||||
v-model:values="images"
|
||||
/>
|
||||
<div>
|
||||
<BasicUpload
|
||||
:action="`${uploadUrl}${urlPrefix}/upload/file`"
|
||||
:headers="uploadHeaders"
|
||||
:data="{ type: 0 }"
|
||||
accept="*"
|
||||
name="file"
|
||||
:width="100"
|
||||
:height="100"
|
||||
fileType="file"
|
||||
:maxNumber="maxNumber"
|
||||
:helpText="helpText"
|
||||
@uploadChange="uploadChange"
|
||||
v-model:value="image"
|
||||
v-model:values="images"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, unref, reactive } from 'vue';
|
||||
import { ref, onMounted, unref, reactive, watch } from 'vue';
|
||||
import { BasicUpload } from '@/components/Upload';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||
@@ -23,6 +27,7 @@
|
||||
export interface Props {
|
||||
value: string | string[] | null;
|
||||
maxNumber: number;
|
||||
helpText?: string;
|
||||
}
|
||||
|
||||
const globSetting = useGlobSetting();
|
||||
@@ -33,7 +38,7 @@
|
||||
Authorization: useUserStore.token,
|
||||
});
|
||||
const emit = defineEmits(['update:value']);
|
||||
const props = withDefaults(defineProps<Props>(), { value: '', maxNumber: 1 });
|
||||
const props = withDefaults(defineProps<Props>(), { value: '', maxNumber: 1, helpText: '' });
|
||||
const image = ref<string>('');
|
||||
const images = ref<string[] | object>([]);
|
||||
|
||||
@@ -47,12 +52,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
function loadImage() {
|
||||
if (props.maxNumber === 1) {
|
||||
image.value = props.value as string;
|
||||
} else {
|
||||
images.value = props.value as string[];
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
() => {
|
||||
loadImage();
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(async () => {
|
||||
loadImage();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
:width="100"
|
||||
:height="100"
|
||||
:maxNumber="maxNumber"
|
||||
:helpText="helpText"
|
||||
@uploadChange="uploadChange"
|
||||
v-model:value="image"
|
||||
v-model:values="images"
|
||||
@@ -14,7 +15,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, unref, reactive } from 'vue';
|
||||
import { onMounted, reactive, ref, unref, watch } from 'vue';
|
||||
import { BasicUpload } from '@/components/Upload';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||
@@ -22,6 +23,7 @@
|
||||
export interface Props {
|
||||
value: string | string[] | null;
|
||||
maxNumber: number;
|
||||
helpText?: string;
|
||||
}
|
||||
|
||||
const globSetting = useGlobSetting();
|
||||
@@ -32,7 +34,7 @@
|
||||
Authorization: useUserStore.token,
|
||||
});
|
||||
const emit = defineEmits(['update:value']);
|
||||
const props = withDefaults(defineProps<Props>(), { value: '', maxNumber: 1 });
|
||||
const props = withDefaults(defineProps<Props>(), { value: '', maxNumber: 1, helpText: '' });
|
||||
const image = ref<string>('');
|
||||
const images = ref<string[]>([]);
|
||||
|
||||
@@ -46,12 +48,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
//赋值默认图片显示
|
||||
function loadImage() {
|
||||
if (props.maxNumber === 1) {
|
||||
image.value = props.value as string;
|
||||
} else {
|
||||
images.value = props.value as string[];
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
() => {
|
||||
loadImage();
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(async () => {
|
||||
loadImage();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user