图片显示
This commit is contained in:
parent
13ee12a4f9
commit
3f71d2c19f
68
src/components/ImageViewer/index.vue
Normal file
68
src/components/ImageViewer/index.vue
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<template>
|
||||||
|
<teleport to="body">
|
||||||
|
<el-image-viewer
|
||||||
|
v-if="visible"
|
||||||
|
:url-list="urlList"
|
||||||
|
:initial-index="initialIndex"
|
||||||
|
:z-index="9999"
|
||||||
|
@close="handleClose"
|
||||||
|
@switch="handleSwitch"
|
||||||
|
/>
|
||||||
|
</teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="ImageViewer">
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
|
||||||
|
interface ImageViewerProps {
|
||||||
|
modelValue: boolean;
|
||||||
|
urlList: string[];
|
||||||
|
initialIndex?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<ImageViewerProps>(), {
|
||||||
|
initialIndex: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:modelValue', value: boolean): void;
|
||||||
|
(e: 'close'): void;
|
||||||
|
(e: 'switch', index: number): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const visible = ref(props.modelValue);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(val) => {
|
||||||
|
visible.value = val;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(visible, (val) => {
|
||||||
|
emit('update:modelValue', val);
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
visible.value = false;
|
||||||
|
emit('close');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSwitch = (index: number) => {
|
||||||
|
emit('switch', index);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
:deep(.el-image-viewer__wrapper) {
|
||||||
|
z-index: 9999 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-image-viewer__mask) {
|
||||||
|
z-index: 9999 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-image-viewer__canvas) {
|
||||||
|
z-index: 10000 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
149
src/components/PreviewImage/index.vue
Normal file
149
src/components/PreviewImage/index.vue
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
<template>
|
||||||
|
<div class="preview-image-container" :style="containerStyle">
|
||||||
|
<img
|
||||||
|
:src="src"
|
||||||
|
:style="imageStyle"
|
||||||
|
:alt="alt"
|
||||||
|
class="preview-image"
|
||||||
|
:class="{ 'clickable': !disabled && canPreview }"
|
||||||
|
@click="handleClick"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
<template v-if="!disabled && canPreview && showZoomIcon">
|
||||||
|
<div class="preview-overlay" @click.stop="handleClick">
|
||||||
|
<el-icon class="zoom-icon">
|
||||||
|
<ZoomIn />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<ImageViewer v-model="viewerVisible" :url-list="urlList" :initial-index="currentIndex" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="PreviewImage">
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import { ZoomIn } from '@element-plus/icons-vue';
|
||||||
|
import ImageViewer from '../ImageViewer/index.vue';
|
||||||
|
|
||||||
|
interface PreviewImageProps {
|
||||||
|
src: string;
|
||||||
|
alt?: string;
|
||||||
|
width?: string | number;
|
||||||
|
height?: string | number;
|
||||||
|
fit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
|
||||||
|
radius?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
urlList?: string[];
|
||||||
|
showZoomIcon?: boolean;
|
||||||
|
border?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<PreviewImageProps>(), {
|
||||||
|
alt: '',
|
||||||
|
width: '100%',
|
||||||
|
height: 'auto',
|
||||||
|
fit: 'cover',
|
||||||
|
radius: '0',
|
||||||
|
disabled: false,
|
||||||
|
urlList: () => [],
|
||||||
|
showZoomIcon: true,
|
||||||
|
border: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const viewerVisible = ref(false);
|
||||||
|
const currentIndex = ref(0);
|
||||||
|
|
||||||
|
const canPreview = computed(() => {
|
||||||
|
return props.urlList.length > 0 || props.src;
|
||||||
|
});
|
||||||
|
|
||||||
|
const urlList = computed(() => {
|
||||||
|
if (props.urlList.length > 0) {
|
||||||
|
return props.urlList;
|
||||||
|
}
|
||||||
|
return [props.src];
|
||||||
|
});
|
||||||
|
|
||||||
|
const containerStyle = computed(() => {
|
||||||
|
const style: Record<string, string | number> = {
|
||||||
|
width: typeof props.width === 'number' ? `${props.width}px` : props.width,
|
||||||
|
height: typeof props.height === 'number' ? `${props.height}px` : props.height,
|
||||||
|
borderRadius: props.radius,
|
||||||
|
};
|
||||||
|
if (props.border) {
|
||||||
|
style.border = '1px solid var(--el-border-color)';
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
});
|
||||||
|
|
||||||
|
const imageStyle = computed(() => {
|
||||||
|
return {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
objectFit: props.fit,
|
||||||
|
borderRadius: props.radius,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
if (props.disabled || !canPreview.value) return;
|
||||||
|
|
||||||
|
if (props.urlList.length > 0) {
|
||||||
|
currentIndex.value = props.urlList.indexOf(props.src);
|
||||||
|
if (currentIndex.value === -1) {
|
||||||
|
currentIndex.value = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentIndex.value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
viewerVisible.value = true;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.preview-image-container {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: var(--el-fill-color-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-image {
|
||||||
|
display: block;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-image.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-image-container:hover .preview-image.clickable {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
.zoom-icon {
|
||||||
|
font-size: 32px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-image-container:hover .preview-overlay {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -2,12 +2,14 @@ import type { App } from 'vue';
|
|||||||
import { authDirective } from '/@/directive/authDirective';
|
import { authDirective } from '/@/directive/authDirective';
|
||||||
import { wavesDirective, dragDirective } from '/@/directive/customDirective';
|
import { wavesDirective, dragDirective } from '/@/directive/customDirective';
|
||||||
import { debounceDirective } from './debounceDirective';
|
import { debounceDirective } from './debounceDirective';
|
||||||
|
import { previewDirective } from './previewDirective';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出指令方法:v-xxx
|
* 导出指令方法:v-xxx
|
||||||
* @methods authDirective 用户权限指令,用法:v-auth
|
* @methods authDirective 用户权限指令,用法:v-auth
|
||||||
* @methods wavesDirective 按钮波浪指令,用法:v-waves
|
* @methods wavesDirective 按钮波浪指令,用法:v-waves
|
||||||
* @methods dragDirective 自定义拖动指令,用法:v-drag
|
* @methods dragDirective 自定义拖动指令,用法:v-drag
|
||||||
|
* @methods previewDirective 图片预览指令,用法:v-preview
|
||||||
*/
|
*/
|
||||||
export function directive(app: App) {
|
export function directive(app: App) {
|
||||||
// 用户权限指令
|
// 用户权限指令
|
||||||
@ -19,4 +21,7 @@ export function directive(app: App) {
|
|||||||
|
|
||||||
//防抖指令
|
//防抖指令
|
||||||
debounceDirective(app);
|
debounceDirective(app);
|
||||||
|
|
||||||
|
// 图片预览指令
|
||||||
|
app.directive('preview', previewDirective);
|
||||||
}
|
}
|
||||||
|
|||||||
40
src/directive/previewDirective.ts
Normal file
40
src/directive/previewDirective.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import type { Directive, DirectiveBinding } from 'vue';
|
||||||
|
import { useImagePreview } from '../utils/imagePreview';
|
||||||
|
|
||||||
|
const { previewSingleImage } = useImagePreview();
|
||||||
|
|
||||||
|
export const previewDirective: Directive = {
|
||||||
|
mounted(el: HTMLElement, binding: DirectiveBinding) {
|
||||||
|
const imgEl = el.tagName === 'IMG' ? el : el.querySelector('img');
|
||||||
|
if (!imgEl) return;
|
||||||
|
|
||||||
|
const urlList = binding.value?.urlList || [];
|
||||||
|
const disabled = binding.value?.disabled || false;
|
||||||
|
|
||||||
|
if (!disabled) {
|
||||||
|
imgEl.style.cursor = 'pointer';
|
||||||
|
imgEl.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const src = (imgEl as HTMLImageElement).src;
|
||||||
|
if (urlList.length > 0) {
|
||||||
|
const { showImagePreview } = useImagePreview();
|
||||||
|
const index = urlList.indexOf(src);
|
||||||
|
showImagePreview({
|
||||||
|
urlList,
|
||||||
|
initialIndex: index >= 0 ? index : 0,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
previewSingleImage(src);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
unmounted(el: HTMLElement) {
|
||||||
|
const imgEl = el.tagName === 'IMG' ? el : el.querySelector('img');
|
||||||
|
if (!imgEl) return;
|
||||||
|
imgEl.removeEventListener('click', () => {});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default previewDirective;
|
||||||
71
src/utils/imagePreview.ts
Normal file
71
src/utils/imagePreview.ts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { createApp, markRaw, h, ref, type App } from 'vue';
|
||||||
|
import ImageViewer from '../components/ImageViewer/index.vue';
|
||||||
|
|
||||||
|
interface ImagePreviewOptions {
|
||||||
|
urlList: string[];
|
||||||
|
initialIndex?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
let imageViewerInstance: any = null;
|
||||||
|
|
||||||
|
export const useImagePreview = () => {
|
||||||
|
const showImagePreview = (options: ImagePreviewOptions) => {
|
||||||
|
const { urlList, initialIndex = 0 } = options;
|
||||||
|
|
||||||
|
if (!urlList || urlList.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageViewerInstance) {
|
||||||
|
imageViewerInstance.unmount();
|
||||||
|
imageViewerInstance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const container = document.createElement('div');
|
||||||
|
document.body.appendChild(container);
|
||||||
|
|
||||||
|
const app = createApp({
|
||||||
|
components: { ImageViewer },
|
||||||
|
setup() {
|
||||||
|
const visible = ref(true);
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
visible.value = false;
|
||||||
|
setTimeout(() => {
|
||||||
|
app.unmount();
|
||||||
|
if (document.body.contains(container)) {
|
||||||
|
document.body.removeChild(container);
|
||||||
|
}
|
||||||
|
imageViewerInstance = null;
|
||||||
|
}, 300);
|
||||||
|
};
|
||||||
|
|
||||||
|
return () =>
|
||||||
|
h(ImageViewer, {
|
||||||
|
modelValue: visible.value,
|
||||||
|
'onUpdate:modelValue': (val: boolean) => {
|
||||||
|
visible.value = val;
|
||||||
|
if (!val) {
|
||||||
|
handleClose();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
urlList,
|
||||||
|
initialIndex,
|
||||||
|
onClose: handleClose,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
imageViewerInstance = app;
|
||||||
|
app.mount(container);
|
||||||
|
};
|
||||||
|
|
||||||
|
const previewSingleImage = (url: string) => {
|
||||||
|
showImagePreview({ urlList: [url] });
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
showImagePreview,
|
||||||
|
previewSingleImage,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -17,20 +17,16 @@
|
|||||||
<el-row :gutter="15" v-if="state.tableData.data.length > 0" v-loading="state.loading">
|
<el-row :gutter="15" v-if="state.tableData.data.length > 0" v-loading="state.loading">
|
||||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb15" v-for="v in state.tableData.data" :key="v.id">
|
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb15" v-for="v in state.tableData.data" :key="v.id">
|
||||||
<div class="img-box">
|
<div class="img-box">
|
||||||
<el-image style="width: 250px; height: 180px" :src="v.url" fit="cover" lazy />
|
<PreviewImage
|
||||||
|
:src="v.url"
|
||||||
|
width="250px"
|
||||||
|
height="180px"
|
||||||
|
fit="cover"
|
||||||
|
radius="8px"
|
||||||
|
:url-list="imageUrlList"
|
||||||
|
:show-zoom-icon="true"
|
||||||
|
/>
|
||||||
<div class="operate">
|
<div class="operate">
|
||||||
<div
|
|
||||||
class="handle-icon"
|
|
||||||
@click="
|
|
||||||
() => {
|
|
||||||
imgViewVisible = true;
|
|
||||||
imageUrl = v.url!;
|
|
||||||
}
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<el-icon><ZoomIn /></el-icon>
|
|
||||||
<span>查看</span>
|
|
||||||
</div>
|
|
||||||
<div class="handle-icon" @click="onDeleteImg(v.id!)">
|
<div class="handle-icon" @click="onDeleteImg(v.id!)">
|
||||||
<el-icon><Delete /></el-icon>
|
<el-icon><Delete /></el-icon>
|
||||||
<span>删除</span>
|
<span>删除</span>
|
||||||
@ -55,18 +51,17 @@
|
|||||||
</el-pagination>
|
</el-pagination>
|
||||||
</template>
|
</template>
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-image-viewer v-if="imgViewVisible" @close="imgViewVisible = false" :url-list="[imageUrl]" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="blogPictures">
|
<script setup lang="ts" name="blogPictures">
|
||||||
import { reactive, onMounted, ref, nextTick } from 'vue';
|
import { reactive, onMounted, ref, computed, nextTick } from 'vue';
|
||||||
import PicturesApi from '/@/api/PicturesApi';
|
import PicturesApi from '/@/api/PicturesApi';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import type { PicturesPageOutput } from '/@/api/models';
|
import type { PicturesPageOutput } from '/@/api/models';
|
||||||
// 查看图片
|
import PreviewImage from '/@/components/PreviewImage/index.vue';
|
||||||
const imgViewVisible = ref(false);
|
import { Delete } from '@element-plus/icons-vue';
|
||||||
const imageUrl = ref('');
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
@ -83,6 +78,10 @@ const state = reactive({
|
|||||||
loading: false,
|
loading: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const imageUrlList = computed(() => {
|
||||||
|
return state.tableData.data.map((v) => v.url!).filter(Boolean);
|
||||||
|
});
|
||||||
|
|
||||||
// 分页点击
|
// 分页点击
|
||||||
const onHandleSizeChange = (val: number) => {
|
const onHandleSizeChange = (val: number) => {
|
||||||
state.tableData.param.pageSize = val;
|
state.tableData.param.pageSize = val;
|
||||||
@ -124,18 +123,7 @@ onMounted(async () => {
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.img-box {
|
.img-box {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 180px;
|
|
||||||
width: 250px;
|
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.03);
|
|
||||||
opacity: 1;
|
|
||||||
box-sizing: border-box;
|
|
||||||
:deep(img) {
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
transform: translateZ(0) scale(1.05);
|
|
||||||
}
|
|
||||||
.operate {
|
.operate {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
@ -147,28 +135,26 @@ onMounted(async () => {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: flex-end;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: rgb(0 0 0 / 60%);
|
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: var(--el-transition-duration-fast);
|
transition: var(--el-transition-duration-fast);
|
||||||
|
background: linear-gradient(to top, rgba(0, 0, 0, 0.5) 0%, transparent 50%);
|
||||||
.handle-icon {
|
.handle-icon {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 0 6%;
|
padding: 10px;
|
||||||
color: aliceblue;
|
color: aliceblue;
|
||||||
.el-icon {
|
.el-icon {
|
||||||
margin-bottom: 40%;
|
font-size: 20px;
|
||||||
font-size: 130%;
|
|
||||||
line-height: 130%;
|
|
||||||
}
|
}
|
||||||
span {
|
span {
|
||||||
font-size: 85%;
|
font-size: 12px;
|
||||||
line-height: 85%;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,14 +12,29 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="营业执照:" prop="businessLicenseUrl">
|
<el-form-item label="营业执照:" prop="businessLicenseUrl">
|
||||||
<el-upload class="avatar-uploader" action="/api/file/upload" :show-file-list="false"
|
<div class="image-upload-container">
|
||||||
:on-success="handleUploadChange">
|
<div class="upload-area">
|
||||||
<div v-if="!formData.businessLicenseUrl" class="upload-placeholder">
|
<el-upload class="avatar-uploader" action="/api/file/upload" :show-file-list="false"
|
||||||
<i class="el-icon-plus avatar-uploader-icon"></i>
|
:on-success="handleUploadChange">
|
||||||
<div>上传</div>
|
<div class="upload-placeholder">
|
||||||
|
<i class="el-icon-plus avatar-uploader-icon"></i>
|
||||||
|
<div>上传</div>
|
||||||
|
</div>
|
||||||
|
</el-upload>
|
||||||
</div>
|
</div>
|
||||||
<el-image v-else :src="formData.businessLicenseUrl" alt="营业执照" style=" height: 200px;" />
|
<div v-if="formData.businessLicenseUrl" class="preview-area">
|
||||||
</el-upload>
|
<PreviewImage
|
||||||
|
:src="formData.businessLicenseUrl"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
fit="contain"
|
||||||
|
:show-zoom-icon="true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else class="preview-area preview-empty">
|
||||||
|
<span class="preview-empty-text">预览区域</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="地址:" prop="address">
|
<el-form-item label="地址:" prop="address">
|
||||||
@ -54,6 +69,7 @@ import { ref, reactive, onMounted, computed } from 'vue';
|
|||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { merchantcertificationMyCertificationGet, merchantcertificationSubmitCertificationPost } from '/@/api/match/merchantcertification';
|
import { merchantcertificationMyCertificationGet, merchantcertificationSubmitCertificationPost } from '/@/api/match/merchantcertification';
|
||||||
import { commonSmsSendVerificationCodePost } from '/@/api/match/common';
|
import { commonSmsSendVerificationCodePost } from '/@/api/match/common';
|
||||||
|
import PreviewImage from '/@/components/PreviewImage/index.vue';
|
||||||
|
|
||||||
const formRef = ref(null);
|
const formRef = ref(null);
|
||||||
|
|
||||||
@ -108,7 +124,7 @@ const beforeUpload = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleUploadChange = (response) => {
|
const handleUploadChange = (response) => {
|
||||||
formData.businessLicenseUrl = response[0].url;
|
formData.businessLicenseUrl = response?.[0]?.url;
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
@ -190,6 +206,45 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.image-upload-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-area {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-area {
|
||||||
|
width: 280px;
|
||||||
|
height: 200px;
|
||||||
|
border: 1px solid var(--el-border-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: var(--el-fill-color-light);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-empty {
|
||||||
|
border: 1px dashed var(--el-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-empty-text {
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-uploader .avatar {
|
||||||
|
width: 178px;
|
||||||
|
height: 178px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
.avatar-uploader .el-upload {
|
.avatar-uploader .el-upload {
|
||||||
border: 1px dashed var(--el-border-color);
|
border: 1px dashed var(--el-border-color);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
@ -197,23 +252,22 @@ onMounted(() => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: var(--el-transition-duration-fast);
|
transition: var(--el-transition-duration-fast);
|
||||||
width: 220px;
|
|
||||||
height: 160px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-uploader .el-upload:hover {
|
.avatar-uploader .el-upload:hover {
|
||||||
border-color: var(--el-color-primary);
|
border-color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-uploader .avatar-uploader-icon {
|
.el-icon.avatar-uploader-icon {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
color: #8c939d;
|
color: #8c939d;
|
||||||
|
width: 178px;
|
||||||
|
height: 178px;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
.upload-placeholder {
|
.upload-placeholder {
|
||||||
color: #8c939d;
|
color: #8c939d;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@ -7,15 +7,40 @@
|
|||||||
|
|
||||||
<el-form-item label="封面" prop="coverImage">
|
<el-form-item label="封面" prop="coverImage">
|
||||||
<div v-if="readonly && localFormData.coverImage">
|
<div v-if="readonly && localFormData.coverImage">
|
||||||
<img :src="localFormData.coverImage" class="avatar" />
|
<PreviewImage
|
||||||
|
:src="localFormData.coverImage"
|
||||||
|
width="178px"
|
||||||
|
height="178px"
|
||||||
|
fit="cover"
|
||||||
|
radius="8px"
|
||||||
|
:show-zoom-icon="true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else class="image-upload-container">
|
||||||
|
<div class="upload-area">
|
||||||
|
<el-upload class="avatar-uploader" action="/api/file/upload" :show-file-list="false"
|
||||||
|
:on-success="handleAvatarSuccess" :disabled="readonly">
|
||||||
|
<div class="upload-placeholder">
|
||||||
|
<el-icon class="avatar-uploader-icon">
|
||||||
|
<Plus />
|
||||||
|
</el-icon>
|
||||||
|
<div>上传</div>
|
||||||
|
</div>
|
||||||
|
</el-upload>
|
||||||
|
</div>
|
||||||
|
<div v-if="localFormData.coverImage" class="preview-area">
|
||||||
|
<PreviewImage
|
||||||
|
:src="localFormData.coverImage"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
fit="cover"
|
||||||
|
:show-zoom-icon="true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else class="preview-area preview-empty">
|
||||||
|
<span class="preview-empty-text">预览区域</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-upload v-else class="avatar-uploader" action="/api/file/upload" :show-file-list="false"
|
|
||||||
:on-success="handleAvatarSuccess" :disabled="readonly">
|
|
||||||
<img v-if="localFormData.coverImage" :src="localFormData.coverImage" class="avatar" />
|
|
||||||
<el-icon v-else class="avatar-uploader-icon">
|
|
||||||
<Plus />
|
|
||||||
</el-icon>
|
|
||||||
</el-upload>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="赛事类型" prop="eventType">
|
<el-form-item label="赛事类型" prop="eventType">
|
||||||
@ -94,6 +119,7 @@ import { ref, watch, onMounted, nextTick } from 'vue';
|
|||||||
import { Plus } from '@element-plus/icons-vue';
|
import { Plus } from '@element-plus/icons-vue';
|
||||||
import { pointsrulePageGet } from '/@/api/match/pointsrule';
|
import { pointsrulePageGet } from '/@/api/match/pointsrule';
|
||||||
import { regionProvincesGet, regionCitiesbyprovinceGet, regionDistrictsbycityGet } from '/@/api/match/area';
|
import { regionProvincesGet, regionCitiesbyprovinceGet, regionDistrictsbycityGet } from '/@/api/match/area';
|
||||||
|
import PreviewImage from '/@/components/PreviewImage/index.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: { type: Object, required: true },
|
modelValue: { type: Object, required: true },
|
||||||
@ -339,6 +365,42 @@ defineExpose({ validate });
|
|||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.image-upload-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-area {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-area {
|
||||||
|
width: 178px;
|
||||||
|
height: 178px;
|
||||||
|
border: 1px solid var(--el-border-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: var(--el-fill-color-light);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-empty {
|
||||||
|
border: 1px dashed var(--el-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-empty-text {
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-placeholder {
|
||||||
|
color: #8c939d;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.avatar-uploader .avatar {
|
.avatar-uploader .avatar {
|
||||||
width: 178px;
|
width: 178px;
|
||||||
height: 178px;
|
height: 178px;
|
||||||
|
|||||||
@ -43,7 +43,16 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #paymentProofUrl="scope">
|
<template #paymentProofUrl="scope">
|
||||||
<el-image :src="scope.row.paymentProofUrl" style="height: 80px" fit="cover" />
|
<PreviewImage
|
||||||
|
v-if="scope.row.paymentProofUrl"
|
||||||
|
:src="scope.row.paymentProofUrl"
|
||||||
|
width="80px"
|
||||||
|
height="80px"
|
||||||
|
fit="cover"
|
||||||
|
radius="4px"
|
||||||
|
:show-zoom-icon="true"
|
||||||
|
/>
|
||||||
|
<span v-else>-</span>
|
||||||
</template>
|
</template>
|
||||||
<template #action="scope">
|
<template #action="scope">
|
||||||
<el-popconfirm title="确认审核完毕吗?" @confirm="onSureOrder(scope.row.id)">
|
<el-popconfirm title="确认审核完毕吗?" @confirm="onSureOrder(scope.row.id)">
|
||||||
@ -163,6 +172,7 @@ import Step2Units from './Steps/Step2Units.vue';
|
|||||||
import Step3ProjectConfig from './Steps/Step3ProjectConfig.vue';
|
import Step3ProjectConfig from './Steps/Step3ProjectConfig.vue';
|
||||||
import Step4FeeConfig from './Steps/Step4FeeConfig.vue';
|
import Step4FeeConfig from './Steps/Step4FeeConfig.vue';
|
||||||
import ProTable from '/@/components/ProTable/index.vue';
|
import ProTable from '/@/components/ProTable/index.vue';
|
||||||
|
import PreviewImage from '/@/components/PreviewImage/index.vue';
|
||||||
|
|
||||||
|
|
||||||
const isShowDialog = ref(false);
|
const isShowDialog = ref(false);
|
||||||
|
|||||||
@ -99,7 +99,7 @@ const formRef = ref();
|
|||||||
const buildEmptyForm = () => ({
|
const buildEmptyForm = () => ({
|
||||||
id: undefined as number | undefined,
|
id: undefined as number | undefined,
|
||||||
ruleName: '',
|
ruleName: '',
|
||||||
participationPoints: 0,
|
participationPoints: undefined as number | undefined,
|
||||||
remark: '',
|
remark: '',
|
||||||
details: [] as Array<{ id?: number; startRank: number; endRank: number; points: number }>,
|
details: [] as Array<{ id?: number; startRank: number; endRank: number; points: number }>,
|
||||||
});
|
});
|
||||||
@ -108,7 +108,6 @@ const formData = ref(buildEmptyForm());
|
|||||||
|
|
||||||
const formRules = ref({
|
const formRules = ref({
|
||||||
ruleName: [{ required: true, message: '请输入规则名称', trigger: 'blur' }],
|
ruleName: [{ required: true, message: '请输入规则名称', trigger: 'blur' }],
|
||||||
participationPoints: [{ required: true, message: '请输入参与积分', trigger: 'change' }],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const columns = ref([
|
const columns = ref([
|
||||||
@ -139,7 +138,7 @@ const onOpenDialog = async (row?: any) => {
|
|||||||
formData.value = {
|
formData.value = {
|
||||||
id: res.data?.id ?? row.id,
|
id: res.data?.id ?? row.id,
|
||||||
ruleName: res.data?.ruleName ?? row.ruleName ?? '',
|
ruleName: res.data?.ruleName ?? row.ruleName ?? '',
|
||||||
participationPoints: res.data?.participationPoints ?? row.participationPoints ?? 0,
|
participationPoints: res.data?.participationPoints ?? row.participationPoints,
|
||||||
remark: res.data?.remark ?? row.remark ?? '',
|
remark: res.data?.remark ?? row.remark ?? '',
|
||||||
details: (res.data?.details ?? []).map((d: any) => ({
|
details: (res.data?.details ?? []).map((d: any) => ({
|
||||||
id: d.id,
|
id: d.id,
|
||||||
|
|||||||
@ -22,7 +22,16 @@
|
|||||||
|
|
||||||
</template>
|
</template>
|
||||||
<template #idCardImageUrl="scope">
|
<template #idCardImageUrl="scope">
|
||||||
<el-image style="width: 100px;" :src="scope.row.idCardImageUrl" fit="cover"></el-image>
|
<PreviewImage
|
||||||
|
v-if="scope.row.idCardImageUrl"
|
||||||
|
:src="scope.row.idCardImageUrl"
|
||||||
|
width="100px"
|
||||||
|
height="100px"
|
||||||
|
fit="cover"
|
||||||
|
radius="4px"
|
||||||
|
:show-zoom-icon="true"
|
||||||
|
/>
|
||||||
|
<span v-else>-</span>
|
||||||
</template>
|
</template>
|
||||||
<template #action="scope">
|
<template #action="scope">
|
||||||
<el-button v-auth="'user:general:record'" size="small" text type="primary"
|
<el-button v-auth="'user:general:record'" size="small" text type="primary"
|
||||||
@ -76,6 +85,7 @@ import { auths } from '/@/utils/authFunction';
|
|||||||
import ProTable from '/@/components/ProTable/index.vue';
|
import ProTable from '/@/components/ProTable/index.vue';
|
||||||
import { appuserPageGet , appuserAuditPost} from '/@/api/match/appuser';
|
import { appuserPageGet , appuserAuditPost} from '/@/api/match/appuser';
|
||||||
import { eventrecordPageGet , eventrecordCertificatesGet} from '/@/api/match/eventRecord';
|
import { eventrecordPageGet , eventrecordCertificatesGet} from '/@/api/match/eventRecord';
|
||||||
|
import PreviewImage from '/@/components/PreviewImage/index.vue';
|
||||||
|
|
||||||
const initParam = ref({
|
const initParam = ref({
|
||||||
refresh: true,
|
refresh: true,
|
||||||
|
|||||||
@ -15,7 +15,16 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #businessLicenseUrl="scope">
|
<template #businessLicenseUrl="scope">
|
||||||
<el-image style="width: 100px;" :src="scope.row.businessLicenseUrl" fit="cover"></el-image>
|
<PreviewImage
|
||||||
|
v-if="scope.row.businessLicenseUrl"
|
||||||
|
:src="scope.row.businessLicenseUrl"
|
||||||
|
width="100px"
|
||||||
|
height="100px"
|
||||||
|
fit="cover"
|
||||||
|
radius="4px"
|
||||||
|
:show-zoom-icon="true"
|
||||||
|
/>
|
||||||
|
<span v-else>-</span>
|
||||||
</template>
|
</template>
|
||||||
<template #action="scope">
|
<template #action="scope">
|
||||||
<el-button v-auth="'user:general:record'" size="small" text type="primary"
|
<el-button v-auth="'user:general:record'" size="small" text type="primary"
|
||||||
@ -89,6 +98,7 @@ import { auths } from '/@/utils/authFunction';
|
|||||||
import ProTable from '/@/components/ProTable/index.vue';
|
import ProTable from '/@/components/ProTable/index.vue';
|
||||||
import { eventrecordPageGet , eventrecordCertificatesGet} from '/@/api/match/eventRecord';
|
import { eventrecordPageGet , eventrecordCertificatesGet} from '/@/api/match/eventRecord';
|
||||||
import { merchantcertificationPageGet, merchantcertificationAuditPost} from '/@/api/match/merchantcertification';
|
import { merchantcertificationPageGet, merchantcertificationAuditPost} from '/@/api/match/merchantcertification';
|
||||||
|
import PreviewImage from '/@/components/PreviewImage/index.vue';
|
||||||
|
|
||||||
const initParam = ref({
|
const initParam = ref({
|
||||||
refresh: true,
|
refresh: true,
|
||||||
|
|||||||
@ -67,12 +67,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="sysMenu">
|
<script setup name="sysMenu">
|
||||||
import { defineAsyncComponent, ref, reactive, onMounted } from 'vue';
|
import { defineAsyncComponent, ref, reactive, onMounted, computed } from 'vue';
|
||||||
import { ElMessage, ElForm } from 'element-plus';
|
import { ElMessage, ElForm } from 'element-plus';
|
||||||
import SysMenuApi from '/@/api/SysMenuApi';
|
import SysMenuApi from '/@/api/SysMenuApi';
|
||||||
import { auths } from '/@/utils/authFunction';
|
import { auths } from '/@/utils/authFunction';
|
||||||
import ProTable from '/@/components/ProTable/index.vue';
|
import ProTable from '/@/components/ProTable/index.vue';
|
||||||
import { sysuserPageGet, sysuserUserPost, sysuserUserPut, sysuserDelete } from '/@/api/match/account';
|
import { sysuserPageGet, sysuserUserPost, sysuserUserPut, sysuserDelete, sysuserDetailGet } from '/@/api/match/account';
|
||||||
import { sysroleSelectGet } from '/@/api/match/role';
|
import { sysroleSelectGet } from '/@/api/match/role';
|
||||||
|
|
||||||
// 定义表单引用类型
|
// 定义表单引用类型
|
||||||
@ -99,20 +99,28 @@ const validateConfirmPassword = (rule, value, callback) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const formRules = ref({
|
const formRules = computed(() => {
|
||||||
name: [
|
const rules = {
|
||||||
{ required: true, message: '姓名', trigger: 'blur' }
|
name: [
|
||||||
],
|
{ required: true, message: '姓名', trigger: 'blur' }
|
||||||
account: [
|
],
|
||||||
{ required: true, message: '请输入账号', trigger: 'blur' }
|
account: [
|
||||||
],
|
{ required: true, message: '请输入账号', trigger: 'blur' }
|
||||||
password: [
|
],
|
||||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
};
|
||||||
{ min: 6, max: 32, message: '密码长度在 6 到 32 个字符', trigger: 'blur' }
|
|
||||||
],
|
// 只有新增时才需要验证密码和确认密码
|
||||||
confirmPassword: [
|
if (!isEdit.value) {
|
||||||
{ required: true, validator: validateConfirmPassword, trigger: 'blur' }
|
rules.password = [
|
||||||
],
|
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||||
|
{ min: 6, max: 32, message: '密码长度在 6 到 32 个字符', trigger: 'blur' }
|
||||||
|
];
|
||||||
|
rules.confirmPassword = [
|
||||||
|
{ required: true, validator: validateConfirmPassword, trigger: 'blur' }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return rules;
|
||||||
});
|
});
|
||||||
|
|
||||||
const columns = ref([
|
const columns = ref([
|
||||||
@ -156,12 +164,23 @@ const columns = ref([
|
|||||||
|
|
||||||
const isShowDialog = ref(false);
|
const isShowDialog = ref(false);
|
||||||
const dialogTitle = ref('新增');
|
const dialogTitle = ref('新增');
|
||||||
|
const isEdit = ref(false);
|
||||||
|
|
||||||
const onOpenMenu = async (row) => {
|
const onOpenMenu = async (row) => {
|
||||||
|
|
||||||
dialogTitle.value = row ? '编辑' : '新增';
|
dialogTitle.value = row ? '编辑' : '新增';
|
||||||
|
isEdit.value = !!row;
|
||||||
if (row) {
|
if (row) {
|
||||||
formData.value = row;
|
// 调用详情接口获取完整的用户信息,包括角色
|
||||||
|
const { data } = await sysuserDetailGet({ id: row.id });
|
||||||
|
formData.value = {
|
||||||
|
id: data.id,
|
||||||
|
name: data.name,
|
||||||
|
account: data.account,
|
||||||
|
password: '',
|
||||||
|
confirmPassword: '',
|
||||||
|
roles: data.roles || []
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
formData.value = {
|
formData.value = {
|
||||||
name: '',
|
name: '',
|
||||||
@ -195,7 +214,9 @@ const onSubmit = () => {
|
|||||||
try {
|
try {
|
||||||
let res;
|
let res;
|
||||||
if (formData.value.id) {
|
if (formData.value.id) {
|
||||||
res = await sysuserUserPut(formData.value);
|
// 编辑时,只发送需要更新的字段,不发送密码和确认密码
|
||||||
|
const { password, confirmPassword, ...updateData } = formData.value;
|
||||||
|
res = await sysuserUserPut(updateData);
|
||||||
} else {
|
} else {
|
||||||
res = await sysuserUserPost(formData.value);
|
res = await sysuserUserPost(formData.value);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,7 +60,7 @@
|
|||||||
<el-input v-model="teamFormData.name" placeholder="请输入团队名称" />
|
<el-input v-model="teamFormData.name" placeholder="请输入团队名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="队员">
|
<el-form-item label="队员" prop="memberList">
|
||||||
<div>
|
<div>
|
||||||
<el-button type="primary" @click="openMemberDialog">添加队员</el-button>
|
<el-button type="primary" @click="openMemberDialog">添加队员</el-button>
|
||||||
<div style="margin-top:8px">
|
<div style="margin-top:8px">
|
||||||
@ -319,8 +319,35 @@ const teamFormData = ref({
|
|||||||
memberNames: '',
|
memberNames: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const validateMemberList = (rule, value, callback) => {
|
||||||
|
if (!teamFormData.value.memberList || teamFormData.value.memberList.length === 0) {
|
||||||
|
callback(new Error('请至少选择一名队员'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateLeaderIds = (rule, value, callback) => {
|
||||||
|
if (!value || value.length === 0) {
|
||||||
|
callback(new Error('请选择领队'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateCoachIds = (rule, value, callback) => {
|
||||||
|
if (!value || value.length === 0) {
|
||||||
|
callback(new Error('请选择教练'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const teamFormRules = ref({
|
const teamFormRules = ref({
|
||||||
name: [{ required: true, message: '请输入团队名称', trigger: 'blur' }],
|
name: [{ required: true, message: '请输入团队名称', trigger: 'blur' }],
|
||||||
|
memberList: [{ required: true, validator: validateMemberList, trigger: ['change', 'blur'] }],
|
||||||
|
leaderIds: [{ required: true, validator: validateLeaderIds, trigger: ['change', 'blur'] }],
|
||||||
|
coachIds: [{ required: true, validator: validateCoachIds, trigger: ['change', 'blur'] }],
|
||||||
});
|
});
|
||||||
|
|
||||||
// 成员选择弹窗(使用 ProTable 的多选能力)
|
// 成员选择弹窗(使用 ProTable 的多选能力)
|
||||||
@ -472,10 +499,6 @@ const cancelMemberSelection = () => {
|
|||||||
// 提交新增团队
|
// 提交新增团队
|
||||||
const onTeamSubmit = () => {
|
const onTeamSubmit = () => {
|
||||||
if (!teamFormRef.value) return;
|
if (!teamFormRef.value) return;
|
||||||
if(!teamFormData.value.name) return ElMessage.error('请输入团队名称');
|
|
||||||
if(!teamFormData.value.memberIds.length) return ElMessage.error('请选择队员');
|
|
||||||
if(!teamFormData.value.leaderIds.length) return ElMessage.error('请选择领队');
|
|
||||||
if(!teamFormData.value.coachIds.length) return ElMessage.error('请选择教练');
|
|
||||||
teamFormRef.value.validate(async (valid) => {
|
teamFormRef.value.validate(async (valid) => {
|
||||||
if (!valid) return;
|
if (!valid) return;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -3,8 +3,15 @@
|
|||||||
<ProTable ref="tableRef" :request-api="usereventregistrationListGet" :columns="columns" :pagination="true"
|
<ProTable ref="tableRef" :request-api="usereventregistrationListGet" :columns="columns" :pagination="true"
|
||||||
:tool-button="false" :init-param="initParam" row-key="id">
|
:tool-button="false" :init-param="initParam" row-key="id">
|
||||||
<template #coverImage="scope">
|
<template #coverImage="scope">
|
||||||
<el-image v-if="scope.row?.coverImage" style="height: 60px; width: 80px"
|
<PreviewImage
|
||||||
:src="scope.row.coverImage" fit="cover" />
|
v-if="scope.row?.coverImage"
|
||||||
|
:src="scope.row.coverImage"
|
||||||
|
width="80px"
|
||||||
|
height="60px"
|
||||||
|
fit="cover"
|
||||||
|
radius="4px"
|
||||||
|
:show-zoom-icon="true"
|
||||||
|
/>
|
||||||
<span v-else>-</span>
|
<span v-else>-</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -444,6 +451,7 @@ import Step1BasicInfo from '/@/views/match/manage/Steps/Step1BasicInfo.vue';
|
|||||||
import Step2Units from '/@/views/match/manage/Steps/Step2Units.vue';
|
import Step2Units from '/@/views/match/manage/Steps/Step2Units.vue';
|
||||||
import Step3ProjectConfig from '/@/views/match/manage/Steps/Step3ProjectConfig.vue';
|
import Step3ProjectConfig from '/@/views/match/manage/Steps/Step3ProjectConfig.vue';
|
||||||
import Step4FeeConfig from '/@/views/match/manage/Steps/Step4FeeConfig.vue';
|
import Step4FeeConfig from '/@/views/match/manage/Steps/Step4FeeConfig.vue';
|
||||||
|
import PreviewImage from '/@/components/PreviewImage/index.vue';
|
||||||
|
|
||||||
const tableRef = ref();
|
const tableRef = ref();
|
||||||
const initParam = ref({ refresh: true });
|
const initParam = ref({ refresh: true });
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user