2026-08-06 b5610241bf38760ef678d9d813b23e858c76aa43
Merge remote-tracking branch 'origin/dev_pro2.0' into dev_pro2.0

# Conflicts:
# src/views/ai/chat/index/modules/message/list-empty.vue
# src/views/im/home/index.vue
已修改9个文件
212 ■■■■ 文件已修改
internal/vite-config/src/config/application.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/form-create/components/use-api-select.tsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/upload/file-upload.vue 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/packages/@core/base/shared/src/constants/vben.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/packages/effects/common-ui/src/ui/authentication/doc-link.vue 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/packages/effects/layouts/src/widgets/help/help.vue 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/preferences.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/ai/chat/index/modules/message/list-empty.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/bpm/processInstance/detail/modules/operation-button.vue 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
internal/vite-config/src/config/application.ts
@@ -44,7 +44,7 @@
      nitroMockOptions: {},
      print: !isBuild,
      printInfoMap: {
        Docs: 'https://doc.iocoder.cn/quick-start/',
        Docs: '#',
      },
      pwa: true,
      pwaOptions: getDefaultPwaOptions(appTitle),
src/components/form-create/components/use-api-select.tsx
@@ -161,9 +161,9 @@
          parseOptions0(data);
          return;
        }
        // 情况三:不是 yudao-vue-pro 标准返回
        // 情况三:不是标准返回
        console.warn(
          `接口[${props.url}] 返回结果不是 yudao-vue-pro 标准返回建议采用自定义解析函数处理`,
          `接口[${props.url}] 返回结果不是标准返回建议采用自定义解析函数处理`,
        );
      }
src/components/upload/file-upload.vue
@@ -10,9 +10,12 @@
import { IconifyIcon } from '@vben/icons';
import { $t } from '@vben/locales';
import { checkFileType, isFunction, isObject, isString } from '@vben/utils';
import { checkFileType, isFunction, isImage, isObject, isString } from '@vben/utils';
import { Button, message, Upload } from 'ant-design-vue';
import { requestClient } from '#/api/request';
import { FilePreviewModal, useFilePreview } from '#/components/file-preview';
import { UploadResultStatus } from './typing';
import { useUpload, useUploadType } from './use-upload';
@@ -139,9 +142,30 @@
  }
}
const { openPreview, previewState } = useFilePreview();
/** 处理文件预览 */
function handlePreview(file: UploadFile) {
async function handlePreview(file: UploadFile) {
  const url = (file as any)?.url || (file as any)?.response?.url || (file as any)?.response;
  if (!url) {
    message.warning('文件地址不存在,无法预览');
    return;
  }
  const name = file.name || (file as any)?.fileName || '';
  if (isImage(name || url)) {
    window.open(url, '_blank');
    return;
  }
  try {
    // 将绝对 URL 转为相对路径,走 Vite 代理避免跨域
    const path = typeof url === 'string' ? url.replace(/^https?:\/\/[^/]+/, '') : url;
    const blob = await requestClient.download(path);
    const blobUrl = URL.createObjectURL(blob as Blob);
    openPreview(blobUrl, name);
  emit('preview', file);
  } catch {
    message.error('文件加载失败');
  }
}
/** 处理文件数量超限 */
@@ -319,6 +343,11 @@
        格式文件
      </div>
    </Upload>
    <FilePreviewModal
      v-model:visible="previewState.visible.value"
      :file-url="previewState.fileUrl.value"
      :file-name="previewState.fileName.value"
    />
  </div>
</template>
src/packages/@core/base/shared/src/constants/vben.ts
@@ -2,14 +2,13 @@
 * @zh_CN GITHUB 仓库地址
 */
// export const VBEN_GITHUB_URL = 'https://github.com/vbenjs/vue-vben-admin';
export const VBEN_GITHUB_URL =
  'https://github.com/yudaocode/yudao-ui-admin-vben';
export const VBEN_GITHUB_URL = '#';
/**
 * @zh_CN 文档地址
 */
// export const VBEN_DOC_URL = 'https://doc.vben.pro';
export const VBEN_DOC_URL = 'https://doc.iocoder.cn/';
export const VBEN_DOC_URL = '#';
/**
 * @zh_CN Vben Logo
src/packages/effects/common-ui/src/ui/authentication/doc-link.vue
@@ -5,44 +5,5 @@
</script>
<template>
  <div class="w-full sm:mx-auto md:max-w-md">
    <div class="mt-4 flex items-center justify-between">
      <span class="border-input w-[35%] border-b dark:border-gray-600"></span>
      <span class="text-muted-foreground text-center text-xs uppercase">
        萌新必读
      </span>
      <span class="border-input w-[35%] border-b dark:border-gray-600"></span>
    </div>
    <div class="mt-4 flex w-full justify-between">
      <a
        href="https://doc.iocoder.cn/"
        target="_blank"
        class="text-primary hover:text-primary/80 text-sm"
      >
        📚 开发指南
      </a>
      <a
        href="https://doc.iocoder.cn/video/"
        target="_blank"
        class="text-primary hover:text-primary/80 text-sm"
      >
        🔥 视频教程
      </a>
      <a
        href="https://www.iocoder.cn/Interview/good-collection/"
        target="_blank"
        class="text-primary hover:text-primary/80 text-sm"
      >
        ⚡ 面试手册
      </a>
      <a
        href="http://static.yudao.iocoder.cn/mp/xinyu370.jpeg"
        target="_blank"
        class="text-primary hover:text-primary/80 text-sm"
      >
        🤝 外包咨询
      </a>
    </div>
  </div>
  <div class="w-full sm:mx-auto md:max-w-md" />
</template>
src/packages/effects/layouts/src/widgets/help/help.vue
@@ -3,7 +3,7 @@
import { openWindow } from '../../../../../utils/src';
import { useVbenModal } from '../../../../../@core/ui-kit/popup-ui/src';
import { Badge, VbenButton, VbenButtonGroup } from '../../../../../@core/ui-kit/shadcn-ui/src';
import { VbenButton, VbenButtonGroup } from '../../../../../@core/ui-kit/shadcn-ui/src';
import { useMagicKeys, whenever } from '@vueuse/core';
@@ -30,77 +30,12 @@
    <div class="mt-2 flex flex-col">
      <div class="mt-2 flex flex-col">
        <VbenButtonGroup class="basis-1/3" :gap="2" border size="large">
          <p class="w-24 p-2">项目地址:</p>
          <VbenButton
            variant="link"
            @click="
              openWindow('https://gitee.com/yudaocode/yudao-ui-admin-vben')
            "
          >
            Gitee
          </VbenButton>
          <VbenButton
            variant="link"
            @click="
              openWindow('https://github.com/yudaocode/yudao-ui-admin-vben')
            "
          >
            Github
          </VbenButton>
        </VbenButtonGroup>
        <VbenButtonGroup class="basis-1/3" :gap="2" border size="large">
          <p class="w-24 p-2">issues:</p>
          <VbenButton
            variant="link"
            @click="
              openWindow(
                'https://gitee.com/yudaocode/yudao-ui-admin-vben/issues',
              )
            "
          >
            Gitee
          </VbenButton>
          <VbenButton
            variant="link"
            @click="
              openWindow(
                'https://github.com/yudaocode/yudao-ui-admin-vben/issues',
              )
            "
          >
            Github
          </VbenButton>
        </VbenButtonGroup>
        <VbenButtonGroup class="basis-1/3" :gap="2" border size="large">
          <p class="w-24 p-2">开发文档:</p>
          <VbenButton
            variant="link"
            @click="openWindow('https://doc.iocoder.cn/quick-start/')"
          >
            项目文档
          </VbenButton>
          <VbenButton variant="link" @click="openWindow('https://antdv.com/')">
            antdv 文档
          </VbenButton>
        </VbenButtonGroup>
      </div>
      <div class="mt-2 flex justify-start">
        <p class="w-24 p-2">软件外包:</p>
        <img
          src="/wx-xingyu.png"
          alt="数舵科技"
          class="cursor-pointer"
          width="80%"
          @click="openWindow('https://shuduokeji.com')"
        />
      </div>
      <p class="mt-2 flex justify-center pt-4 text-sm italic">
        本项目采用 <Badge class="mx-2" variant="destructive">MIT</Badge>
        开源协议,个人与企业可100% 免费使用
      </p>
    </div>
  </Modal>
</template>
src/preferences.ts
@@ -32,7 +32,7 @@
  },
  copyright: {
    companyName: import.meta.env.VITE_APP_TITLE,
    companySiteLink: 'https://gitee.com/yudaocode/yudao-ui-admin-vben',
    companySiteLink: '#',
  },
  logo: {
    source: __APP_LOGO__ || undefined,
src/views/ai/chat/index/modules/message/list-empty.vue
@@ -20,7 +20,7 @@
  <div class="relative flex h-full w-full flex-row justify-center">
    <div class="flex flex-col justify-center">
      <!-- title -->
      <div class="text-center text-3xl font-bold">超级管理员 AI</div>
      <div class="text-center text-3xl font-bold">AI 助手</div>
      <!-- role-list -->
      <div class="mt-5 flex w-96 flex-wrap items-center justify-center">
        <div
src/views/bpm/processInstance/detail/modules/operation-button.vue
@@ -23,8 +23,6 @@
import { useUserStore } from '@vben/stores';
import { isEmpty } from '@vben/utils';
import { FilePreviewModal, useFilePreview } from '#/components/file-preview';
import FormCreate from '@form-create/ant-design-vue';
import { until, useDebounceFn } from '@vueuse/core';
import {
@@ -787,38 +785,6 @@
  approveFormRef.value?.validateFields(['signPicUrl']);
}
/** 附件图片预览 */
const imagePreviewVisible = ref(false);
const imagePreviewUrl = ref('');
const { openPreview: openFilePreview, previewState: filePreviewState } = useFilePreview();
/** 判断文件是否为图片类型 */
function isImageUrl(url: string) {
  return /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(
    url.split(/[?#]/)[0] || '',
  );
}
/** 处理文件预览 */
function handleFilePreview(file: any) {
  if (!file?.url && !file?.response) {
    message.warning('文件地址不存在,无法预览');
    return;
  }
  const url = file.url || file?.response?.url || file?.response;
  if (!url) {
    message.warning('文件地址不存在,无法预览');
    return;
  }
  if (isImageUrl(url)) {
    imagePreviewUrl.value = url;
    imagePreviewVisible.value = true;
  } else {
    openFilePreview(url, file?.name);
  }
}
/** 处理弹窗可见性 */
function handlePopoverVisible(visible: boolean) {
  if (!visible) {
@@ -926,7 +892,6 @@
                  :show-description="true"
                  :show-download-icon="false"
                  help-text="支持多文件/图片上传"
                  @preview="handleFilePreview"
                />
              </FormItem>
              <FormItem>
@@ -996,7 +961,6 @@
                  :multiple="true"
                  :show-description="true"
                  help-text="支持多文件/图片上传"
                  @preview="handleFilePreview"
                />
              </FormItem>
              <FormItem>
@@ -1543,24 +1507,4 @@
  <!-- 签名弹窗 -->
  <SignatureModal @success="handleSignFinish" />
  <!-- 图片预览(隐藏的 Image 组件,仅用于附件预览弹窗) -->
  <div style="display: none">
    <Image
      :preview="{
        visible: imagePreviewVisible,
        onVisibleChange: (visible: boolean) => {
          imagePreviewVisible = visible;
        },
      }"
      :src="imagePreviewUrl"
    />
  </div>
  <!-- 文件预览(PDF/Word/Excel/PPT) -->
  <FilePreviewModal
    v-model:visible="filePreviewState.visible.value"
    :file-url="filePreviewState.fileUrl.value"
    :file-name="filePreviewState.fileName.value"
  />
</template>