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
| | |
| | | nitroMockOptions: {}, |
| | | print: !isBuild, |
| | | printInfoMap: { |
| | | Docs: 'https://doc.iocoder.cn/quick-start/', |
| | | Docs: '#', |
| | | }, |
| | | pwa: true, |
| | | pwaOptions: getDefaultPwaOptions(appTitle), |
| | |
| | | parseOptions0(data); |
| | | return; |
| | | } |
| | | // 情况三:不是 yudao-vue-pro 标准返回 |
| | | // 情况三:不是标准返回 |
| | | console.warn( |
| | | `接口[${props.url}] 返回结果不是 yudao-vue-pro 标准返回建议采用自定义解析函数处理`, |
| | | `接口[${props.url}] 返回结果不是标准返回建议采用自定义解析函数处理`, |
| | | ); |
| | | } |
| | | |
| | |
| | | |
| | | 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'; |
| | |
| | | } |
| | | } |
| | | |
| | | 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('文件加载失败'); |
| | | } |
| | | } |
| | | |
| | | /** 处理文件数量超限 */ |
| | |
| | | 格式文件 |
| | | </div> |
| | | </Upload> |
| | | <FilePreviewModal |
| | | v-model:visible="previewState.visible.value" |
| | | :file-url="previewState.fileUrl.value" |
| | | :file-name="previewState.fileName.value" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | * @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 |
| | |
| | | </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> |
| | |
| | | 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'; |
| | | |
| | |
| | | <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> |
| | |
| | | }, |
| | | copyright: { |
| | | companyName: import.meta.env.VITE_APP_TITLE, |
| | | companySiteLink: 'https://gitee.com/yudaocode/yudao-ui-admin-vben', |
| | | companySiteLink: '#', |
| | | }, |
| | | logo: { |
| | | source: __APP_LOGO__ || undefined, |
| | |
| | | <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 |
| | |
| | | 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 { |
| | |
| | | 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) { |
| | |
| | | :show-description="true" |
| | | :show-download-icon="false" |
| | | help-text="支持多文件/图片上传" |
| | | @preview="handleFilePreview" |
| | | /> |
| | | </FormItem> |
| | | <FormItem> |
| | |
| | | :multiple="true" |
| | | :show-description="true" |
| | | help-text="支持多文件/图片上传" |
| | | @preview="handleFilePreview" |
| | | /> |
| | | </FormItem> |
| | | <FormItem> |
| | |
| | | |
| | | <!-- 签名弹窗 --> |
| | | <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> |