Huanyi 2 тижнів тому
батько
коміт
23428636d5

+ 56 - 3
src/components/ImageUpload/index.vue

@@ -21,6 +21,25 @@
       <el-icon class="avatar-uploader-icon">
         <plus />
       </el-icon>
+      <template #file="{ file }">
+        <div class="upload-file-content">
+          <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
+          <span class="el-upload-list__item-actions">
+            <!-- 预览图标 -->
+            <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
+              <el-icon><zoom-in /></el-icon>
+            </span>
+            <!-- 替换图标 (canDelete 为 false 时展示) -->
+            <span v-if="!canDelete" class="el-upload-list__item-delete" @click="handleReplace(file)">
+              <el-icon><refresh /></el-icon>
+            </span>
+            <!-- 删除图标 (canDelete 为 true 时展示) -->
+            <span v-if="canDelete" class="el-upload-list__item-delete" @click="handleDelete(file)">
+              <el-icon><delete /></el-icon>
+            </span>
+          </span>
+        </div>
+      </template>
     </el-upload>
     <!-- 上传提示 -->
     <div v-if="showTip" class="el-upload__tip">
@@ -69,7 +88,12 @@ const props = defineProps({
     default: false
   },
   // 压缩目标大小,单位KB。默认300KB以上文件才压缩,并压缩至300KB以内
-  compressTargetSize: propTypes.number.def(300)
+  compressTargetSize: propTypes.number.def(300),
+  // 是否允许删除
+  canDelete: {
+    type: Boolean,
+    default: true
+  }
 });
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -186,11 +210,14 @@ const handleUploadSuccess = (res: any, file: UploadFile) => {
 };
 
 // 删除图片
-const handleDelete = (file: UploadFile): boolean => {
+const handleDelete = (file: any, isRequest = true): boolean => {
   const findex = fileList.value.map((f) => f.name).indexOf(file.name);
   if (findex > -1 && uploadList.value.length === number.value) {
     const ossId = fileList.value[findex].ossId;
-    delOss(ossId);
+    // 如果有 ossId 则逻辑上删除(实际调用后端接口删除物理文件取决于后端实现或需求)
+    if (ossId && isRequest) {
+      delOss(ossId);
+    }
     fileList.value.splice(findex, 1);
     emit('update:modelValue', listToString(fileList.value));
     return false;
@@ -198,6 +225,19 @@ const handleDelete = (file: UploadFile): boolean => {
   return true;
 };
 
+/** 替换图片 */
+const handleReplace = (file: any) => {
+  // 先执行删除图片的逻辑,清空当前图片,但不发起请求
+  handleDelete(file, false);
+  // 等待 DOM 更新后触发上传点击事件
+  nextTick(() => {
+    const input = imageUploadRef.value?.$el.querySelector('input');
+    if (input) {
+      input.click();
+    }
+  });
+};
+
 // 上传结束处理
 const uploadedSuccessfully = () => {
   if (number.value > 0 && uploadList.value.length === number.value) {
@@ -239,4 +279,17 @@ const listToString = (list: any[], separator?: string) => {
 :deep(.hide .el-upload--picture-card) {
   display: none;
 }
+
+.upload-file-content {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+
+  .el-upload-list__item-thumbnail {
+    object-fit: contain;
+  }
+}
 </style>

+ 37 - 43
src/views/login.vue

@@ -1,66 +1,58 @@
 <template>
-    <div class="login" :style="{ backgroundImage: 'url(' + (websiteSetting.loginBackgroundUrl || defaultBg) + ')' }">
+  <div class="login" :style="{ backgroundImage: 'url(' + (websiteSetting.loginBackgroundUrl || defaultBg) + ')' }">
     <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
       <div class="title-box">
         <h3 class="title">{{ websiteSetting.loginTitle }}</h3>
         <lang-select />
       </div>
       <el-form-item v-if="tenantEnabled" prop="tenantId">
-        <el-select v-model="loginForm.tenantId" filterable :placeholder="proxy.$t('login.selectPlaceholder')" style="width: 100%">
-          <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option>
+        <el-select v-model="loginForm.tenantId" filterable :placeholder="proxy.$t('login.selectPlaceholder')"
+          style="width: 100%">
+          <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName"
+            :value="item.tenantId"></el-option>
           <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
         </el-select>
       </el-form-item>
       <el-form-item prop="username">
-        <el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" :placeholder="proxy.$t('login.username')">
+        <el-input v-model="loginForm.username" type="text" size="large" auto-complete="off"
+          :placeholder="proxy.$t('login.username')">
           <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
         </el-input>
       </el-form-item>
       <el-form-item prop="password">
-        <el-input
-          v-model="loginForm.password"
-          type="password"
-          size="large"
-          auto-complete="off"
-          :placeholder="proxy.$t('login.password')"
-          @keyup.enter="handleLogin"
-        >
+        <el-input v-model="loginForm.password" type="password" size="large" auto-complete="off"
+          :placeholder="proxy.$t('login.password')" @keyup.enter="handleLogin">
           <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
         </el-input>
       </el-form-item>
       <el-form-item v-if="captchaEnabled" prop="code">
-        <el-input
-          v-model="loginForm.code"
-          size="large"
-          auto-complete="off"
-          :placeholder="proxy.$t('login.code')"
-          style="width: 63%"
-          @keyup.enter="handleLogin"
-        >
+        <el-input v-model="loginForm.code" size="large" auto-complete="off" :placeholder="proxy.$t('login.code')"
+          style="width: 63%" @keyup.enter="handleLogin">
           <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
         </el-input>
         <div class="login-code">
           <img :src="codeUrl" class="login-code-img" @click="getCode" />
         </div>
       </el-form-item>
-      <el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">{{ proxy.$t('login.rememberPassword') }}</el-checkbox>
-<!--      <el-form-item style="float: right">-->
-<!--        <el-button circle :title="proxy.$t('login.social.wechat')" @click="doSocialLogin('wechat')">-->
-<!--          <svg-icon icon-class="wechat" />-->
-<!--        </el-button>-->
-<!--        <el-button circle :title="proxy.$t('login.social.maxkey')" @click="doSocialLogin('maxkey')">-->
-<!--          <svg-icon icon-class="maxkey" />-->
-<!--        </el-button>-->
-<!--        <el-button circle :title="proxy.$t('login.social.topiam')" @click="doSocialLogin('topiam')">-->
-<!--          <svg-icon icon-class="topiam" />-->
-<!--        </el-button>-->
-<!--        <el-button circle :title="proxy.$t('login.social.gitee')" @click="doSocialLogin('gitee')">-->
-<!--          <svg-icon icon-class="gitee" />-->
-<!--        </el-button>-->
-<!--        <el-button circle :title="proxy.$t('login.social.github')" @click="doSocialLogin('github')">-->
-<!--          <svg-icon icon-class="github" />-->
-<!--        </el-button>-->
-<!--      </el-form-item>-->
+      <el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">{{ proxy.$t('login.rememberPassword')
+        }}</el-checkbox>
+      <!--      <el-form-item style="float: right">-->
+      <!--        <el-button circle :title="proxy.$t('login.social.wechat')" @click="doSocialLogin('wechat')">-->
+      <!--          <svg-icon icon-class="wechat" />-->
+      <!--        </el-button>-->
+      <!--        <el-button circle :title="proxy.$t('login.social.maxkey')" @click="doSocialLogin('maxkey')">-->
+      <!--          <svg-icon icon-class="maxkey" />-->
+      <!--        </el-button>-->
+      <!--        <el-button circle :title="proxy.$t('login.social.topiam')" @click="doSocialLogin('topiam')">-->
+      <!--          <svg-icon icon-class="topiam" />-->
+      <!--        </el-button>-->
+      <!--        <el-button circle :title="proxy.$t('login.social.gitee')" @click="doSocialLogin('gitee')">-->
+      <!--          <svg-icon icon-class="gitee" />-->
+      <!--        </el-button>-->
+      <!--        <el-button circle :title="proxy.$t('login.social.github')" @click="doSocialLogin('github')">-->
+      <!--          <svg-icon icon-class="github" />-->
+      <!--        </el-button>-->
+      <!--      </el-form-item>-->
       <el-form-item style="width: 100%">
         <el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin">
           <span v-if="!loading">{{ proxy.$t('login.login') }}</span>
@@ -72,9 +64,9 @@
       </el-form-item>
     </el-form>
     <!--  底部  -->
-<!--    <div class="el-login-footer">-->
-<!--      <span>Copyright © 2018-2026 疯狂的狮子Li All Rights Reserved.</span>-->
-<!--    </div>-->
+    <!--    <div class="el-login-footer">-->
+    <!--      <span>Copyright © 2018-2026 疯狂的狮子Li All Rights Reserved.</span>-->
+    <!--    </div>-->
   </div>
 </template>
 
@@ -102,8 +94,8 @@ const { t } = useI18n();
 const loginForm = ref<LoginData>({
   platformId: 0,
   tenantId: '000000',
-  username: 'admin',
-  password: 'admin123',
+  username: '',
+  password: '',
   rememberMe: false,
   code: '',
   uuid: ''
@@ -271,8 +263,10 @@ onMounted(() => {
   width: 400px;
   padding: 25px 25px 5px 25px;
   z-index: 1;
+
   .el-input {
     height: 40px;
+
     input {
       height: 40px;
     }

+ 2 - 2
src/views/systemConfig/app/index.vue

@@ -17,13 +17,13 @@
       <el-form ref="appFormRef" :model="form" :rules="rules" label-width="160px" label-position="right" class="premium-setting-form">
         <!-- 登录图标 -->
         <el-form-item label="登录页图标:" prop="loginIcon">
-          <image-upload v-model="form.loginIcon" :limit="1" />
+          <image-upload v-model="form.loginIcon" :limit="1" :can-delete="false" />
           <div class="form-tip">建议尺寸:200x200,支持 png/jpg 格式</div>
         </el-form-item>
 
         <!-- 登录页背景图 -->
         <el-form-item label="登录页背景:" prop="loginBackground">
-          <image-upload v-model="form.loginBackground" :limit="1" />
+          <image-upload v-model="form.loginBackground" :limit="1" :can-delete="false" />
           <div class="form-tip">建议尺寸:1080x1920(9:16),支持 jpg/png 格式</div>
         </el-form-item>
 

+ 1 - 1
src/views/systemConfig/platform/components/CustomerConfig.vue

@@ -39,7 +39,7 @@
       </el-form-item>
 
       <el-form-item label="客服二维码:" prop="qrCode">
-        <image-upload v-model="form.qrCode" :limit="1" />
+        <image-upload v-model="form.qrCode" :limit="1" :can-delete="false" />
         <div class="form-tip">支持 jpg/png 格式</div>
       </el-form-item>
 

+ 2 - 2
src/views/systemConfig/website/index.vue

@@ -42,13 +42,13 @@
 
         <!-- 网站图标 -->
         <el-form-item label="网站图标:" prop="icon">
-          <image-upload v-model="form.icon" :limit="1" />
+          <image-upload v-model="form.icon" :limit="1" :can-delete="false" />
           <div class="form-tip">建议尺寸:32x32,支持 png/ico 格式</div>
         </el-form-item>
 
         <!-- 登录背景图 -->
         <el-form-item label="登录页背景:" prop="loginBackground">
-          <image-upload v-model="form.loginBackground" :limit="1" />
+          <image-upload v-model="form.loginBackground" :limit="1" :can-delete="false" />
           <div class="form-tip">建议尺寸:1920x1080,支持 jpg/png 格式</div>
         </el-form-item>