|
@@ -3,13 +3,13 @@
|
|
|
<view class="ut-upload-card">
|
|
<view class="ut-upload-card">
|
|
|
<template v-for="(item, index) in fileList" :key="index">
|
|
<template v-for="(item, index) in fileList" :key="index">
|
|
|
<view :style="{ width, height }" class="card-item">
|
|
<view :style="{ width, height }" class="card-item">
|
|
|
- <template v-if="accept === 'image'">
|
|
|
|
|
|
|
+ <template v-if="getItemKind(item) === 'image'">
|
|
|
<image :src="item.status === 'uploading' && item.tempUrl ? item.tempUrl : item.url" :mode="mode" style="width: 100%; height: 100%" @click="onPreview(index)"></image>
|
|
<image :src="item.status === 'uploading' && item.tempUrl ? item.tempUrl : item.url" :mode="mode" style="width: 100%; height: 100%" @click="onPreview(index)"></image>
|
|
|
</template>
|
|
</template>
|
|
|
- <template v-else-if="accept === 'video'">
|
|
|
|
|
|
|
+ <template v-else-if="getItemKind(item) === 'video'">
|
|
|
<video :src="item.status === 'uploading' && item.tempUrl ? item.tempUrl : item.url" controls style="width: 100%; height: 100%" @click="onPreview(index)"></video>
|
|
<video :src="item.status === 'uploading' && item.tempUrl ? item.tempUrl : item.url" controls style="width: 100%; height: 100%" @click="onPreview(index)"></video>
|
|
|
</template>
|
|
</template>
|
|
|
- <template v-if="accept === 'file'">
|
|
|
|
|
|
|
+ <template v-else>
|
|
|
<view class="d-flex flex-cln file-box" @click="onPreview(index)">
|
|
<view class="d-flex flex-cln file-box" @click="onPreview(index)">
|
|
|
<view class="flex1">
|
|
<view class="flex1">
|
|
|
<view class="f-s-28 c-primary up-line-2">{{ item.fileName || '文件' }}</view>
|
|
<view class="f-s-28 c-primary up-line-2">{{ item.fileName || '文件' }}</view>
|
|
@@ -28,12 +28,37 @@
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
</template>
|
|
</template>
|
|
|
- <view v-if="(fileList.length < maxCount)" :style="{ width, height }" @click="clickBtnUpload" class="card-item btn-select d-flex flex-cln j-c a-c">
|
|
|
|
|
- <view class="mb-10">
|
|
|
|
|
- <up-icon :color="iconColor" :name="iconName" :iconSize="iconSize"></up-icon>
|
|
|
|
|
|
|
+ <template v-if="fileList.length < maxCount">
|
|
|
|
|
+ <!-- 兼容旧用法:只有一种类型时,仍然只展示一个按钮,文案/样式按类型和配置对象决定 -->
|
|
|
|
|
+ <view
|
|
|
|
|
+ v-if="getAcceptKinds().length === 1"
|
|
|
|
|
+ :style="[{ width, height }, getUploadBtnStyle(getAcceptKinds()[0])]"
|
|
|
|
|
+ @click="clickBtnUpload"
|
|
|
|
|
+ class="card-item btn-select d-flex flex-cln j-c a-c"
|
|
|
|
|
+ :class="getUploadBtnClass(getAcceptKinds()[0])"
|
|
|
|
|
+ >
|
|
|
|
|
+ <view class="mb-10">
|
|
|
|
|
+ <up-icon :color="getUploadIconColor(getAcceptKinds()[0])" :name="getUploadIconName(getAcceptKinds()[0])" :iconSize="getUploadIconSize(getAcceptKinds()[0])"></up-icon>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="f-s-24 c-primary" :style="getUploadBtnTextStyle(getAcceptKinds()[0])">{{ getUploadTextByKind(getAcceptKinds()[0]) }}</view>
|
|
|
</view>
|
|
</view>
|
|
|
- <view class="f-s-24 c-primary">{{ uploadText }}</view>
|
|
|
|
|
- </view>
|
|
|
|
|
|
|
+ <!-- 多种类型时,根据 accept 展示多个按钮,每个按钮对应一种上传类型 -->
|
|
|
|
|
+ <template v-else>
|
|
|
|
|
+ <view
|
|
|
|
|
+ v-for="kind in getAcceptKinds()"
|
|
|
|
|
+ :key="kind"
|
|
|
|
|
+ :style="[{ width, height }, getUploadBtnStyle(kind)]"
|
|
|
|
|
+ @click="onClickUpload(kind)"
|
|
|
|
|
+ class="card-item btn-select d-flex flex-cln j-c a-c"
|
|
|
|
|
+ :class="getUploadBtnClass(kind)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <view class="mb-10">
|
|
|
|
|
+ <up-icon :color="getUploadIconColor(kind)" :name="getUploadIconName(kind)" :iconSize="getUploadIconSize(kind)"></up-icon>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="f-s-24 c-primary" :style="getUploadBtnTextStyle(kind)">{{ getUploadTextByKind(kind) }}</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </template>
|
|
|
</view>
|
|
</view>
|
|
|
</template>
|
|
</template>
|
|
|
</template>
|
|
</template>
|
|
@@ -43,6 +68,18 @@ import upload from '@/utils/upload';
|
|
|
import { fileExt, isUrl } from '@/utils/ruoyi';
|
|
import { fileExt, isUrl } from '@/utils/ruoyi';
|
|
|
import { getFileIconByUrl } from '@/utils/common';
|
|
import { getFileIconByUrl } from '@/utils/common';
|
|
|
|
|
|
|
|
|
|
+type AcceptKind = 'image' | 'video' | 'file';
|
|
|
|
|
+
|
|
|
|
|
+interface UploadButtonConfigItem {
|
|
|
|
|
+ text?: string; // 按钮文字
|
|
|
|
|
+ bgColor?: string; // 按钮背景色
|
|
|
|
|
+ textColor?: string; // 文字颜色
|
|
|
|
|
+ iconName?: string; // 覆盖默认图标名
|
|
|
|
|
+ iconColor?: string; // 覆盖默认图标颜色
|
|
|
|
|
+ iconSize?: string | number; // 覆盖默认图标大小
|
|
|
|
|
+ customClass?: string; // 自定义 class
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
interface FileItem {
|
|
interface FileItem {
|
|
|
url: string;
|
|
url: string;
|
|
|
fileName?: string;
|
|
fileName?: string;
|
|
@@ -52,6 +89,7 @@ interface FileItem {
|
|
|
tempUrl?: string;
|
|
tempUrl?: string;
|
|
|
status?: 'uploading' | 'done' | 'error';
|
|
status?: 'uploading' | 'done' | 'error';
|
|
|
progress?: number;
|
|
progress?: number;
|
|
|
|
|
+ kind?: AcceptKind;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
interface UploadEvent {
|
|
interface UploadEvent {
|
|
@@ -69,8 +107,12 @@ interface Props {
|
|
|
height: string;
|
|
height: string;
|
|
|
multiple: boolean;
|
|
multiple: boolean;
|
|
|
uploadText: string;
|
|
uploadText: string;
|
|
|
|
|
+ uploadImageText?: string;
|
|
|
|
|
+ uploadVideoText?: string;
|
|
|
|
|
+ uploadFileText?: string;
|
|
|
|
|
+ uploadButtonConfig?: Partial<Record<AcceptKind, UploadButtonConfigItem>>; // 统一配置 image/file/video 按钮
|
|
|
uploadIcon: string;
|
|
uploadIcon: string;
|
|
|
- accept: string; // image/video/file
|
|
|
|
|
|
|
+ accept: string; // image/video/file image,file,video
|
|
|
uploadUrl?: string;
|
|
uploadUrl?: string;
|
|
|
uploadTimeout?: number;
|
|
uploadTimeout?: number;
|
|
|
extension?: string | string[]; // 限制选择的文件扩展名(仅在 accept==='file' 生效)
|
|
extension?: string | string[]; // 限制选择的文件扩展名(仅在 accept==='file' 生效)
|
|
@@ -89,8 +131,11 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
height: '210rpx',
|
|
height: '210rpx',
|
|
|
multiple: true,
|
|
multiple: true,
|
|
|
uploadText: '点击上传',
|
|
uploadText: '点击上传',
|
|
|
|
|
+ uploadImageText: '上传图片',
|
|
|
|
|
+ uploadVideoText: '上传视频',
|
|
|
|
|
+ uploadFileText: '上传文件',
|
|
|
uploadIcon: 'plus',
|
|
uploadIcon: 'plus',
|
|
|
- accept: 'image',
|
|
|
|
|
|
|
+ accept: 'image', // image/video/file image,file,video
|
|
|
uploadUrl: '/resource/oss/upload',
|
|
uploadUrl: '/resource/oss/upload',
|
|
|
uploadTimeout: 600000,
|
|
uploadTimeout: 600000,
|
|
|
extension: () => ['pdf'],
|
|
extension: () => ['pdf'],
|
|
@@ -100,6 +145,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
iconColor: '#37a954',
|
|
iconColor: '#37a954',
|
|
|
iconSize: '30rpx',
|
|
iconSize: '30rpx',
|
|
|
mode: 'aspectFill',
|
|
mode: 'aspectFill',
|
|
|
|
|
+ uploadButtonConfig: () => ({}),
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const emit = defineEmits<{
|
|
const emit = defineEmits<{
|
|
@@ -108,14 +154,43 @@ const emit = defineEmits<{
|
|
|
}>();
|
|
}>();
|
|
|
|
|
|
|
|
const fileList = ref<FileItem[]>([]);
|
|
const fileList = ref<FileItem[]>([]);
|
|
|
-const buildFileName = (path: string, kind: 'image' | 'video' | 'file') => {
|
|
|
|
|
|
|
+const buildFileName = (path: string, kind: AcceptKind) => {
|
|
|
const ext = fileExt(path) || 'dat';
|
|
const ext = fileExt(path) || 'dat';
|
|
|
const prefix = kind === 'image' ? 'img' : kind === 'video' ? 'video' : 'file';
|
|
const prefix = kind === 'image' ? 'img' : kind === 'video' ? 'video' : 'file';
|
|
|
return `${prefix}_${Date.now()}.${ext}`;
|
|
return `${prefix}_${Date.now()}.${ext}`;
|
|
|
};
|
|
};
|
|
|
-const clickBtnUpload = async () => {
|
|
|
|
|
- // 判断是图片/视频/文件不同的上传
|
|
|
|
|
- // 使用chooseMedia选择图片或视频 chooseMessageFile选择文件
|
|
|
|
|
|
|
+const getAcceptKinds = (): AcceptKind[] => {
|
|
|
|
|
+ if (!props.accept) return ['image'];
|
|
|
|
|
+ const parts = String(props.accept)
|
|
|
|
|
+ .split(',')
|
|
|
|
|
+ .map((s) => s.trim())
|
|
|
|
|
+ .filter(Boolean) as AcceptKind[];
|
|
|
|
|
+ const all: AcceptKind[] = ['image', 'video', 'file'];
|
|
|
|
|
+ const result = parts.filter((p) => all.includes(p));
|
|
|
|
|
+ return result.length ? result : ['image'];
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const getBtnConfig = (kind: AcceptKind): UploadButtonConfigItem => {
|
|
|
|
|
+ return (props.uploadButtonConfig && props.uploadButtonConfig[kind]) || {};
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const detectKindByUrl = (path?: string | null): AcceptKind => {
|
|
|
|
|
+ if (!path) return 'file';
|
|
|
|
|
+ const ext = (fileExt(path) || '').toLowerCase();
|
|
|
|
|
+ const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
|
|
|
|
|
+ const videoExts = ['mp4', 'mov', 'avi', 'wmv', 'flv', 'mkv', 'webm', '3gp'];
|
|
|
|
|
+ if (imageExts.includes(ext)) return 'image';
|
|
|
|
|
+ if (videoExts.includes(ext)) return 'video';
|
|
|
|
|
+ return 'file';
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const getItemKind = (item: FileItem): AcceptKind => {
|
|
|
|
|
+ if (item.kind) return item.kind;
|
|
|
|
|
+ const path = item.tempUrl || item.url;
|
|
|
|
|
+ return detectKindByUrl(path);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const doUploadByKind = async (kind: AcceptKind) => {
|
|
|
try {
|
|
try {
|
|
|
const remain = props.maxCount - fileList.value.length;
|
|
const remain = props.maxCount - fileList.value.length;
|
|
|
if (remain <= 0) {
|
|
if (remain <= 0) {
|
|
@@ -123,7 +198,7 @@ const clickBtnUpload = async () => {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (props.accept === 'file') {
|
|
|
|
|
|
|
+ if (kind === 'file') {
|
|
|
const res: any = await uni.chooseMessageFile({
|
|
const res: any = await uni.chooseMessageFile({
|
|
|
count: props.multiple ? remain : 1,
|
|
count: props.multiple ? remain : 1,
|
|
|
type: 'file',
|
|
type: 'file',
|
|
@@ -132,7 +207,7 @@ const clickBtnUpload = async () => {
|
|
|
const files = (res?.tempFiles || []) as Array<{ name?: string; size: number; path: string }>;
|
|
const files = (res?.tempFiles || []) as Array<{ name?: string; size: number; path: string }>;
|
|
|
for (const f of files) {
|
|
for (const f of files) {
|
|
|
const name = f.name || buildFileName(f.path, 'file');
|
|
const name = f.name || buildFileName(f.path, 'file');
|
|
|
- const placeholder: FileItem = { url: '', fileName: name, fileSize: f.size, tempUrl: f.path, status: 'uploading' };
|
|
|
|
|
|
|
+ const placeholder: FileItem = { url: '', fileName: name, fileSize: f.size, tempUrl: f.path, status: 'uploading', kind: 'file' };
|
|
|
const idx = fileList.value.push(placeholder) - 1;
|
|
const idx = fileList.value.push(placeholder) - 1;
|
|
|
try {
|
|
try {
|
|
|
const upRes = await upload({ url: props.uploadUrl!, filePath: f.path, name: 'file', timeout: props.uploadTimeout });
|
|
const upRes = await upload({ url: props.uploadUrl!, filePath: f.path, name: 'file', timeout: props.uploadTimeout });
|
|
@@ -156,13 +231,21 @@ const clickBtnUpload = async () => {
|
|
|
} else {
|
|
} else {
|
|
|
const res: any = await uni.chooseMedia({
|
|
const res: any = await uni.chooseMedia({
|
|
|
count: props.multiple ? remain : 1,
|
|
count: props.multiple ? remain : 1,
|
|
|
- mediaType: props.accept === 'image' ? ['image'] : ['video'],
|
|
|
|
|
|
|
+ mediaType: kind === 'image' ? ['image'] : ['video'],
|
|
|
sourceType: ['album', 'camera'],
|
|
sourceType: ['album', 'camera'],
|
|
|
});
|
|
});
|
|
|
const files = (res?.tempFiles || []) as Array<{ tempFilePath: string; size: number; thumbTempFilePath?: string }>;
|
|
const files = (res?.tempFiles || []) as Array<{ tempFilePath: string; size: number; thumbTempFilePath?: string }>;
|
|
|
for (const f of files) {
|
|
for (const f of files) {
|
|
|
- const name = buildFileName(f.tempFilePath, props.accept === 'image' ? 'image' : 'video');
|
|
|
|
|
- const placeholder: FileItem = { url: '', fileName: name, fileSize: f.size, tempUrl: f.tempFilePath, status: 'uploading' };
|
|
|
|
|
|
|
+ const name = buildFileName(f.tempFilePath, kind);
|
|
|
|
|
+ const placeholder: FileItem = {
|
|
|
|
|
+ url: '',
|
|
|
|
|
+ fileName: name,
|
|
|
|
|
+ fileSize: f.size,
|
|
|
|
|
+ tempUrl: f.tempFilePath,
|
|
|
|
|
+ coverUrl: f.thumbTempFilePath,
|
|
|
|
|
+ status: 'uploading',
|
|
|
|
|
+ kind
|
|
|
|
|
+ };
|
|
|
const idx = fileList.value.push(placeholder) - 1;
|
|
const idx = fileList.value.push(placeholder) - 1;
|
|
|
try {
|
|
try {
|
|
|
const upRes = await upload({ url: props.uploadUrl!, filePath: f.tempFilePath, name: 'file', timeout: props.uploadTimeout });
|
|
const upRes = await upload({ url: props.uploadUrl!, filePath: f.tempFilePath, name: 'file', timeout: props.uploadTimeout });
|
|
@@ -184,20 +267,76 @@ const clickBtnUpload = async () => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 最后再统一触发一次
|
|
|
|
|
emitCurrentValue();
|
|
emitCurrentValue();
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
console.log('upload error:', e);
|
|
console.log('upload error:', e);
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+// 兼容旧用法:当模板中只用一个上传按钮时,默认使用 accept 中的第一种类型
|
|
|
|
|
+const clickBtnUpload = async () => {
|
|
|
|
|
+ const kinds = getAcceptKinds();
|
|
|
|
|
+ await doUploadByKind(kinds[0]);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const onClickUpload = async (kind: AcceptKind) => {
|
|
|
|
|
+ await doUploadByKind(kind);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const getUploadTextByKind = (kind: AcceptKind) => {
|
|
|
|
|
+ const cfg = getBtnConfig(kind);
|
|
|
|
|
+ if (cfg.text) return cfg.text;
|
|
|
|
|
+ // 兼容旧用法:如果外部显式传入了 uploadText(且不是默认值),统一用这个文案
|
|
|
|
|
+ if (props.uploadText && props.uploadText !== '点击上传') {
|
|
|
|
|
+ return props.uploadText;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (kind === 'image') return props.uploadImageText || '上传图片';
|
|
|
|
|
+ if (kind === 'video') return props.uploadVideoText || '上传视频';
|
|
|
|
|
+ if (kind === 'file') return props.uploadFileText || '上传文件';
|
|
|
|
|
+ return props.uploadText || '点击上传';
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const getUploadBtnStyle = (kind: AcceptKind) => {
|
|
|
|
|
+ const cfg = getBtnConfig(kind);
|
|
|
|
|
+ const style: Record<string, string> = {};
|
|
|
|
|
+ if (cfg.bgColor) style.backgroundColor = cfg.bgColor;
|
|
|
|
|
+ return style;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const getUploadBtnTextStyle = (kind: AcceptKind) => {
|
|
|
|
|
+ const cfg = getBtnConfig(kind);
|
|
|
|
|
+ const style: Record<string, string> = {};
|
|
|
|
|
+ if (cfg.textColor) style.color = cfg.textColor;
|
|
|
|
|
+ return style;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const getUploadBtnClass = (kind: AcceptKind) => {
|
|
|
|
|
+ const cfg = getBtnConfig(kind);
|
|
|
|
|
+ return cfg.customClass || '';
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const getUploadIconName = (kind: AcceptKind) => {
|
|
|
|
|
+ const cfg = getBtnConfig(kind);
|
|
|
|
|
+ return cfg.iconName || props.iconName;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const getUploadIconColor = (kind: AcceptKind) => {
|
|
|
|
|
+ const cfg = getBtnConfig(kind);
|
|
|
|
|
+ return cfg.iconColor || props.iconColor;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const getUploadIconSize = (kind: AcceptKind) => {
|
|
|
|
|
+ const cfg = getBtnConfig(kind);
|
|
|
|
|
+ return cfg.iconSize || props.iconSize;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
|
|
|
const onPreview = (index: number) => {
|
|
const onPreview = (index: number) => {
|
|
|
const item = fileList.value[index];
|
|
const item = fileList.value[index];
|
|
|
if (!item) return;
|
|
if (!item) return;
|
|
|
|
|
+ const kind = getItemKind(item);
|
|
|
// 文件类型:上传中也允许预览本地临时文件
|
|
// 文件类型:上传中也允许预览本地临时文件
|
|
|
- if (props.accept === 'file') {
|
|
|
|
|
|
|
+ if (kind === 'file') {
|
|
|
const localPath = item.status === 'uploading' && item.tempUrl
|
|
const localPath = item.status === 'uploading' && item.tempUrl
|
|
|
? item.tempUrl
|
|
? item.tempUrl
|
|
|
: (!isUrl(item.url) ? item.url : '');
|
|
: (!isUrl(item.url) ? item.url : '');
|
|
@@ -238,21 +377,26 @@ const onPreview = (index: number) => {
|
|
|
}
|
|
}
|
|
|
// 图片/视频:上传中不允许预览
|
|
// 图片/视频:上传中不允许预览
|
|
|
if (item?.status === 'uploading') return;
|
|
if (item?.status === 'uploading') return;
|
|
|
- if (props.accept === 'image') {
|
|
|
|
|
- const urls = fileList.value.map((i) => i.url);
|
|
|
|
|
|
|
+ if (kind === 'image') {
|
|
|
|
|
+ const images = fileList.value.filter((i) => getItemKind(i) === 'image');
|
|
|
|
|
+ const urls = images.map((i) => i.url);
|
|
|
|
|
+ const currentUrl = item.url;
|
|
|
|
|
+ const current = urls.indexOf(currentUrl);
|
|
|
uni.previewImage({
|
|
uni.previewImage({
|
|
|
urls,
|
|
urls,
|
|
|
- current: urls[index]
|
|
|
|
|
|
|
+ current: current >= 0 ? urls[current] : urls[0]
|
|
|
});
|
|
});
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- if (props.accept === 'video') {
|
|
|
|
|
|
|
+ if (kind === 'video') {
|
|
|
// #ifdef MP-WEIXIN
|
|
// #ifdef MP-WEIXIN
|
|
|
- const sources = fileList.value.map((i) => ({ url: i.url, type: 'video', poster: i.coverUrl || '' }));
|
|
|
|
|
|
|
+ const videos = fileList.value.filter((i) => getItemKind(i) === 'video');
|
|
|
|
|
+ const sources = videos.map((i) => ({ url: i.url, type: 'video', poster: i.coverUrl || '' }));
|
|
|
|
|
+ const current = videos.findIndex((v) => v === item);
|
|
|
// @ts-ignore
|
|
// @ts-ignore
|
|
|
wx.previewMedia({
|
|
wx.previewMedia({
|
|
|
sources,
|
|
sources,
|
|
|
- current: index
|
|
|
|
|
|
|
+ current: current >= 0 ? current : 0
|
|
|
});
|
|
});
|
|
|
// #endif
|
|
// #endif
|
|
|
// #ifndef MP-WEIXIN
|
|
// #ifndef MP-WEIXIN
|