Commit 99def7931afd6f6c9797422d6a4a5fcc89b458ea

Authored by xp.Huang
2 parents ac6ad4c5 b28f82dd

Merge branch 'local_dev_ft' into 'main'

pref:优化产品Topic列表 移除不需要的文字;优化个人头像上传头像使用自带组件

See merge request yunteng/thingskit-front!491
... ... @@ -179,14 +179,22 @@
179 179 cropper?.value?.[event]?.(arg);
180 180 }
181 181
  182 + const blobToFile = (blob, fileName) => {
  183 + const file = new File([blob], fileName, { type: blob.type });
  184 + const formData = new FormData();
  185 + formData.append('file', file);
  186 + return formData;
  187 + };
  188 +
182 189 async function handleOk() {
183 190 const uploadApi = props.uploadApi;
184 191 if (uploadApi && isFunction(uploadApi)) {
185 192 const blob = dataURLtoBlob(previewSource.value);
  193 + const base64D = blobToFile(blob, filename);
186 194 try {
187 195 setModalProps({ confirmLoading: true });
188   - const result = await uploadApi({ name: 'file', file: blob, filename });
189   - emit('uploadSuccess', { source: previewSource.value, data: result.data });
  196 + const result = await uploadApi(base64D);
  197 + emit('uploadSuccess', { source: previewSource.value, data: result.fileStaticUri });
190 198 closeModal();
191 199 } finally {
192 200 setModalProps({ confirmLoading: false });
... ...
1   -<template>
2   - <div :class="getClass" :style="getStyle">
3   - <div :class="`${prefixCls}-image-wrapper`" :style="getImageWrapperStyle" @click="openModal">
4   - <div :class="`${prefixCls}-image-mask`" :style="getImageWrapperStyle">
5   - <Icon
6   - icon="ant-design:cloud-upload-outlined"
7   - :size="getIconWidth"
8   - :style="getImageWrapperStyle"
9   - color="#d6d6d6"
10   - />
11   - </div>
12   - <img :src="sourceValue" v-if="sourceValue" alt="avatar" />
13   - </div>
14   - <a-button
15   - :class="`${prefixCls}-upload-btn`"
16   - @click="openModal"
17   - v-if="showBtn"
18   - v-bind="btnProps"
19   - >
20   - {{ btnText ? btnText : t('component.cropper.selectImage') }}
21   - </a-button>
22   -
23   - <CopperModal
24   - @register="register"
25   - @uploadSuccess="handleUploadSuccess"
26   - :uploadApi="uploadApi"
27   - :src="sourceValue"
28   - />
29   - </div>
30   -</template>
31   -<script lang="ts">
32   - import {
33   - defineComponent,
34   - computed,
35   - CSSProperties,
36   - unref,
37   - ref,
38   - watchEffect,
39   - watch,
40   - PropType,
41   - } from 'vue';
42   - import CopperModal from './CopperModal.vue';
43   - import { useDesign } from '/@/hooks/web/useDesign';
44   - import { useModal } from '/@/components/Modal';
45   - import { useMessage } from '/@/hooks/web/useMessage';
46   - import { useI18n } from '/@/hooks/web/useI18n';
47   - import type { ButtonProps } from '/@/components/Button';
48   - import Icon from '/@/components/Icon';
49   -
50   - const props = {
51   - width: { type: [String, Number], default: '200px' },
52   - value: { type: String },
53   - showBtn: { type: Boolean, default: true },
54   - btnProps: { type: Object as PropType<ButtonProps> },
55   - btnText: { type: String, default: '' },
56   - uploadApi: { type: Function as PropType<({ file: Blob, name: string }) => Promise<void>> },
57   - };
58   -
59   - export default defineComponent({
60   - name: 'CropperAvatar',
61   - components: { CopperModal, Icon },
62   - props,
63   - emits: ['update:value', 'change'],
64   - setup(props, { emit, expose }) {
65   - const sourceValue = ref(props.value || '');
66   - const { prefixCls } = useDesign('cropper-avatar');
67   - const [register, { openModal, closeModal }] = useModal();
68   - const { createMessage } = useMessage();
69   - const { t } = useI18n();
70   -
71   - const getClass = computed(() => [prefixCls]);
72   -
73   - const getWidth = computed(() => `${props.width}`.replace(/px/, '') + 'px');
74   -
75   - const getIconWidth = computed(() => parseInt(`${props.width}`.replace(/px/, '')) / 2 + 'px');
76   -
77   - const getStyle = computed((): CSSProperties => ({ width: unref(getWidth) }));
78   -
79   - const getImageWrapperStyle = computed(
80   - (): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) })
81   - );
82   -
83   - watchEffect(() => {
84   - sourceValue.value = props.value || '';
85   - });
86   -
87   - watch(
88   - () => sourceValue.value,
89   - (v: string) => {
90   - emit('update:value', v);
91   - }
92   - );
93   -
94   - function handleUploadSuccess(source) {
95   - sourceValue.value = source;
96   - emit('change', source);
97   - createMessage.success(t('component.cropper.uploadSuccess'));
98   - }
99   -
100   - expose({ openModal: openModal.bind(null, true), closeModal });
101   -
102   - return {
103   - t,
104   - prefixCls,
105   - register,
106   - openModal,
107   - getIconWidth,
108   - sourceValue,
109   - getClass,
110   - getImageWrapperStyle,
111   - getStyle,
112   - handleUploadSuccess,
113   - };
114   - },
115   - });
116   -</script>
117   -
118   -<style lang="less" scoped>
119   - @prefix-cls: ~'@{namespace}-cropper-avatar';
120   -
121   - .@{prefix-cls} {
122   - display: inline-block;
123   - text-align: center;
124   -
125   - &-image-wrapper {
126   - overflow: hidden;
127   - cursor: pointer;
128   - background: @component-background;
129   - border: 1px solid @border-color-base;
130   - border-radius: 50%;
131   -
132   - img {
133   - width: 100%;
134   - }
135   - }
136   -
137   - &-image-mask {
138   - opacity: 0;
139   - position: absolute;
140   - width: inherit;
141   - height: inherit;
142   - border-radius: inherit;
143   - border: inherit;
144   - background: rgba(0, 0, 0, 0.4);
145   - cursor: pointer;
146   - -webkit-transition: opacity 0.4s;
147   - transition: opacity 0.4s;
148   -
149   - :deep(svg) {
150   - margin: auto;
151   - }
152   - }
153   -
154   - &-image-mask:hover {
155   - opacity: 40;
156   - }
157   -
158   - &-upload-btn {
159   - margin: 10px auto;
160   - }
161   - }
162   -</style>
  1 +<template>
  2 + <div :class="getClass" :style="getStyle">
  3 + <div :class="`${prefixCls}-image-wrapper`" :style="getImageWrapperStyle" @click="openModal">
  4 + <div :class="`${prefixCls}-image-mask`" :style="getImageWrapperStyle">
  5 + <Icon
  6 + icon="ant-design:cloud-upload-outlined"
  7 + :size="getIconWidth"
  8 + :style="getImageWrapperStyle"
  9 + color="#d6d6d6"
  10 + />
  11 + </div>
  12 + <img :src="sourceValue" v-if="sourceValue" alt="avatar" />
  13 + </div>
  14 + <a-button
  15 + :class="`${prefixCls}-upload-btn`"
  16 + @click="openModal"
  17 + v-if="showBtn"
  18 + v-bind="btnProps"
  19 + >
  20 + {{ btnText ? btnText : t('component.cropper.selectImage') }}
  21 + </a-button>
  22 +
  23 + <CopperModal
  24 + @register="register"
  25 + @uploadSuccess="handleUploadSuccess"
  26 + :uploadApi="uploadApi"
  27 + :src="sourceValue"
  28 + />
  29 + </div>
  30 +</template>
  31 +<script lang="ts">
  32 + import {
  33 + defineComponent,
  34 + computed,
  35 + CSSProperties,
  36 + unref,
  37 + ref,
  38 + watchEffect,
  39 + watch,
  40 + PropType,
  41 + } from 'vue';
  42 + import CopperModal from './CopperModal.vue';
  43 + import { useDesign } from '/@/hooks/web/useDesign';
  44 + import { useModal } from '/@/components/Modal';
  45 + import { useMessage } from '/@/hooks/web/useMessage';
  46 + import { useI18n } from '/@/hooks/web/useI18n';
  47 + import type { ButtonProps } from '/@/components/Button';
  48 + import Icon from '/@/components/Icon';
  49 +
  50 + const props = {
  51 + width: { type: [String, Number], default: '200px' },
  52 + value: { type: String },
  53 + showBtn: { type: Boolean, default: true },
  54 + btnProps: { type: Object as PropType<ButtonProps> },
  55 + btnText: { type: String, default: '' },
  56 + uploadApi: { type: Function as PropType<({ file: Blob, name: string }) => Promise<void>> },
  57 + };
  58 +
  59 + export default defineComponent({
  60 + name: 'CropperAvatar',
  61 + components: { CopperModal, Icon },
  62 + props,
  63 + emits: ['update:value', 'change'],
  64 + setup(props, { emit, expose }) {
  65 + const sourceValue = ref(props.value || '');
  66 + const { prefixCls } = useDesign('cropper-avatar');
  67 + const [register, { openModal, closeModal }] = useModal();
  68 + const { createMessage } = useMessage();
  69 + const { t } = useI18n();
  70 +
  71 + const getClass = computed(() => [prefixCls]);
  72 +
  73 + const getWidth = computed(() => `${props.width}`.replace(/px/, '') + 'px');
  74 +
  75 + const getIconWidth = computed(() => parseInt(`${props.width}`.replace(/px/, '')) / 2 + 'px');
  76 +
  77 + const getStyle = computed((): CSSProperties => ({ width: unref(getWidth) }));
  78 +
  79 + const getImageWrapperStyle = computed(
  80 + (): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) })
  81 + );
  82 +
  83 + watchEffect(() => {
  84 + sourceValue.value = props.value || '';
  85 + });
  86 +
  87 + watch(
  88 + () => sourceValue.value,
  89 + (v: string) => {
  90 + emit('update:value', v);
  91 + }
  92 + );
  93 +
  94 + function handleUploadSuccess(source) {
  95 + sourceValue.value = source.data;
  96 + emit('change', source);
  97 + createMessage.success(t('component.cropper.uploadSuccess'));
  98 + }
  99 +
  100 + expose({ openModal: openModal.bind(null, true), closeModal });
  101 +
  102 + return {
  103 + t,
  104 + prefixCls,
  105 + register,
  106 + openModal,
  107 + getIconWidth,
  108 + sourceValue,
  109 + getClass,
  110 + getImageWrapperStyle,
  111 + getStyle,
  112 + handleUploadSuccess,
  113 + };
  114 + },
  115 + });
  116 +</script>
  117 +
  118 +<style lang="less" scoped>
  119 + @prefix-cls: ~'@{namespace}-cropper-avatar';
  120 +
  121 + .@{prefix-cls} {
  122 + display: inline-block;
  123 + text-align: center;
  124 +
  125 + &-image-wrapper {
  126 + overflow: hidden;
  127 + cursor: pointer;
  128 + background: @component-background;
  129 + border: 1px solid @border-color-base;
  130 + border-radius: 50%;
  131 +
  132 + img {
  133 + width: 100%;
  134 + }
  135 + }
  136 +
  137 + &-image-mask {
  138 + opacity: 0;
  139 + position: absolute;
  140 + width: inherit;
  141 + height: inherit;
  142 + border-radius: inherit;
  143 + border: inherit;
  144 + background: rgba(0, 0, 0, 0.4);
  145 + cursor: pointer;
  146 + -webkit-transition: opacity 0.4s;
  147 + transition: opacity 0.4s;
  148 +
  149 + :deep(svg) {
  150 + margin: auto;
  151 + }
  152 + }
  153 +
  154 + &-image-mask:hover {
  155 + opacity: 40;
  156 + }
  157 +
  158 + &-upload-btn {
  159 + margin: 10px auto;
  160 + }
  161 + }
  162 +</style>
... ...
... ... @@ -13,30 +13,9 @@
13 13 <div class="text-center cursor-pointer">
14 14 <div class="text-left text-lg border-gray-200 p-2 border">个人头像</div>
15 15 <div class="flex items-center justify-center mt-4">
16   - <Upload
17   - name="avatar"
18   - list-type="picture-card"
19   - class="round !flex justify-center items-center"
20   - :show-upload-list="false"
21   - :customRequest="customUpload"
22   - :before-upload="beforeUpload"
23   - >
24   - <img
25   - class="round"
26   - v-if="personalPicture || headerImg"
27   - :src="personalPicture || headerImg"
28   - alt="avatar"
29   - />
30   - <div v-else>
31   - <div>
32   - <LoadingOutlined class="text-3xl" v-if="loading" />
33   - <PlusOutlined v-else class="text-3xl" />
34   - </div>
35   - </div>
36   - </Upload>
  16 + <CropperAvatar @change="handleChange" :uploadApi="uploadApi" :value="personalPicture" />
37 17 </div>
38 18 </div>
39   -
40 19 <Description @register="registerDesc" class="mt-8 p-4" />
41 20 </div>
42 21 <div class="ml-4 border border-gray-200">
... ... @@ -49,22 +28,19 @@
49 28 </BasicModal>
50 29 </template>
51 30 <script lang="ts">
52   - import { defineComponent, ref, unref } from 'vue';
  31 + import { defineComponent, ref } from 'vue';
53 32 import { BasicModal, useModalInner } from '/@/components/Modal/index';
54 33 import { BasicForm, useForm } from '/@/components/Form/index';
55 34 import { formSchema } from './config';
56 35 import { Description, DescItem, useDescription } from '/@/components/Description/index';
57 36 import { uploadApi, personalPut } from '/@/api/personal/index';
58 37 import { useMessage } from '/@/hooks/web/useMessage';
59   - import { Upload } from 'ant-design-vue';
60   - import { PlusOutlined } from '@ant-design/icons-vue';
61 38 import { useUserStore } from '/@/store/modules/user';
62   - import type { FileItem } from '/@/components/Upload/src/typing';
63   - import { LoadingOutlined } from '@ant-design/icons-vue';
64 39 import headerImg from '/@/assets/images/logo.png';
65 40 import { getMyInfo } from '/@/api/sys/user';
66 41 import { UserInfoModel } from '/@/api/sys/model/userModel';
67 42 import { UserInfo } from '/#/store';
  43 + import { CropperAvatar } from '/@/components/Cropper';
68 44
69 45 const schema: DescItem[] = [
70 46 {
... ... @@ -95,7 +71,12 @@
95 71
96 72 export default defineComponent({
97 73 name: 'Index',
98   - components: { BasicModal, BasicForm, Description, Upload, PlusOutlined, LoadingOutlined },
  74 + components: {
  75 + BasicModal,
  76 + BasicForm,
  77 + Description,
  78 + CropperAvatar,
  79 + },
99 80 emits: ['refreshPersonal', 'register'],
100 81 setup(_, { emit }) {
101 82 const loading = ref(false);
... ... @@ -111,31 +92,8 @@
111 92 column: 1,
112 93 bordered: true,
113 94 });
114   -
115   - const customUpload = async ({ file }) => {
116   - if (beforeUpload(file)) {
117   - personalPicture.value = '';
118   - loading.value = true;
119   - const formData = new FormData();
120   - formData.append('file', file);
121   - const response = await uploadApi(formData);
122   - if (response.fileStaticUri) {
123   - personalPicture.value = response.fileStaticUri;
124   - loading.value = false;
125   - }
126   - }
127   - };
128   -
129   - const beforeUpload = (file: FileItem) => {
130   - const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
131   - if (!isJpgOrPng) {
132   - createMessage.error('只能上传图片文件!');
133   - }
134   - const isLt2M = (file.size as number) / 1024 / 1024 < 5;
135   - if (!isLt2M) {
136   - createMessage.error('图片大小不能超过5MB!');
137   - }
138   - return isJpgOrPng && isLt2M;
  95 + const handleChange = (e) => {
  96 + personalPicture.value = e.data;
139 97 };
140 98
141 99 const [registerForm, { validate, resetFields, setFieldsValue }] = useForm({
... ... @@ -146,7 +104,7 @@
146 104 const [registerModal, { closeModal }] = useModalInner(async () => {
147 105 const info = await getMyInfo();
148 106 personalInfo.value = info;
149   - personalPicture.value = info.avatar;
  107 + personalPicture.value = info.avatar || headerImg;
150 108 setFieldsValue(info);
151 109 setDescProps({ data: info });
152 110 });
... ... @@ -157,7 +115,7 @@
157 115 const record = await personalPut({
158 116 ...value,
159 117 id: userInfo.userId,
160   - avatar: unref(personalPicture),
  118 + avatar: personalPicture.value,
161 119 });
162 120
163 121 userStore.setUserInfo(record as unknown as UserInfo);
... ... @@ -171,13 +129,13 @@
171 129 personalInfo,
172 130 registerDesc,
173 131 personalPicture,
174   - beforeUpload,
175   - customUpload,
176 132 handleSubmit,
177 133 registerModal,
178 134 registerForm,
179 135 loading,
180 136 headerImg,
  137 + uploadApi,
  138 + handleChange,
181 139 };
182 140 },
183 141 });
... ...
... ... @@ -55,7 +55,9 @@ export const topicTableColumn: BasicColumn[] = [
55 55 customRender: ({ text }: { text: any }) => {
56 56 return h(
57 57 'span',
  58 +
58 59 {
  60 + style: { cursor: 'pointer' },
59 61 onClick: () => {
60 62 handeleCopy(text);
61 63 },
... ... @@ -73,6 +75,7 @@ export const topicTableColumn: BasicColumn[] = [
73 75 return h(
74 76 'span',
75 77 {
  78 + style: { cursor: 'pointer' },
76 79 onClick: () => {
77 80 handeleCopy(text);
78 81 },
... ... @@ -180,8 +183,8 @@ export const list = [
180 183 {
181 184 deviceType: '网关/直连/网关子设备',
182 185 function: '事件上报',
183   - release: 'v1/devices/event/${deviceId}/${identifier}/{$eventType}',
184   - subscribe: 'v1/devices/event/${deviceId}/${identifier}/{$eventType}',
  186 + release: 'v1/devices/event/${deviceId}/${identifier}',
  187 + subscribe: 'v1/devices/event/${deviceId}/${identifier}',
185 188 platform: '订阅',
186 189 device: '发布',
187 190 },
... ...
... ... @@ -6,52 +6,21 @@
6 6 <template #logoUpload>
7 7 <ContentUploadText>
8 8 <template #uploadImg>
9   - <Upload
10   - name="avatar"
11   - list-type="picture-card"
12   - class="avatar-uploader"
13   - :show-upload-list="false"
14   - @preview="handlePreview"
15   - :customRequest="customUploadLogoPic"
16   - :before-upload="beforeUploadLogoPic"
17   - >
18   - <img v-if="logoPic" class="fill-img" :src="logoPic" alt="avatar" />
19   - <div v-else>
20   - <Spin v-if="loading" tip="正在上传中..." />
21   - <PlusOutlined v-else />
22   - <div class="ant-upload-text">上传</div>
23   - </div>
24   - </Upload>
  9 + <CustomUploadComp :imgUrl="logoPic" @setImg="handleSetLogoImgUrl" />
25 10 </template>
26 11 <template #uploadText>
27   - <div class="box-outline">
28   - 支持.PNG、.JPG格式,建议尺寸为32*32px,大小不超过500KB
29   - </div>
  12 + <div class="box-outline"> 支持.PNG、.JPG格式,建议尺寸为32*32px,大小不超过5M </div>
30 13 </template>
31 14 </ContentUploadText>
32 15 </template>
33 16 <template #bgUpload>
34 17 <ContentUploadText>
35 18 <template #uploadImg>
36   - <Upload
37   - name="avatar"
38   - list-type="picture-card"
39   - class="avatar-uploader"
40   - :show-upload-list="false"
41   - :customRequest="customUploadBgPic"
42   - :before-upload="beforeUploadBgPic"
43   - >
44   - <img v-if="bgPic" class="fill-img" :src="bgPic" alt="avatar" />
45   - <div v-else>
46   - <Spin v-if="loading1" tip="正在上传中..." />
47   - <PlusOutlined v-else />
48   - <div class="ant-upload-text">上传</div>
49   - </div>
50   - </Upload>
  19 + <CustomUploadComp :imgUrl="bgPic" @setImg="handleSetBgImgUrl" />
51 20 </template>
52 21 <template #uploadText>
53 22 <div class="box-outline">
54   - 支持.PNG、.JPG格式,建议尺寸为1920*1080px,大小不超过2M
  23 + 支持.PNG、.JPG格式,建议尺寸为1920*1080px,大小不超过5M
55 24 </div>
56 25 </template>
57 26 </ContentUploadText>
... ... @@ -83,7 +52,7 @@
83 52 </template>
84 53 <template #uploadText>
85 54 <div class="box-outline">
86   - 支持.PNG、.JPG格式,建议尺寸为800*600px,大小不超过3M
  55 + 支持.PNG、.JPG格式,建议尺寸为800*600px,大小不超过5M
87 56 </div>
88 57 </template>
89 58 </ContentUploadText>
... ... @@ -108,15 +77,16 @@
108 77 import { defineComponent, ref, unref, onMounted } from 'vue';
109 78 import { BasicForm, useForm } from '/@/components/Form/index';
110 79 import { Loading } from '/@/components/Loading/index';
111   - import { Card, Upload, Input, Modal, Spin } from 'ant-design-vue';
  80 + import { Card, Upload, Input, Modal } from 'ant-design-vue';
112 81 import { PlusOutlined } from '@ant-design/icons-vue';
113 82 import { schemas } from '../config/AppDraw.config';
114 83 import { FileItem, FileInfo } from '../types/index';
115   - import { logoUpload, bgUpload, resetAppInfo } from '/@/api/oem/index';
  84 + import { bgUpload, resetAppInfo } from '/@/api/oem/index';
116 85 import { useMessage } from '/@/hooks/web/useMessage';
117 86 import { getAppDesign, updateAppDesign } from '/@/api/oem/index';
118 87 import { Authority } from '/@/components/Authority';
119 88 import ContentUploadText from './ContentUploadText.vue';
  89 + import { CustomUploadComp } from './customUplaod/index';
120 90
121 91 export default defineComponent({
122 92 components: {
... ... @@ -129,7 +99,7 @@
129 99 Modal,
130 100 Authority,
131 101 ContentUploadText,
132   - Spin,
  102 + CustomUploadComp,
133 103 },
134 104 setup() {
135 105 const loading = ref(false);
... ... @@ -170,59 +140,20 @@
170 140 previewVisible.value = true;
171 141 };
172 142
  143 + const handleSetBgImgUrl = (d) => {
  144 + bgPic.value = d;
  145 + };
  146 +
  147 + const handleSetLogoImgUrl = (d) => {
  148 + logoPic.value = d;
  149 + };
  150 +
173 151 // logo图片上传
174 152 const logoPic = ref();
175   - async function customUploadLogoPic({ file }) {
176   - if (beforeUploadLogoPic(file)) {
177   - logoPic.value = '';
178   - loading.value = true;
179   - const formData = new FormData();
180   - formData.append('file', file);
181   - const response = await logoUpload(formData);
182   - if (response.fileStaticUri) {
183   - logoPic.value = response.fileStaticUri;
184   - loading.value = false;
185   - }
186   - }
187   - }
188   - const beforeUploadLogoPic = (file) => {
189   - const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
190   - if (!isJpgOrPng) {
191   - createMessage.error('只能上传图片文件!');
192   - }
193   - const isLt2M = (file.size as number) / 1024 < 500;
194   - if (!isLt2M) {
195   - createMessage.error('图片大小不能超过500KB!');
196   - }
197   - return isJpgOrPng && isLt2M;
198   - };
199 153
200 154 // 登录页背景上传
201 155 const bgPic = ref();
202   - async function customUploadBgPic({ file }) {
203   - if (beforeUploadBgPic(file)) {
204   - bgPic.value = '';
205   - loading1.value = true;
206   - const formData = new FormData();
207   - formData.append('file', file);
208   - const response = await bgUpload(formData);
209   - if (response.fileStaticUri) {
210   - bgPic.value = response.fileStaticUri;
211   - loading1.value = false;
212   - }
213   - }
214   - }
215   - const beforeUploadBgPic = (file) => {
216   - const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
217   - if (!isJpgOrPng) {
218   - createMessage.error('只能上传图片文件!');
219   - }
220   - const isLt2M = (file.size as number) / 1024 / 1024 < 2;
221   - if (!isLt2M) {
222   - createMessage.error('图片大小不能超过2MB!');
223   - }
224   - return isJpgOrPng && isLt2M;
225   - };
  156 +
226 157 // 首页轮播图
227 158 const fileList = ref<FileItem[]>([]);
228 159 async function customUploadHomeSwiper({ file }) {
... ... @@ -337,10 +268,6 @@
337 268 handleUpdateInfo,
338 269 handleCancel,
339 270 handlePreview,
340   - customUploadLogoPic,
341   - beforeUploadLogoPic,
342   - customUploadBgPic,
343   - beforeUploadBgPic,
344 271 customUploadHomeSwiper,
345 272 beforeUploadHomeSwiper,
346 273 handleChange,
... ... @@ -351,6 +278,8 @@
351 278 loading,
352 279 loading1,
353 280 handleResetInfo,
  281 + handleSetBgImgUrl,
  282 + handleSetLogoImgUrl,
354 283 };
355 284 },
356 285 });
... ... @@ -371,9 +300,4 @@
371 300 border: 1px dashed #d9d9d9;
372 301 text-align: left;
373 302 }
374   -
375   - .fill-img {
376   - width: 100%;
377   - height: 100%;
378   - }
379 303 </style>
... ...
... ... @@ -6,26 +6,10 @@
6 6 <template #logoUpload>
7 7 <ContentUploadText>
8 8 <template #uploadImg>
9   - <Upload
10   - name="avatar"
11   - list-type="picture-card"
12   - class="avatar-uploader"
13   - :show-upload-list="false"
14   - :customRequest="customUploadLogoPic"
15   - :before-upload="beforeUploadLogoPic"
16   - >
17   - <img class="fill-img" v-if="logoPic" :src="logoPic" alt="avatar" />
18   - <div v-else>
19   - <Spin v-if="loading" tip="正在上传中..." />
20   - <PlusOutlined v-else />
21   - <div class="ant-upload-text">上传</div>
22   - </div>
23   - </Upload>
  9 + <CustomUploadComp :imgUrl="logoPic" @setImg="handleSetLogoImgUrl" />
24 10 </template>
25 11 <template #uploadText>
26   - <div class="box-outline">
27   - 支持.PNG、.JPG格式,建议尺寸为32*32px,大小不超过500KB
28   - </div>
  12 + <div class="box-outline"> 支持.PNG、.JPG格式,建议尺寸为32*32px,大小不超过5M </div>
29 13 </template>
30 14 </ContentUploadText>
31 15 </template>
... ... @@ -61,23 +45,7 @@
61 45 <template #bgUpload>
62 46 <ContentUploadText>
63 47 <template #uploadImg>
64   - <Upload
65   - name="avatar"
66   - list-type="picture-card"
67   - class="avatar-uploader"
68   - :show-upload-list="false"
69   - :customRequest="customUploadBgPic"
70   - :before-upload="beforeUploadBgPic"
71   - >
72   - <img class="fill-img" v-if="bgPic" :src="bgPic" alt="avatar" />
73   - <div v-else>
74   - <div>
75   - <Spin v-if="loading2" tip="正在上传中..." />
76   - <PlusOutlined v-else />
77   - <div class="ant-upload-text">上传</div>
78   - </div>
79   - </div></Upload
80   - >
  48 + <CustomUploadComp :imgUrl="bgPic" @setImg="handleSetBgImgUrl" />
81 49 </template>
82 50 <template #uploadText>
83 51 <div class="box-outline">
... ... @@ -112,19 +80,13 @@
112 80 import { Loading } from '/@/components/Loading/index';
113 81 import { useMessage } from '/@/hooks/web/useMessage';
114 82 import type { FileItem } from '/@/components/Upload/src/typing';
115   - import {
116   - logoUpload,
117   - iconUpload,
118   - bgUpload,
119   - getPlatForm,
120   - updatePlatForm,
121   - resetPlateInfo,
122   - } from '/@/api/oem/index';
  83 + import { iconUpload, getPlatForm, updatePlatForm, resetPlateInfo } from '/@/api/oem/index';
123 84 import { PlusOutlined } from '@ant-design/icons-vue';
124 85 import { useUserStore } from '/@/store/modules/user';
125 86 import { createLocalStorage } from '/@/utils/cache/index';
126 87 import { Authority } from '/@/components/Authority';
127 88 import ContentUploadText from './ContentUploadText.vue';
  89 + import { CustomUploadComp } from './customUplaod/index';
128 90
129 91 export default defineComponent({
130 92 components: {
... ... @@ -137,6 +99,7 @@
137 99 Authority,
138 100 ContentUploadText,
139 101 Spin,
  102 + CustomUploadComp,
140 103 },
141 104 setup() {
142 105 const loading = ref(false);
... ... @@ -163,30 +126,13 @@
163 126 const logoPic = ref();
164 127 const iconPic = ref();
165 128 const bgPic = ref();
166   - // logo图片上传
167   - async function customUploadLogoPic({ file }) {
168   - if (beforeUploadLogoPic(file)) {
169   - logoPic.value = '';
170   - loading.value = true;
171   - const formData = new FormData();
172   - formData.append('file', file);
173   - const response = await logoUpload(formData);
174   - if (response.fileStaticUri) {
175   - logoPic.value = response.fileStaticUri;
176   - loading.value = false;
177   - }
178   - }
179   - }
180   - const beforeUploadLogoPic = (file: FileItem) => {
181   - const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
182   - if (!isJpgOrPng) {
183   - createMessage.error('只能上传图片文件!');
184   - }
185   - const isLt2M = (file.size as number) / 1024 < 500;
186   - if (!isLt2M) {
187   - createMessage.error('图片大小不能超过500KB!');
188   - }
189   - return isJpgOrPng && isLt2M;
  129 +
  130 + const handleSetBgImgUrl = (d) => {
  131 + bgPic.value = d;
  132 + };
  133 +
  134 + const handleSetLogoImgUrl = (d) => {
  135 + logoPic.value = d;
190 136 };
191 137 // Icon上传
192 138 async function customUploadIconPic({ file }) {
... ... @@ -213,32 +159,6 @@
213 159 }
214 160 return isJpgOrPng && isLt2M;
215 161 };
216   - // 登录页背景上传
217   - async function customUploadBgPic({ file }) {
218   - if (beforeUploadBgPic(file)) {
219   - bgPic.value = '';
220   - loading2.value = true;
221   - const formData = new FormData();
222   - formData.append('file', file);
223   - const response = await bgUpload(formData);
224   - if (response.fileStaticUri) {
225   - bgPic.value = response.fileStaticUri;
226   - loading2.value = false;
227   - }
228   - }
229   - }
230   - const beforeUploadBgPic = (file: FileItem) => {
231   - const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
232   - if (!isJpgOrPng) {
233   - createMessage.error('只能上传图片文件!');
234   - }
235   - const isLt2M = (file.size as number) / 1024 / 1024 < 5;
236   - if (!isLt2M) {
237   - createMessage.error('图片大小不能超过5MB!');
238   - }
239   - return isJpgOrPng && isLt2M;
240   - };
241   -
242 162 // 更新
243 163 const handleUpdateInfo = async () => {
244 164 try {
... ... @@ -296,18 +216,16 @@
296 216 logoPic,
297 217 iconPic,
298 218 bgPic,
299   - customUploadLogoPic,
300   - beforeUploadLogoPic,
301 219 customUploadIconPic,
302 220 beforeUploadIconPic,
303   - customUploadBgPic,
304   - beforeUploadBgPic,
305 221 compState,
306 222 handleUpdateInfo,
307 223 loading,
308 224 loading1,
309 225 loading2,
310 226 handleResetInfo,
  227 + handleSetBgImgUrl,
  228 + handleSetLogoImgUrl,
311 229 };
312 230 },
313 231 });
... ...
... ... @@ -5,21 +5,7 @@
5 5 <template #qrcode>
6 6 <ContentUploadText>
7 7 <template #uploadImg>
8   - <Upload
9   - name="avatar"
10   - list-type="picture-card"
11   - class="avatar-uploader"
12   - :show-upload-list="false"
13   - :customRequest="customUploadqrcodePic"
14   - :before-upload="beforeUploadqrcodePic"
15   - >
16   - <img class="fill-img" v-if="qrcodePic" :src="qrcodePic" alt="avatar" />
17   - <div v-else>
18   - <Spin v-if="loading" tip="正在上传中..." />
19   - <PlusOutlined v-else />
20   - <div class="ant-upload-text">上传</div>
21   - </div></Upload
22   - >
  8 + <CustomUploadComp :imgUrl="qrcodePic" @setImg="handleSetCodeImgUrl" />
23 9 </template>
24 10 <template #uploadText>
25 11 <div class="box-outline"> 支持.PNG、.JPG格式,建议尺寸为300*300px,大小不超过5M </div>
... ... @@ -46,7 +32,7 @@
46 32
47 33 <script lang="ts">
48 34 import { defineComponent, onMounted, ref, computed } from 'vue';
49   - import { Card, Upload, Spin } from 'ant-design-vue';
  35 + import { Card } from 'ant-design-vue';
50 36 import { BasicForm, useForm } from '/@/components/Form/index';
51 37 import { schemas, provSchemas } from '../config/enterPriseInfo.config';
52 38 import { getAreaList, getEnterPriseDetail, updateEnterPriseDetail } from '/@/api/oem/index';
... ... @@ -54,25 +40,21 @@
54 40 import { useMessage } from '/@/hooks/web/useMessage';
55 41 import { useUserStore } from '/@/store/modules/user';
56 42 import { createLocalStorage } from '/@/utils/cache';
57   - import { PlusOutlined } from '@ant-design/icons-vue';
58   - import { qrcodeUpload } from '/@/api/oem/index';
59   - import type { FileItem } from '/@/components/Upload/src/typing';
60 43 import type { CityItem, Code } from '../types';
61 44 import { Authority } from '/@/components/Authority';
62 45 import { USER_INFO_KEY } from '/@/enums/cacheEnum';
63 46 import { getAuthCache } from '/@/utils/auth';
64 47 import ContentUploadText from './ContentUploadText.vue';
  48 + import { CustomUploadComp } from './customUplaod/index';
65 49
66 50 export default defineComponent({
67 51 components: {
68 52 Card,
69 53 BasicForm,
70 54 Loading,
71   - Upload,
72   - PlusOutlined,
73 55 Authority,
74 56 ContentUploadText,
75   - Spin,
  57 + CustomUploadComp,
76 58 },
77 59 setup() {
78 60 const userInfo: any = getAuthCache(USER_INFO_KEY);
... ... @@ -119,30 +101,8 @@
119 101 const { createMessage } = useMessage();
120 102
121 103 const qrcodePic = ref();
122   - const customUploadqrcodePic = async ({ file }) => {
123   - clearValidate('qrcode');
124   - if (beforeUploadqrcodePic(file)) {
125   - qrcodePic.value = '';
126   - loading.value = true;
127   - const formData = new FormData();
128   - formData.append('file', file);
129   - const response = await qrcodeUpload(formData);
130   - if (response.fileStaticUri) {
131   - qrcodePic.value = response.fileStaticUri;
132   - loading.value = false;
133   - }
134   - }
135   - };
136   - const beforeUploadqrcodePic = (file: FileItem) => {
137   - const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
138   - if (!isJpgOrPng) {
139   - createMessage.error('只能上传图片文件!');
140   - }
141   - const isLt2M = (file.size as number) / 1024 / 1024 < 5;
142   - if (!isLt2M) {
143   - createMessage.error('图片大小不能超过5MB!');
144   - }
145   - return isJpgOrPng && isLt2M;
  104 + const handleSetCodeImgUrl = (d) => {
  105 + qrcodePic.value = d;
146 106 };
147 107 // 更新
148 108 const handleUpdateInfo = async () => {
... ... @@ -372,11 +332,10 @@
372 332 compState,
373 333 qrcodePic,
374 334 handleUpdateInfo,
375   - customUploadqrcodePic,
376   - beforeUploadqrcodePic,
377 335 registerCustomForm,
378 336 loading,
379 337 isWhereAdmin,
  338 + handleSetCodeImgUrl,
380 339 };
381 340 },
382 341 });
... ...
  1 +<script setup name="CustomUploadComp" lang="ts">
  2 + import { PlusOutlined } from '@ant-design/icons-vue';
  3 + import { Upload, Spin } from 'ant-design-vue';
  4 + import { ref, watchEffect } from 'vue';
  5 + import { useUpload } from './hooks/useUploadFile.hook';
  6 + import { logoUpload } from '/@/api/oem';
  7 +
  8 + const props = withDefaults(
  9 + defineProps<{
  10 + imgUrl: string;
  11 + }>(),
  12 + {
  13 + imgUrl: '',
  14 + }
  15 + );
  16 + const emit = defineEmits(['setImg']);
  17 +
  18 + const { beforeUploadVerify } = useUpload();
  19 +
  20 + const uploadLoading = ref(false);
  21 +
  22 + const uploadImgUrl = ref('');
  23 +
  24 + //上传图片接口
  25 + const customUpload = async ({ file }) => {
  26 + try {
  27 + if (beforeUploadVerify(file)) {
  28 + uploadImgUrl.value = '';
  29 + uploadLoading.value = true;
  30 + const formData = new FormData();
  31 + formData.append('file', file);
  32 + const response = await logoUpload(formData);
  33 + if (response.fileStaticUri) {
  34 + uploadImgUrl.value = response.fileStaticUri;
  35 + emit('setImg', uploadImgUrl.value);
  36 + }
  37 + }
  38 + } finally {
  39 + uploadLoading.value = false;
  40 + }
  41 + };
  42 +
  43 + watchEffect(() => {
  44 + init();
  45 + });
  46 + function init() {
  47 + if (!props.imgUrl) uploadImgUrl.value = '';
  48 + uploadImgUrl.value = props.imgUrl;
  49 + }
  50 +</script>
  51 +
  52 +<template>
  53 + <div>
  54 + <Upload
  55 + name="avatar"
  56 + list-type="picture-card"
  57 + class="avatar-uploader"
  58 + :show-upload-list="false"
  59 + :customRequest="customUpload"
  60 + :before-upload="beforeUploadVerify"
  61 + >
  62 + <img v-if="uploadImgUrl" class="fill-img" :src="uploadImgUrl" alt="avatar" />
  63 + <div v-else>
  64 + <Spin v-if="uploadLoading" tip="正在上传中..." />
  65 + <PlusOutlined v-else />
  66 + <div class="ant-upload-text">上传</div>
  67 + </div>
  68 + </Upload>
  69 + </div>
  70 +</template>
  71 +
  72 +<style lang="less" scoped>
  73 + .fill-img {
  74 + width: 100%;
  75 + height: 100%;
  76 + }
  77 +</style>
... ...
  1 +import { useMessage } from '/@/hooks/web/useMessage';
  2 +
  3 +const { createMessage } = useMessage();
  4 +
  5 +export const useUpload = () => {
  6 + //验证图片类型和大小
  7 + const beforeUploadVerify = ({ type, size }) => {
  8 + const isJpgOrPng = type === 'image/jpeg' || type === 'image/png';
  9 + if (!isJpgOrPng) {
  10 + createMessage.error('只能上传图片文件!');
  11 + }
  12 + const limitImgSize = (size as number) / 1024 / 1024 < 5;
  13 + if (!limitImgSize) {
  14 + createMessage.error('图片大小不能超过5MB!');
  15 + }
  16 + return isJpgOrPng && limitImgSize;
  17 + };
  18 + return {
  19 + beforeUploadVerify,
  20 + };
  21 +};
... ...
  1 +import CustomUploadComp from './CustomUploadComp.vue';
  2 +export { CustomUploadComp };
... ...