This commit is contained in:
xingyu4j
2025-06-16 16:59:04 +08:00
parent d09b993bc8
commit 014785a1ad
71 changed files with 447 additions and 423 deletions

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { Item } from './ui/typeing';
import type { Item } from './ui/typing';
import { onMounted, onUnmounted, ref } from 'vue';

View File

@@ -0,0 +1,2 @@
export { default as Tinyflow } from './tinyflow.vue';
export * from './ui/typing';

View File

@@ -1,21 +1,21 @@
export declare type Item = {
export interface Item {
children?: Item[];
label: string;
value: number | string;
};
}
export type Position = {
export interface Position {
x: number;
y: number;
};
}
export type Viewport = {
export interface Viewport {
x: number;
y: number;
zoom: number;
};
}
export type Node = {
export interface Node {
data?: Record<string, any>;
draggable?: boolean;
height?: number;
@@ -24,23 +24,23 @@ export type Node = {
selected?: boolean;
type?: string;
width?: number;
};
}
export type Edge = {
export interface Edge {
animated?: boolean;
id: string;
label?: string;
source: string;
target: string;
type?: string;
};
}
export type TinyflowData = Partial<{
edges: Edge[];
nodes: Node[];
viewport: Viewport;
}>;
export declare type TinyflowOptions = {
export interface TinyflowOptions {
data?: TinyflowData;
element: Element | string;
provider?: {
@@ -48,7 +48,7 @@ export declare type TinyflowOptions = {
knowledge?: () => Item[] | Promise<Item[]>;
llm?: () => Item[] | Promise<Item[]>;
};
};
}
export declare class Tinyflow {
private _init;
@@ -66,5 +66,3 @@ export declare class Tinyflow {
getOptions(): TinyflowOptions;
setData(data: TinyflowData): void;
}
export {};

View File

@@ -0,0 +1,3 @@
export { default as MarkdownView } from './markdown-view.vue';
export * from './typing';

View File

@@ -1,4 +1,6 @@
<script setup lang="ts">
import type { MarkdownViewProps } from './typing';
import { computed, onMounted, ref } from 'vue';
import { MarkdownIt } from '@vben/plugins/markmap';
@@ -10,15 +12,10 @@ import hljs from 'highlight.js';
import 'highlight.js/styles/vs2015.min.css';
//
const props = defineProps({
content: {
type: String,
required: true,
},
});
const props = defineProps<MarkdownViewProps>();
const { copy } = useClipboard(); // copy
const contentRef = ref();
const contentRef = ref<HTMLElement | null>(null);
const md = new MarkdownIt({
highlight(str, lang) {
@@ -40,7 +37,7 @@ const renderedMarkdown = computed(() => {
/** 初始化 */
onMounted(async () => {
// copy
contentRef.value.addEventListener('click', (e: any) => {
contentRef.value?.addEventListener('click', (e: any) => {
if (e.target.id === 'copy') {
copy(e.target?.dataset?.copy);
message.success('复制成功!');

View File

@@ -0,0 +1,3 @@
export type MarkdownViewProps = {
content: string;
};

View File

@@ -28,7 +28,6 @@ const props = defineProps({
default: null,
},
});
/** 新建对话 */
// 定义钩子
const emits = defineEmits([
@@ -37,9 +36,11 @@ const emits = defineEmits([
'onConversationClear',
'onConversationDelete',
]);
const [Drawer, drawerApi] = useVbenDrawer({
connectedComponent: RoleRepository,
});
// 定义属性
const searchName = ref<string>(''); // 对话搜索
const activeConversationId = ref<null | number>(null); // 选中的对话,默认为 null
@@ -50,7 +51,7 @@ const loading = ref<boolean>(false); // 加载中
const loadingTime = ref<any>();
/** 搜索对话 */
const searchConversation = async () => {
async function searchConversation() {
// 恢复数据
if (searchName.value.trim().length === 0) {
conversationMap.value = await getConversationGroupByCreateTime(
@@ -64,25 +65,25 @@ const searchConversation = async () => {
conversationMap.value =
await getConversationGroupByCreateTime(filterValues);
}
};
}
/** 点击对话 */
const handleConversationClick = async (id: number) => {
async function handleConversationClick(id: number) {
// 过滤出选中的对话
const filterConversation = conversationList.value.find((item) => {
return item.id === id;
});
// 回调 onConversationClick
// noinspection JSVoidFunctionReturnValueUsed
const success = emits('onConversationClick', filterConversation);
const success = emits('onConversationClick', filterConversation) as any;
// 切换对话
if (success) {
activeConversationId.value = id;
}
};
}
/** 获取对话列表 */
const getChatConversationList = async () => {
async function getChatConversationList() {
try {
// 加载中
loadingTime.value = setTimeout(() => {
@@ -114,12 +115,12 @@ const getChatConversationList = async () => {
// 加载完成
loading.value = false;
}
};
}
/** 按照 creteTime 创建时间,进行分组 */
const getConversationGroupByCreateTime = async (
async function getConversationGroupByCreateTime(
list: AiChatConversationApi.ChatConversationVO[],
) => {
) {
// 排序、指定、时间分组(今天、一天前、三天前、七天前、30天前)
// noinspection NonAsciiCharacters
const groupMap: any = {
@@ -159,8 +160,9 @@ const getConversationGroupByCreateTime = async (
}
}
return groupMap;
};
const createConversation = async () => {
}
async function createConversation() {
// 1. 新建对话
const conversationId = await createChatConversationMy(
{} as unknown as AiChatConversationApi.ChatConversationVO,
@@ -171,12 +173,12 @@ const createConversation = async () => {
await handleConversationClick(conversationId);
// 4. 回调
emits('onConversationCreate');
};
}
/** 修改对话的标题 */
const updateConversationTitle = async (
async function updateConversationTitle(
conversation: AiChatConversationApi.ChatConversationVO,
) => {
) {
// 1. 二次确认
prompt({
async beforeClose(scope) {
@@ -225,12 +227,12 @@ const updateConversationTitle = async (
title: '修改标题',
modelPropName: 'value',
});
};
}
/** 删除聊天对话 */
const deleteChatConversation = async (
async function deleteChatConversation(
conversation: AiChatConversationApi.ChatConversationVO,
) => {
) {
try {
// 删除的二次确认
await confirm(`是否确认删除对话 - ${conversation.title}?`);
@@ -242,8 +244,9 @@ const deleteChatConversation = async (
// 回调
emits('onConversationDelete', conversation);
} catch {}
};
const handleClearConversation = async () => {
}
async function handleClearConversation() {
try {
await confirm('确认后对话会全部清空,置顶的对话除外。');
await deleteChatConversationMyByUnpinned();
@@ -255,18 +258,18 @@ const handleClearConversation = async () => {
// 回调 方法
emits('onConversationClear');
} catch {}
};
}
/** 对话置顶 */
const handleTop = async (
async function handleTop(
conversation: AiChatConversationApi.ChatConversationVO,
) => {
) {
// 更新对话置顶
conversation.pinned = !conversation.pinned;
await updateChatConversationMy(conversation);
// 刷新对话
await getChatConversationList();
};
}
// ============ 角色仓库 ============

View File

@@ -47,10 +47,10 @@ const documentList = computed(() => {
});
/** 点击 document 处理 */
const handleClick = (doc: any) => {
function handleClick(doc: any) {
document.value = doc;
dialogVisible.value = true;
};
}
</script>
<template>

View File

@@ -14,7 +14,7 @@ import { useClipboard } from '@vueuse/core';
import { Avatar, Button, message } from 'ant-design-vue';
import { deleteChatMessage } from '#/api/ai/chat/message';
import MarkdownView from '#/components/MarkdownView/index.vue';
import { MarkdownView } from '#/components/markdown-view';
import MessageKnowledge from './MessageKnowledge.vue';
// 定义 props
@@ -67,44 +67,44 @@ function handleScroll() {
}
/** 回到底部 */
const handleGoBottom = async () => {
async function handleGoBottom() {
const scrollContainer = messageContainer.value;
scrollContainer.scrollTop = scrollContainer.scrollHeight;
};
}
/** 回到顶部 */
const handlerGoTop = async () => {
async function handlerGoTop() {
const scrollContainer = messageContainer.value;
scrollContainer.scrollTop = 0;
};
}
defineExpose({ scrollToBottom, handlerGoTop }); // 提供方法给 parent 调用
// ============ 处理消息操作 ==============
/** 复制 */
const copyContent = async (content: string) => {
async function copyContent(content: string) {
await copy(content);
message.success('复制成功!');
};
}
/** 删除 */
const onDelete = async (id: number) => {
async function onDelete(id: number) {
// 删除 message
await deleteChatMessage(id);
message.success('删除成功!');
// 回调
emits('onDeleteSuccess');
};
}
/** 刷新 */
const onRefresh = async (message: AiChatMessageApi.ChatMessageVO) => {
async function onRefresh(message: AiChatMessageApi.ChatMessageVO) {
emits('onRefresh', message);
};
}
/** 编辑 */
const onEdit = async (message: AiChatMessageApi.ChatMessageVO) => {
async function onEdit(message: AiChatMessageApi.ChatMessageVO) {
emits('onEdit', message);
};
}
/** 初始化 */
onMounted(async () => {

View File

@@ -11,9 +11,9 @@ const promptList = [
prompt: '写一首好听的诗歌?',
},
]; /** 选中 prompt 点击 */
const handlerPromptClick = async (prompt: any) => {
async function handlerPromptClick(prompt: any) {
emits('onPrompt', prompt.prompt);
};
}
</script>
<template>
<div class="relative flex h-full w-full flex-row justify-center">

View File

@@ -4,9 +4,9 @@ import { Button } from 'ant-design-vue';
const emits = defineEmits(['onNewConversation']);
/** 新建 conversation 聊天对话 */
const handlerNewChat = () => {
function handlerNewChat() {
emits('onNewConversation');
};
}
</script>
<template>

View File

@@ -19,9 +19,9 @@ defineProps({
const emits = defineEmits(['onCategoryClick']);
/** 处理分类点击事件 */
const handleCategoryClick = async (category: string) => {
async function handleCategoryClick(category: string) {
emits('onCategoryClick', category);
};
}
</script>
<template>

View File

@@ -33,7 +33,7 @@ const emits = defineEmits(['onDelete', 'onEdit', 'onUse', 'onPage']);
const tabsRef = ref<any>();
/** 操作:编辑、删除 */
const handleMoreClick = async (data: any) => {
async function handleMoreClick(data: any) {
const type = data[0];
const role = data[1];
if (type === 'delete') {
@@ -41,22 +41,22 @@ const handleMoreClick = async (data: any) => {
} else {
emits('onEdit', role);
}
};
}
/** 选中 */
const handleUseClick = (role: any) => {
function handleUseClick(role: any) {
emits('onUse', role);
};
}
/** 滚动 */
const handleTabsScroll = async () => {
async function handleTabsScroll() {
if (tabsRef.value) {
const { scrollTop, scrollHeight, clientHeight } = tabsRef.value;
if (scrollTop + clientHeight >= scrollHeight - 20 && !props.loading) {
await emits('onPage');
}
}
};
}
</script>
<template>

View File

@@ -46,15 +46,15 @@ const activeCategory = ref<string>('全部'); // 选择中的分类
const categoryList = ref<string[]>([]); // 角色分类类别
/** tabs 点击 */
const handleTabsClick = async (tab: any) => {
async function handleTabsClick(tab: any) {
// 设置切换状态
activeTab.value = tab;
// 切换的时候重新加载数据
await getActiveTabsRole();
};
}
/** 获取 my role 我的角色 */
const getMyRole = async (append?: boolean) => {
async function getMyRole(append?: boolean) {
const params: AiModelChatRoleApi.ChatRolePageReqVO = {
...myRoleParams,
name: search.value,
@@ -66,10 +66,10 @@ const getMyRole = async (append?: boolean) => {
} else {
myRoleList.value = list;
}
};
}
/** 获取 public role 公共角色 */
const getPublicRole = async (append?: boolean) => {
async function getPublicRole(append?: boolean) {
const params: AiModelChatRoleApi.ChatRolePageReqVO = {
...publicRoleParams,
category: activeCategory.value === '全部' ? '' : activeCategory.value,
@@ -82,10 +82,10 @@ const getPublicRole = async (append?: boolean) => {
} else {
publicRoleList.value = list;
}
};
}
/** 获取选中的 tabs 角色 */
const getActiveTabsRole = async () => {
async function getActiveTabsRole() {
if (activeTab.value === 'my-role') {
myRoleParams.pageNo = 1;
await getMyRole();
@@ -93,43 +93,44 @@ const getActiveTabsRole = async () => {
publicRoleParams.pageNo = 1;
await getPublicRole();
}
};
}
/** 获取角色分类列表 */
const getRoleCategoryList = async () => {
async function getRoleCategoryList() {
categoryList.value = ['全部', ...(await getCategoryList())];
};
}
/** 处理分类点击 */
const handlerCategoryClick = async (category: string) => {
async function handlerCategoryClick(category: string) {
// 切换选择的分类
activeCategory.value = category;
// 筛选
await getActiveTabsRole();
};
}
const handlerAddRole = async () => {
async function handlerAddRole() {
formModalApi.setData({ formType: 'my-create' }).open();
};
}
/** 编辑角色 */
const handlerCardEdit = async (role: any) => {
async function handlerCardEdit(role: any) {
formModalApi.setData({ formType: 'my-update', id: role.id }).open();
};
}
/** 添加角色成功 */
const handlerAddRoleSuccess = async () => {
async function handlerAddRoleSuccess() {
// 刷新数据
await getActiveTabsRole();
};
}
/** 删除角色 */
const handlerCardDelete = async (role: any) => {
async function handlerCardDelete(role: any) {
await deleteMy(role.id);
// 刷新数据
await getActiveTabsRole();
};
}
/** 角色分页:获取下一页 */
const handlerCardPage = async (type: string) => {
async function handlerCardPage(type: string) {
try {
loading.value = true;
if (type === 'public') {
@@ -142,10 +143,10 @@ const handlerCardPage = async (type: string) => {
} finally {
loading.value = false;
}
};
}
/** 选择 card 角色:新建聊天对话 */
const handlerCardUse = async (role: any) => {
async function handlerCardUse(role: any) {
// 1. 创建对话
const data: AiChatConversationApi.ChatConversationVO = {
roleId: role.id,
@@ -159,7 +160,8 @@ const handlerCardUse = async (role: any) => {
conversationId,
},
});
};
}
/** 初始化 */
onMounted(async () => {
// 获取分类

View File

@@ -61,7 +61,7 @@ const receiveMessageDisplayedText = ref('');
// =========== 【聊天对话】相关 ===========
/** 获取对话信息 */
const getConversation = async (id: null | number) => {
async function getConversation(id: null | number) {
if (!id) {
return;
}
@@ -72,7 +72,7 @@ const getConversation = async (id: null | number) => {
}
activeConversation.value = conversation;
activeConversationId.value = conversation.id;
};
}
/**
* 点击某个对话
@@ -80,9 +80,9 @@ const getConversation = async (id: null | number) => {
* @param conversation 选中的对话
* @return 是否切换成功
*/
const handleConversationClick = async (
async function handleConversationClick(
conversation: AiChatConversationApi.ChatConversationVO,
) => {
) {
// 对话进行中,不允许切换
if (conversationInProgress.value) {
alert('对话中,不允许切换!');
@@ -99,20 +99,20 @@ const handleConversationClick = async (
// 清空输入框
prompt.value = '';
return true;
};
}
/** 删除某个对话*/
const handlerConversationDelete = async (
async function handlerConversationDelete(
delConversation: AiChatConversationApi.ChatConversationVO,
) => {
) {
// 删除的对话如果是当前选中的,那么就重置
if (activeConversationId.value === delConversation.id) {
await handleConversationClear();
}
};
}
/** 清空选中的对话 */
const handleConversationClear = async () => {
async function handleConversationClear() {
// 对话进行中,不允许切换
if (conversationInProgress.value) {
alert('对话中,不允许切换!');
@@ -121,31 +121,31 @@ const handleConversationClear = async () => {
activeConversationId.value = null;
activeConversation.value = null;
activeMessageList.value = [];
};
}
const openChatConversationUpdateForm = async () => {
async function openChatConversationUpdateForm() {
formModalApi.setData({ id: activeConversationId.value }).open();
};
const handleConversationUpdateSuccess = async () => {
}
async function handleConversationUpdateSuccess() {
// 对话更新成功,刷新最新信息
await getConversation(activeConversationId.value);
};
}
/** 处理聊天对话的创建成功 */
const handleConversationCreate = async () => {
async function handleConversationCreate() {
// 创建对话
await conversationListRef.value.createConversation();
};
}
/** 处理聊天对话的创建成功 */
const handleConversationCreateSuccess = async () => {
async function handleConversationCreateSuccess() {
// 创建新的对话,清空输入框
prompt.value = '';
};
}
// =========== 【消息列表】相关 ===========
/** 获取消息 message 列表 */
const getMessageList = async () => {
async function getMessageList() {
try {
if (activeConversationId.value === null) {
return;
@@ -171,7 +171,7 @@ const getMessageList = async () => {
// 加载结束
activeMessageListLoading.value = false;
}
};
}
/**
* 消息列表
@@ -196,17 +196,17 @@ const messageList = computed(() => {
});
/** 处理删除 message 消息 */
const handleMessageDelete = () => {
function handleMessageDelete() {
if (conversationInProgress.value) {
alert('回答中,不能删除!');
return;
}
// 刷新 message 列表
getMessageList();
};
}
/** 处理 message 清空 */
const handlerMessageClear = async () => {
async function handlerMessageClear() {
if (!activeConversationId.value) {
return;
}
@@ -218,16 +218,16 @@ const handlerMessageClear = async () => {
// 刷新 message 列表
activeMessageList.value = [];
} catch {}
};
}
/** 回到 message 列表的顶部 */
const handleGoTopMessage = () => {
function handleGoTopMessage() {
messageRef.value.handlerGoTop();
};
}
// =========== 【发送消息】相关 ===========
/** 处理来自 keydown 的发送消息 */
const handleSendByKeydown = async (event: any) => {
async function handleSendByKeydown(event: any) {
// 判断用户是否在输入
if (isComposing.value) {
return;
@@ -248,15 +248,15 @@ const handleSendByKeydown = async (event: any) => {
event.preventDefault(); // 防止默认的提交行为
}
}
};
}
/** 处理来自【发送】按钮的发送消息 */
const handleSendByButton = () => {
function handleSendByButton() {
doSendMessage(prompt.value?.trim() as string);
};
}
/** 处理 prompt 输入变化 */
const handlePromptInput = (event) => {
function handlePromptInput(event: any) {
// 非输入法 输入设置为 true
if (!isComposing.value) {
// 回车 event data 是 null
@@ -273,27 +273,27 @@ const handlePromptInput = (event) => {
inputTimeout.value = setTimeout(() => {
isComposing.value = false;
}, 400);
};
}
const onCompositionstart = () => {
function onCompositionstart() {
isComposing.value = true;
};
}
const onCompositionend = () => {
function onCompositionend() {
// console.log('输入结束...')
setTimeout(() => {
isComposing.value = false;
}, 200);
};
}
/** 真正执行【发送】消息操作 */
const doSendMessage = async (content: string) => {
async function doSendMessage(content: string) {
// 校验
if (content.length === 0) {
message.error('发送失败,原因:内容为空!');
return;
}
if (activeConversationId.value == null) {
if (activeConversationId.value === null) {
message.error('还没创建对话,不能发送!');
return;
}
@@ -304,12 +304,12 @@ const doSendMessage = async (content: string) => {
conversationId: activeConversationId.value,
content,
} as AiChatMessageApi.ChatMessageVO);
};
}
/** 真正执行【发送】消息操作 */
const doSendMessageStream = async (
async function doSendMessageStream(
userMessage: AiChatMessageApi.ChatMessageVO,
) => {
) {
// 创建 AbortController 实例,以便中止请求
conversationInAbortController.value = new AbortController();
// 标记对话进行中
@@ -385,40 +385,40 @@ const doSendMessageStream = async (
},
);
} catch {}
};
}
/** 停止 stream 流式调用 */
const stopStream = async () => {
async function stopStream() {
// tip如果 stream 进行中的 message就需要调用 controller 结束
if (conversationInAbortController.value) {
conversationInAbortController.value.abort();
}
// 设置为 false
conversationInProgress.value = false;
};
}
/** 编辑 message设置为 prompt可以再次编辑 */
const handleMessageEdit = (message: AiChatMessageApi.ChatMessageVO) => {
function handleMessageEdit(message: AiChatMessageApi.ChatMessageVO) {
prompt.value = message.content;
};
}
/** 刷新 message基于指定消息再次发起对话 */
const handleMessageRefresh = (message: AiChatMessageApi.ChatMessageVO) => {
function handleMessageRefresh(message: AiChatMessageApi.ChatMessageVO) {
doSendMessage(message.content);
};
}
// ============== 【消息滚动】相关 =============
/** 滚动到 message 底部 */
const scrollToBottom = async (isIgnore?: boolean) => {
async function scrollToBottom(isIgnore?: boolean) {
await nextTick();
if (messageRef.value) {
messageRef.value.scrollToBottom(isIgnore);
}
};
}
/** 自提滚动效果 */
const textRoll = async () => {
async function textRoll() {
let index = 0;
try {
// 只能执行一次
@@ -475,7 +475,7 @@ const textRoll = async () => {
};
let timer = setTimeout(task, textSpeed.value);
} catch {}
};
}
/** 初始化 */
onMounted(async () => {
@@ -569,8 +569,8 @@ onMounted(async () => {
<MessageList
v-if="!activeMessageListLoading && messageList.length > 0"
ref="messageRef"
:conversation="activeConversation"
:list="messageList"
:conversation="activeConversation as any"
:list="messageList as any"
@on-delete-success="handleMessageDelete"
@on-edit="handleMessageEdit"
@on-refresh="handleMessageRefresh"

View File

@@ -2,7 +2,7 @@ import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE } from '#/utils';
import { DICT_TYPE, getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchemaConversation(): VbenFormSchema[] {
@@ -22,8 +22,7 @@ export function useGridFormSchemaConversation(): VbenFormSchema[] {
label: '创建时间',
component: 'RangePicker',
componentProps: {
placeholder: ['开始时间', '结束时间'],
valueFormat: 'YYYY-MM-DD HH:mm:ss',
...getRangePickerDefaultProps(),
allowClear: true,
},
},
@@ -118,8 +117,7 @@ export function useGridFormSchemaMessage(): VbenFormSchema[] {
label: '创建时间',
component: 'RangePicker',
componentProps: {
placeholder: ['开始时间', '结束时间'],
valueFormat: 'YYYY-MM-DD HH:mm:ss',
...getRangePickerDefaultProps(),
allowClear: true,
},
},

View File

@@ -9,7 +9,7 @@ import { confirm } from '@vben/common-ui';
import { Button, Card, Image, message } from 'ant-design-vue';
import { AiImageStatusEnum } from '#/utils/constants';
import { AiImageStatusEnum } from '#/utils';
// 消息
@@ -24,20 +24,18 @@ const emits = defineEmits(['onBtnClick', 'onMjBtnClick']);
const cardImageRef = ref<any>(); // 卡片 image ref
/** 处理点击事件 */
const handleButtonClick = async (type: string, detail: AiImageApi.ImageVO) => {
async function handleButtonClick(type: string, detail: AiImageApi.ImageVO) {
emits('onBtnClick', type, detail);
};
}
/** 处理 Midjourney 按钮点击事件 */
const handleMidjourneyBtnClick = async (
async function handleMidjourneyBtnClick(
button: AiImageApi.ImageMidjourneyButtonsVO,
) => {
) {
// 确认窗体
await confirm(`确认操作 "${button.label} ${button.emoji}" ?`);
emits('onMjBtnClick', button, props.detail);
};
// emits
}
/** 监听详情 */
const { detail } = toRefs(props);
@@ -46,7 +44,7 @@ watch(detail, async (newVal) => {
});
const loading = ref();
/** 处理加载状态 */
const handleLoading = async (status: number) => {
async function handleLoading(status: number) {
// 情况一:如果是生成中,则设置加载中的 loading
if (status === AiImageStatusEnum.IN_PROGRESS) {
loading.value = message.loading({
@@ -57,7 +55,7 @@ const handleLoading = async (status: number) => {
} else {
if (loading.value) setTimeout(loading.value, 100);
}
};
}
/** 初始化 */
onMounted(async () => {

View File

@@ -3,6 +3,8 @@ import type { AiImageApi } from '#/api/ai/image';
import { ref, toRefs, watch } from 'vue';
import { formatDate } from '@vben/utils';
import { Image } from 'ant-design-vue';
import { getImageMy } from '#/api/ai/image';
@@ -12,8 +14,7 @@ import {
StableDiffusionClipGuidancePresets,
StableDiffusionSamplers,
StableDiffusionStylePresets,
} from '#/utils/constants';
import { formatTime } from '#/utils/formatTime';
} from '#/utils';
// 图片详细信息
const props = defineProps({
@@ -25,9 +26,9 @@ const props = defineProps({
const detail = ref<AiImageApi.ImageVO>({} as AiImageApi.ImageVO);
/** 获取图片详情 */
const getImageDetail = async (id: number) => {
async function getImageDetail(id: number) {
detail.value = await getImageMy(id);
};
}
const { id } = toRefs(props);
watch(
@@ -53,10 +54,10 @@ watch(
<div class="tip text-lg font-bold">时间</div>
<div class="body mt-2 text-gray-600">
<div>
提交时间{{ formatTime(detail.createTime, 'yyyy-MM-dd HH:mm:ss') }}
提交时间{{ formatDate(detail.createTime, 'yyyy-MM-dd HH:mm:ss') }}
</div>
<div>
生成时间{{ formatTime(detail.finishTime, 'yyyy-MM-dd HH:mm:ss') }}
生成时间{{ formatDate(detail.finishTime, 'yyyy-MM-dd HH:mm:ss') }}
</div>
</div>
</div>

View File

@@ -5,6 +5,7 @@ import { onMounted, onUnmounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import { confirm, useVbenDrawer } from '@vben/common-ui';
import { downloadFileFromImageUrl } from '@vben/utils';
import { useDebounceFn } from '@vueuse/core';
import { Button, Card, message, Pagination } from 'ant-design-vue';
@@ -15,8 +16,7 @@ import {
getImagePageMy,
midjourneyAction,
} from '#/api/ai/image';
import { AiImageStatusEnum } from '#/utils/constants';
import { download } from '#/utils/download';
import { AiImageStatusEnum } from '#/utils';
import ImageCard from './ImageCard.vue';
import ImageDetail from './ImageDetail.vue';
@@ -43,18 +43,18 @@ const inProgressTimer = ref<any>(); // 生成中的 image 定时器,轮询生
const showImageDetailId = ref<number>(0); // 图片详情的图片编号
/** 处理查看绘图作品 */
const handleViewPublic = () => {
function handleViewPublic() {
router.push({
name: 'AiImageSquare',
});
};
}
/** 查看图片的详情 */
const handleDetailOpen = async () => {
async function handleDetailOpen() {
drawerApi.open();
};
}
/** 获得 image 图片列表 */
const getImageList = async () => {
async function getImageList() {
const loading = message.loading({
content: `加载中...`,
});
@@ -77,10 +77,10 @@ const getImageList = async () => {
// 关闭正在“加载中”的 Loading
loading();
}
};
}
const debounceGetImageList = useDebounceFn(getImageList, 80);
/** 轮询生成中的 image 列表 */
const refreshWatchImages = async () => {
async function refreshWatchImages() {
const imageIds = Object.keys(inProgressImageMap.value).map(Number);
if (imageIds.length === 0) {
return;
@@ -101,13 +101,13 @@ const refreshWatchImages = async () => {
}
});
inProgressImageMap.value = newWatchImages;
};
}
/** 图片的点击事件 */
const handleImageButtonClick = async (
async function handleImageButtonClick(
type: string,
imageDetail: AiImageApi.ImageVO,
) => {
) {
// 详情
if (type === 'more') {
showImageDetailId.value = imageDetail.id;
@@ -124,20 +124,23 @@ const handleImageButtonClick = async (
}
// 下载
if (type === 'download') {
await download.image({ url: imageDetail.picUrl });
await downloadFileFromImageUrl({
fileName: imageDetail.model,
source: imageDetail.picUrl,
});
return;
}
// 重新生成
if (type === 'regeneration') {
await emits('onRegeneration', imageDetail);
}
};
}
/** 处理 Midjourney 按钮点击事件 */
const handleImageMidjourneyButtonClick = async (
async function handleImageMidjourneyButtonClick(
button: AiImageApi.ImageMidjourneyButtonsVO,
imageDetail: AiImageApi.ImageVO,
) => {
) {
// 1. 构建 params 参数
const data = {
id: imageDetail.id,
@@ -147,7 +150,7 @@ const handleImageMidjourneyButtonClick = async (
await midjourneyAction(data);
// 3. 刷新列表
await getImageList();
};
}
defineExpose({ getImageList }); /** 组件挂在的时候 */
onMounted(async () => {

View File

@@ -10,11 +10,7 @@ import { confirm } from '@vben/common-ui';
import { Button, InputNumber, Select, Space, Textarea } from 'ant-design-vue';
import { drawImage } from '#/api/ai/image';
import {
AiPlatformEnum,
ImageHotWords,
OtherPlatformEnum,
} from '#/utils/constants';
import { AiPlatformEnum, ImageHotWords, OtherPlatformEnum } from '#/utils';
// 消息弹窗
@@ -39,7 +35,7 @@ const platformModels = ref<AiModelModelApi.ModelVO[]>([]); // 模型列表
const modelId = ref<number>(); // 选中的模型
/** 选择热词 */
const handleHotWordClick = async (hotWord: string) => {
async function handleHotWordClick(hotWord: string) {
// 情况一:取消选中
if (selectHotWord.value === hotWord) {
selectHotWord.value = '';
@@ -49,10 +45,10 @@ const handleHotWordClick = async (hotWord: string) => {
// 情况二:选中
selectHotWord.value = hotWord; // 选中
prompt.value = hotWord; // 替换提示词
};
}
/** 图片生成 */
const handleGenerateImage = async () => {
async function handleGenerateImage() {
// 二次确认
await confirm(`确认生成内容?`);
try {
@@ -76,17 +72,17 @@ const handleGenerateImage = async () => {
// 加载结束
drawIn.value = false;
}
};
}
/** 填充值 */
const settingValues = async (detail: AiImageApi.ImageVO) => {
async function settingValues(detail: AiImageApi.ImageVO) {
prompt.value = detail.prompt;
width.value = detail.width;
height.value = detail.height;
};
}
/** 平台切换 */
const handlerPlatformChange = async (platform: any) => {
async function handlerPlatformChange(platform: any) {
// 根据选择的平台筛选模型
platformModels.value = props.models.filter(
(item: AiModelModelApi.ModelVO) => item.platform === platform,
@@ -96,7 +92,7 @@ const handlerPlatformChange = async (platform: any) => {
? platformModels.value[0].id
: undefined;
// 切换平台,默认选择一个模型
};
}
/** 监听 models 变化 */
watch(

View File

@@ -2,7 +2,7 @@
<script setup lang="ts">
import type { AiImageApi } from '#/api/ai/image';
import type { AiModelModelApi } from '#/api/ai/model/model';
import type { ImageModelVO, ImageSizeVO } from '#/utils/constants';
import type { ImageModelVO, ImageSizeVO } from '#/utils';
import { ref } from 'vue';
@@ -17,7 +17,7 @@ import {
Dall3SizeList,
Dall3StyleList,
ImageHotWords,
} from '#/utils/constants';
} from '#/utils';
// 接收父组件传入的模型列表
const props = defineProps({
@@ -37,7 +37,7 @@ const selectSize = ref<string>('1024x1024'); // 选中 size
const style = ref<string>('vivid'); // style 样式
/** 选择热词 */
const handleHotWordClick = async (hotWord: string) => {
async function handleHotWordClick(hotWord: string) {
// 情况一:取消选中
if (selectHotWord.value === hotWord) {
selectHotWord.value = '';
@@ -47,10 +47,10 @@ const handleHotWordClick = async (hotWord: string) => {
// 情况二:选中
selectHotWord.value = hotWord;
prompt.value = hotWord;
};
}
/** 选择 model 模型 */
const handleModelClick = async (model: ImageModelVO) => {
async function handleModelClick(model: ImageModelVO) {
selectModel.value = model.key;
// 可以在这里添加模型特定的处理逻辑
// 例如,如果未来需要根据不同模型设置不同参数
@@ -73,20 +73,20 @@ const handleModelClick = async (model: ImageModelVO) => {
if (recommendedSize) {
selectSize.value = recommendedSize.key;
}
};
}
/** 选择 style 样式 */
const handleStyleClick = async (imageStyle: ImageModelVO) => {
async function handleStyleClick(imageStyle: ImageModelVO) {
style.value = imageStyle.key;
};
}
/** 选择 size 大小 */
const handleSizeClick = async (imageSize: ImageSizeVO) => {
async function handleSizeClick(imageSize: ImageSizeVO) {
selectSize.value = imageSize.key;
};
}
/** 图片生产 */
const handleGenerateImage = async () => {
async function handleGenerateImage() {
// 从 models 中查找匹配的模型
const matchedModel = props.models.find(
(item) =>
@@ -127,10 +127,10 @@ const handleGenerateImage = async () => {
// 加载结束
drawIn.value = false;
}
};
}
/** 填充值 */
const settingValues = async (detail: AiImageApi.ImageVO) => {
async function settingValues(detail: AiImageApi.ImageVO) {
prompt.value = detail.prompt;
selectModel.value = detail.model;
style.value = detail.options?.style;
@@ -138,7 +138,7 @@ const settingValues = async (detail: AiImageApi.ImageVO) => {
(item) => item.key === `${detail.width}x${detail.height}`,
) as ImageSizeVO;
await handleSizeClick(imageSize);
};
}
/** 暴露组件方法 */
defineExpose({ settingValues });

View File

@@ -2,7 +2,7 @@
<script setup lang="ts">
import type { AiImageApi } from '#/api/ai/image';
import type { AiModelModelApi } from '#/api/ai/model/model';
import type { ImageModelVO, ImageSizeVO } from '#/utils/constants';
import type { ImageModelVO, ImageSizeVO } from '#/utils';
import { ref } from 'vue';
@@ -26,7 +26,7 @@ import {
MidjourneySizeList,
MidjourneyVersions,
NijiVersionList,
} from '#/utils/constants';
} from '#/utils';
// 消息弹窗
@@ -51,7 +51,7 @@ const selectVersion = ref<any>('6.0'); // 选中的 version
const versionList = ref<any>(MidjourneyVersions); // version 列表
/** 选择热词 */
const handleHotWordClick = async (hotWord: string) => {
async function handleHotWordClick(hotWord: string) {
// 情况一:取消选中
if (selectHotWord.value === hotWord) {
selectHotWord.value = '';
@@ -61,23 +61,23 @@ const handleHotWordClick = async (hotWord: string) => {
// 情况二:选中
selectHotWord.value = hotWord; // 选中
prompt.value = hotWord; // 设置提示次
};
}
/** 点击 size 尺寸 */
const handleSizeClick = async (imageSize: ImageSizeVO) => {
async function handleSizeClick(imageSize: ImageSizeVO) {
selectSize.value = imageSize.key;
};
}
/** 点击 model 模型 */
const handleModelClick = async (model: ImageModelVO) => {
async function handleModelClick(model: ImageModelVO) {
selectModel.value = model.key;
versionList.value =
model.key === 'niji' ? NijiVersionList : MidjourneyVersions;
selectVersion.value = versionList.value[0].value;
};
}
/** 图片生成 */
const handleGenerateImage = async () => {
async function handleGenerateImage() {
// 从 models 中查找匹配的模型
const matchedModel = props.models.find(
(item) =>
@@ -115,10 +115,10 @@ const handleGenerateImage = async () => {
// 加载结束
drawIn.value = false;
}
};
}
/** 填充值 */
const settingValues = async (detail: AiImageApi.ImageVO) => {
async function settingValues(detail: AiImageApi.ImageVO) {
// 提示词
prompt.value = detail.prompt;
// image size
@@ -137,7 +137,7 @@ const settingValues = async (detail: AiImageApi.ImageVO) => {
).value;
// image
referImageUrl.value = detail.options.referImageUrl;
};
}
/** 暴露组件方法 */
defineExpose({ settingValues });

View File

@@ -23,10 +23,7 @@ import {
StableDiffusionClipGuidancePresets,
StableDiffusionSamplers,
StableDiffusionStylePresets,
} from '#/utils/constants';
import { hasChinese } from '#/utils/utils';
// 消息弹窗
} from '#/utils';
// 接收父组件传入的模型列表
const props = defineProps({
@@ -35,8 +32,13 @@ const props = defineProps({
default: () => [] as AiModelModelApi.ModelVO[],
},
});
const emits = defineEmits(['onDrawStart', 'onDrawComplete']);
function hasChinese(str: string) {
return /[\u4E00-\u9FA5]/.test(str);
}
// 定义属性
const drawIn = ref<boolean>(false); // 生成中
const selectHotWord = ref<string>(''); // 选中的热词
@@ -52,7 +54,7 @@ const clipGuidancePreset = ref<string>('NONE'); // 文本提示相匹配的图
const stylePreset = ref<string>('3d-model'); // 风格
/** 选择热词 */
const handleHotWordClick = async (hotWord: string) => {
async function handleHotWordClick(hotWord: string) {
// 情况一:取消选中
if (selectHotWord.value === hotWord) {
selectHotWord.value = '';
@@ -62,10 +64,10 @@ const handleHotWordClick = async (hotWord: string) => {
// 情况二:选中
selectHotWord.value = hotWord; // 选中
prompt.value = hotWord; // 替换提示词
};
}
/** 图片生成 */
const handleGenerateImage = async () => {
async function handleGenerateImage() {
// 从 models 中查找匹配的模型
const selectModel = 'stable-diffusion-v1-6';
const matchedModel = props.models.find(
@@ -112,10 +114,10 @@ const handleGenerateImage = async () => {
// 加载结束
drawIn.value = false;
}
};
}
/** 填充值 */
const settingValues = async (detail: AiImageApi.ImageVO) => {
async function settingValues(detail: AiImageApi.ImageVO) {
prompt.value = detail.prompt;
width.value = detail.width;
height.value = detail.height;
@@ -125,7 +127,7 @@ const settingValues = async (detail: AiImageApi.ImageVO) => {
sampler.value = detail.options?.sampler;
clipGuidancePreset.value = detail.options?.clipGuidancePreset;
stylePreset.value = detail.options?.stylePreset;
};
}
/** 暴露组件方法 */
defineExpose({ settingValues });

View File

@@ -9,7 +9,7 @@ import { Page } from '@vben/common-ui';
import { Segmented } from 'ant-design-vue';
import { getModelSimpleList } from '#/api/ai/model/model';
import { AiModelTypeEnum, AiPlatformEnum } from '#/utils/constants';
import { AiModelTypeEnum, AiPlatformEnum } from '#/utils';
import Common from './components/common/index.vue';
import Dall3 from './components/dall3/index.vue';

View File

@@ -2,7 +2,7 @@ import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions } from '#/utils';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {
@@ -49,8 +49,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '创建时间',
component: 'RangePicker',
componentProps: {
placeholder: ['开始时间', '结束时间'],
valueFormat: 'YYYY-MM-DD HH:mm:ss',
...getRangePickerDefaultProps(),
allowClear: true,
},
},

View File

@@ -13,7 +13,7 @@ import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { deleteImage, getImagePage, updateImage } from '#/api/ai/image';
import { getSimpleUserList } from '#/api/system/user';
import { $t } from '#/locales';
import { AiImageStatusEnum } from '#/utils/constants';
import { AiImageStatusEnum } from '#/utils';
import { useGridColumns, useGridFormSchema } from './data';

View File

@@ -9,7 +9,7 @@ import { useDebounceFn } from '@vueuse/core';
import { Input, Pagination } from 'ant-design-vue';
import { getImagePageMy } from '#/api/ai/image';
// TODO @fan加个 loading 加载中的状态
const loading = ref(true); // 列表的加载中
const list = ref<AiImageApi.ImageVO[]>([]); // 列表的数据
const total = ref(0); // 列表的总页数
@@ -21,7 +21,7 @@ const queryParams = reactive({
});
/** 查询列表 */
const getList = async () => {
async function getList() {
loading.value = true;
try {
const data = await getImagePageMy(queryParams);
@@ -30,7 +30,7 @@ const getList = async () => {
} finally {
loading.value = false;
}
};
}
const debounceGetList = useDebounceFn(getList, 80);
/** 搜索按钮操作 */
const handleQuery = () => {

View File

@@ -19,9 +19,9 @@ const parent = inject('parent') as any;
const pollingTimer = ref<null | number>(null); // 轮询定时器 ID用于跟踪和清除轮询进程
/** 判断文件处理是否完成 */
const isProcessComplete = (file: any) => {
function isProcessComplete(file: any) {
return file.progress === 100;
};
}
/** 判断所有文件是否都处理完成 */
const allProcessComplete = computed(() => {
@@ -29,14 +29,14 @@ const allProcessComplete = computed(() => {
});
/** 完成按钮点击事件处理 */
const handleComplete = () => {
function handleComplete() {
if (parent?.exposed?.handleBack) {
parent.exposed.handleBack();
}
};
}
/** 获取文件处理进度 */
const getProcessList = async () => {
async function getProcessList() {
try {
// 1. 调用 API 获取处理进度
const documentIds = props.modelValue.list
@@ -82,7 +82,7 @@ const getProcessList = async () => {
console.error('获取处理进度失败:', error);
pollingTimer.value = window.setTimeout(getProcessList, 5000);
}
};
}
/** 组件挂载时开始轮询 */
onMounted(() => {

View File

@@ -42,12 +42,13 @@ const currentFile = ref<any>(null); // 当前选中的文件
const submitLoading = ref(false); // 提交按钮加载状态
/** 选择文件 */
const selectFile = async (index: number) => {
async function selectFile(index: number) {
currentFile.value = modelData.value.list[index];
await splitContentFile(currentFile.value);
};
}
/** 获取文件分段内容 */
const splitContentFile = async (file: any) => {
async function splitContentFile(file: any) {
if (!file || !file.url) {
message.warning('文件 URL 不存在');
return;
@@ -65,9 +66,9 @@ const splitContentFile = async (file: any) => {
} finally {
splitLoading.value = false;
}
};
}
/** 处理预览分段 */
const handleAutoSegment = async () => {
async function handleAutoSegment() {
// 如果没有选中文件,默认选中第一个
if (
!currentFile.value &&
@@ -84,18 +85,18 @@ const handleAutoSegment = async () => {
// 获取分段内容
await splitContentFile(currentFile.value);
};
}
/** 上一步按钮处理 */
const handlePrevStep = () => {
function handlePrevStep() {
const parentEl = parent || getCurrentInstance()?.parent;
if (parentEl && typeof parentEl.exposed?.goToPrevStep === 'function') {
parentEl.exposed.goToPrevStep();
}
};
}
/** 保存操作 */
const handleSave = async () => {
async function handleSave() {
// 保存前验证
if (
!currentFile?.value?.segments ||
@@ -140,7 +141,7 @@ const handleSave = async () => {
// 关闭按钮加载状态
submitLoading.value = false;
}
};
}
/** 初始化 */
onMounted(async () => {

View File

@@ -10,11 +10,11 @@ import { computed, getCurrentInstance, inject, onMounted, ref } from 'vue';
import { IconifyIcon } from '@vben/icons';
import { $t } from '@vben/locales';
import { generateAcceptedFileTypes } from '@vben/utils';
import { Button, Form, message, UploadDragger } from 'ant-design-vue';
import { useUpload } from '#/components/upload/use-upload';
import { generateAcceptedFileTypes } from '#/utils/upload';
const props = defineProps({
modelValue: {
@@ -70,14 +70,14 @@ const modelData = computed({
set: (val) => emit('update:modelValue', val),
});
/** 确保 list 属性存在 */
const ensureListExists = () => {
function ensureListExists() {
if (!props.modelValue.list) {
emit('update:modelValue', {
...props.modelValue,
list: [],
});
}
};
}
/** 是否所有文件都已上传完成 */
const isAllUploaded = computed(() => {
return (
@@ -93,7 +93,7 @@ const isAllUploaded = computed(() => {
* @param file 待上传的文件
* @returns 是否允许上传
*/
const beforeUpload = (file: any) => {
function beforeUpload(file: any) {
// 1.1 检查文件扩展名
const fileName = file.name.toLowerCase();
const fileExtension = fileName.slice(
@@ -112,7 +112,7 @@ const beforeUpload = (file: any) => {
// 2. 增加上传中的文件计数
uploadingCount.value++;
return true;
};
}
async function customRequest(info: UploadRequestOption<any>) {
const file = info.file as File;
const name = file?.name;
@@ -148,7 +148,7 @@ async function customRequest(info: UploadRequestOption<any>) {
*
* @param index 要移除的文件索引
*/
const removeFile = (index: number) => {
function removeFile(index: number) {
// 从列表中移除文件
const newList = [...props.modelValue.list];
newList.splice(index, 1);
@@ -157,10 +157,10 @@ const removeFile = (index: number) => {
...props.modelValue,
list: newList,
});
};
}
/** 下一步按钮处理 */
const handleNextStep = () => {
function handleNextStep() {
// 1.1 检查是否有文件上传
if (!modelData.value.list || modelData.value.list.length === 0) {
message.warning('请上传至少一个文件');
@@ -177,7 +177,7 @@ const handleNextStep = () => {
if (parentEl && typeof parentEl.exposed?.goToNextStep === 'function') {
parentEl.exposed.goToNextStep();
}
};
}
/** 初始化 */
onMounted(() => {
@@ -210,9 +210,9 @@ onMounted(() => {
/>
<div class="ant-upload-text text-[16px] text-[#606266]">
拖拽文件至此或者
<em class="cursor-pointer not-italic text-[#409eff]"
>选择文件</em
>
<em class="cursor-pointer not-italic text-[#409eff]">
选择文件
</em>
</div>
<div class="ant-upload-tip mt-10px text-[12px] text-[#909399]">
已支持 {{ supportedFileTypes.join('、') }}每个文件不超过

View File

@@ -56,7 +56,7 @@ provide('parent', getCurrentInstance()); // 提供 parent 给子组件使用
const tabs = useTabs();
/** 返回列表页 */
const handleBack = () => {
function handleBack() {
// 关闭当前页签
tabs.closeCurrentTab();
// 跳转到列表页,使用路径, 目前后端的路由 name 'name'+ menuId
@@ -66,10 +66,10 @@ const handleBack = () => {
knowledgeId: route.query.knowledgeId,
},
});
};
}
/** 初始化数据 */
const initData = async () => {
async function initData() {
if (route.query.knowledgeId) {
formData.value.knowledgeId = route.query.knowledgeId as any;
}
@@ -91,20 +91,20 @@ const initData = async () => {
// 进入下一步
goToNextStep();
}
};
}
/** 切换到下一步 */
const goToNextStep = () => {
function goToNextStep() {
if (currentStep.value < steps.length - 1) {
currentStep.value++;
}
};
}
/** 切换到上一步 */
const goToPrevStep = () => {
function goToPrevStep() {
if (currentStep.value > 0) {
currentStep.value--;
}
};
}
/** 初始化 */
onMounted(async () => {

View File

@@ -17,7 +17,7 @@ import {
updateKnowledgeDocumentStatus,
} from '#/api/ai/knowledge/document';
import { $t } from '#/locales';
import { CommonStatusEnum } from '#/utils/constants';
import { CommonStatusEnum } from '#/utils';
import { useGridColumns, useGridFormSchema } from './data';

View File

@@ -8,6 +8,7 @@ import {
CommonStatusEnum,
DICT_TYPE,
getDictOptions,
getRangePickerDefaultProps,
} from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
@@ -112,8 +113,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '创建时间',
component: 'RangePicker',
componentProps: {
placeholder: ['开始时间', '结束时间'],
valueFormat: 'YYYY-MM-DD HH:mm:ss',
...getRangePickerDefaultProps(),
allowClear: true,
},
},

View File

@@ -57,20 +57,20 @@ async function handleDelete(row: AiKnowledgeKnowledgeApi.KnowledgeVO) {
}
/** 文档按钮操作 */
const router = useRouter();
const handleDocument = (id: number) => {
function handleDocument(id: number) {
router.push({
name: 'AiKnowledgeDocument',
query: { knowledgeId: id },
});
};
}
/** 跳转到文档召回测试页面 */
const handleRetrieval = (id: number) => {
function handleRetrieval(id: number) {
router.push({
name: 'AiKnowledgeRetrieval',
query: { id },
});
};
}
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: {

View File

@@ -32,7 +32,7 @@ const queryParams = reactive({
});
/** 调用文档召回测试接口 */
const getRetrievalResult = async () => {
async function getRetrievalResult() {
if (!queryParams.content) {
message.warning('请输入查询文本');
return;
@@ -54,15 +54,15 @@ const getRetrievalResult = async () => {
} finally {
loading.value = false;
}
};
}
/** 展开/收起段落内容 */
const toggleExpand = (segment: any) => {
function toggleExpand(segment: any) {
segment.expanded = !segment.expanded;
};
}
/** 获取知识库信息 */
const getKnowledgeInfo = async (id: number) => {
async function getKnowledgeInfo(id: number) {
try {
const knowledge = await getKnowledge(id);
if (knowledge) {
@@ -71,7 +71,7 @@ const getKnowledgeInfo = async (id: number) => {
knowledge.similarityThreshold || queryParams.similarityThreshold;
}
} catch {}
};
}
/** 初始化 */
onMounted(() => {

View File

@@ -18,7 +18,7 @@ import {
updateKnowledgeSegmentStatus,
} from '#/api/ai/knowledge/segment';
import { $t } from '#/locales';
import { CommonStatusEnum } from '#/utils/constants';
import { CommonStatusEnum } from '#/utils';
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
@@ -93,9 +93,9 @@ const [Grid, gridApi] = useVbenVxeGrid({
});
/** 修改是否发布 */
const handleStatusChange = async (
async function handleStatusChange(
row: AiKnowledgeSegmentApi.KnowledgeSegmentVO,
) => {
) {
try {
// 修改状态的二次确认
const text = row.status ? '启用' : '禁用';
@@ -112,7 +112,8 @@ const handleStatusChange = async (
? CommonStatusEnum.DISABLE
: CommonStatusEnum.ENABLE;
}
};
}
onMounted(() => {
gridApi.formApi.setFieldValue('documentId', route.query.documentId);
});

View File

@@ -6,7 +6,7 @@ import { nextTick, onMounted, ref } from 'vue';
import { alert, Page } from '@vben/common-ui';
import { generateMindMap } from '#/api/ai/mindmap';
import { MindMapContentExample } from '#/utils/constants';
import { MindMapContentExample } from '#/utils';
import Left from './modules/Left.vue';
import Right from './modules/Right.vue';
@@ -21,13 +21,13 @@ const leftRef = ref<InstanceType<typeof Left>>(); // 左边组件
const rightRef = ref(); // 右边组件
/** 使用已有内容直接生成 */
const directGenerate = (existPrompt: string) => {
function directGenerate(existPrompt: string) {
isEnd.value = false; // 先设置为 false 再设置为 true让子组建的 watch 能够监听到
generatedContent.value = existPrompt;
isEnd.value = true;
};
}
/** 提交生成 */
const submit = (data: AiMindmapApi.AiMindMapGenerateReqVO) => {
function submit(data: AiMindmapApi.AiMindMapGenerateReqVO) {
isGenerating.value = true;
isStart.value = true;
isEnd.value = false;
@@ -59,13 +59,13 @@ const submit = (data: AiMindmapApi.AiMindMapGenerateReqVO) => {
},
ctrl: ctrl.value,
});
};
}
/** 停止 stream 生成 */
const stopStream = () => {
function stopStream() {
isGenerating.value = false;
isStart.value = false;
ctrl.value?.abort();
};
}
/** 初始化 */
onMounted(() => {

View File

@@ -3,7 +3,7 @@ import { reactive, ref } from 'vue';
import { Button, Textarea } from 'ant-design-vue';
import { MindMapContentExample } from '#/utils/constants';
import { MindMapContentExample } from '#/utils';
defineProps<{
isGenerating: boolean;

View File

@@ -7,11 +7,10 @@ import {
Toolbar,
Transformer,
} from '@vben/plugins/markmap';
import { downloadImageByCanvas } from '@vben/utils';
import { Button, Card, message } from 'ant-design-vue';
import { download } from '#/utils/download';
const props = defineProps<{
generatedContent: string; // 生成结果
isEnd: boolean; // 是否结束
@@ -85,7 +84,7 @@ const update = () => {
}
};
/** 处理内容 */
const processContent = (text: string) => {
function processContent(text: string) {
const arr: string[] = [];
const lines = text.split('\n');
for (let line of lines) {
@@ -97,21 +96,21 @@ const processContent = (text: string) => {
arr.push(line);
}
return arr.join('\n');
};
}
/** 下载图片download SVG to png file */
const downloadImage = () => {
function downloadImage() {
const svgElement = mindMapRef.value;
// 将 SVG 渲染到图片对象
const serializer = new XMLSerializer();
const source = `<?xml version="1.0" standalone="no"?>\r\n${serializer.serializeToString(svgRef.value!)}`;
const base64Url = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(source)}`;
download.image({
downloadImageByCanvas({
url: base64Url,
canvasWidth: svgElement?.offsetWidth,
canvasHeight: svgElement?.offsetHeight,
drawWithImageSize: false,
});
};
}
defineExpose({
scrollBottom() {
mdContainerRef.value?.scrollTo(0, mdContainerRef.value?.scrollHeight);

View File

@@ -2,6 +2,7 @@ import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {
@@ -26,8 +27,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '创建时间',
component: 'RangePicker',
componentProps: {
placeholder: ['开始时间', '结束时间'],
valueFormat: 'YYYY-MM-DD HH:mm:ss',
...getRangePickerDefaultProps(),
allowClear: true,
},
},

View File

@@ -75,13 +75,13 @@ const [Grid, gridApi] = useVbenVxeGrid({
},
} as VxeTableGridOptions<AiMindmapApi.MindMapVO>,
});
const openPreview = async (row: AiMindmapApi.MindMapVO) => {
async function openPreview(row: AiMindmapApi.MindMapVO) {
previewVisible.value = false;
drawerApi.open();
await nextTick();
previewVisible.value = true;
previewContent.value = row.generatedContent;
};
}
onMounted(async () => {
// 获得下拉数据
userList.value = await getSimpleUserList();

View File

@@ -109,9 +109,9 @@ onMounted(async () => {
/>
</template>
<template #keyId="{ row }">
<span>{{
apiKeyList.find((item) => item.id === row.keyId)?.name
}}</span>
<span>
{{ apiKeyList.find((item) => item.id === row.keyId)?.name }}
</span>
</template>
<template #actions="{ row }">
<TableAction

View File

@@ -1,7 +1,12 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils';
import {
CommonStatusEnum,
DICT_TYPE,
getDictOptions,
getRangePickerDefaultProps,
} from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
return [
@@ -64,8 +69,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '创建时间',
component: 'RangePicker',
componentProps: {
placeholder: ['开始时间', '结束时间'],
valueFormat: 'YYYY-MM-DD HH:mm:ss',
...getRangePickerDefaultProps(),
allowClear: true,
},
},

View File

@@ -8,7 +8,7 @@ import { Page } from '@vben/common-ui';
import List from './list/index.vue';
import Mode from './mode/index.vue';
defineOptions({ name: 'Index' });
defineOptions({ name: 'AiMusicIndex' });
const listRef = ref<Nullable<{ generateMusic: (...args: any) => void }>>(null);

View File

@@ -4,12 +4,11 @@ import type { Nullable } from '@vben/types';
import { inject, reactive, ref } from 'vue';
import { IconifyIcon } from '@vben/icons';
import { formatPast } from '@vben/utils';
import { Image, Slider } from 'ant-design-vue';
import { formatPast } from '#/utils/formatTime';
defineOptions({ name: 'Index' });
defineOptions({ name: 'AiMusicAudioBarIndex' });
const currentSong = inject('currentSong', {});

View File

@@ -9,7 +9,7 @@ import audioBar from './audioBar/index.vue';
import songCard from './songCard/index.vue';
import songInfo from './songInfo/index.vue';
defineOptions({ name: 'Index' });
defineOptions({ name: 'AiMusicListIndex' });
const currentType = ref('mine');
// loading 状态

View File

@@ -5,7 +5,7 @@ import { IconifyIcon } from '@vben/icons';
import { Image } from 'ant-design-vue';
defineOptions({ name: 'Index' });
defineOptions({ name: 'AiMusicSongCardIndex' });
defineProps({
songInfo: {

View File

@@ -3,7 +3,7 @@ import { inject } from 'vue';
import { Button, Card, Image } from 'ant-design-vue';
defineOptions({ name: 'Index' });
defineOptions({ name: 'AiMusicSongInfoIndex' });
const currentSong = inject('currentSong', {});
</script>

View File

@@ -5,7 +5,7 @@ import { Select, Switch, Textarea } from 'ant-design-vue';
import Title from '../title/index.vue';
defineOptions({ name: 'Desc' });
defineOptions({ name: 'AiMusicModeDesc' });
const formData = reactive({
desc: '',

View File

@@ -8,7 +8,7 @@ import { Button, Card, Radio } from 'ant-design-vue';
import desc from './desc.vue';
import lyric from './lyric.vue';
defineOptions({ name: 'Index' });
defineOptions({ name: 'AiMusicModeIndex' });
const emits = defineEmits(['generateMusic']);

View File

@@ -5,7 +5,7 @@ import { Button, Input, Select, Space, Tag, Textarea } from 'ant-design-vue';
import Title from '../title/index.vue';
defineOptions({ name: 'Lyric' });
defineOptions({ name: 'AiMusicModeLyric' });
const tags = ['rock', 'punk', 'jazz', 'soul', 'country', 'kidsmusic', 'pop'];

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup>
defineOptions({ name: 'Index' });
defineOptions({ name: 'AiMusicTitleIndex' });
defineProps({
title: {

View File

@@ -2,7 +2,7 @@ import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions } from '#/utils';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {
@@ -45,8 +45,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '创建时间',
component: 'RangePicker',
componentProps: {
placeholder: ['开始时间', '结束时间'],
valueFormat: 'YYYY-MM-DD HH:mm:ss',
...getRangePickerDefaultProps(),
allowClear: true,
},
},

View File

@@ -13,7 +13,7 @@ import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { deleteMusic, getMusicPage, updateMusic } from '#/api/ai/music';
import { getSimpleUserList } from '#/api/system/user';
import { $t } from '#/locales';
import { AiMusicStatusEnum } from '#/utils/constants';
import { AiMusicStatusEnum } from '#/utils';
import { useGridColumns, useGridFormSchema } from './data';

View File

@@ -1,7 +1,7 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE, getDictOptions } from '#/utils';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {
@@ -30,8 +30,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '创建时间',
component: 'RangePicker',
componentProps: {
placeholder: ['开始时间', '结束时间'],
valueFormat: 'YYYY-MM-DD HH:mm:ss',
...getRangePickerDefaultProps(),
allowClear: true,
},
},

View File

@@ -28,14 +28,14 @@ const basicInfoRef = ref<InstanceType<typeof BasicInfo>>();
const workflowDesignRef = ref<InstanceType<typeof WorkflowDesign>>();
/** 步骤校验函数 */
const validateBasic = async () => {
async function validateBasic() {
await basicInfoRef.value?.validate();
};
}
/** 工作流设计校验 */
const validateWorkflow = async () => {
async function validateWorkflow() {
await workflowDesignRef.value?.validate();
};
}
const currentStep = ref(-1); // 步骤控制。-1 用于,一开始全部不展示等当前页面数据初始化完成
@@ -60,7 +60,8 @@ provide('workflowData', workflowData);
/** 初始化数据 */
const actionType = route.params.type as string;
const initData = async () => {
async function initData() {
if (actionType === 'update') {
const workflowId = route.params.id as string;
formData.value = await getWorkflow(workflowId);
@@ -79,10 +80,10 @@ const initData = async () => {
// 设置当前步骤
currentStep.value = 0;
};
}
/** 校验所有步骤数据是否完整 */
const validateAllSteps = async () => {
async function validateAllSteps() {
// 基本信息校验
try {
await validateBasic();
@@ -99,10 +100,10 @@ const validateAllSteps = async () => {
throw new Error('请完善工作流信息');
}
return true;
};
}
/** 保存操作 */
const handleSave = async () => {
async function handleSave() {
try {
// 保存前校验所有步骤的数据
await validateAllSteps();
@@ -124,10 +125,10 @@ const handleSave = async () => {
console.error('保存失败:', error);
message.warning(error.message || '请完善所有步骤的必填信息');
}
};
}
/** 发布操作 */
const handleDeploy = async () => {
async function handleDeploy() {
try {
// 修改场景下直接发布,新增场景下需要先确认
if (!formData.value.id) {
@@ -158,10 +159,10 @@ const handleDeploy = async () => {
console.error('发布失败:', error);
message.warning(error.message || '发布失败');
}
};
}
/** 步骤切换处理 */
const handleStepClick = async (index: number) => {
async function handleStepClick(index: number) {
try {
if (index !== 0) {
await validateBasic();
@@ -176,17 +177,17 @@ const handleStepClick = async (index: number) => {
console.error('步骤切换失败:', error);
message.warning('请先完善当前步骤必填信息');
}
};
}
const tabs = useTabs();
/** 返回列表页 */
const handleBack = () => {
function handleBack() {
// 关闭当前页签
tabs.closeCurrentTab();
// 跳转到列表页,使用路径, 目前后端的路由 name 'name'+ menuId
router.push({ path: '/ai/workflow' });
};
}
/** 初始化 */
onMounted(async () => {

View File

@@ -18,9 +18,9 @@ const rules: Record<string, Rule[]> = {
};
/** 表单校验 */
const validate = async () => {
async function validate() {
await formRef.value?.validate();
};
}
defineExpose({ validate });
</script>

View File

@@ -4,11 +4,12 @@ import type { Ref } from 'vue';
import { inject, ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
import { isNumber } from '@vben/utils';
import { Button, Input, Select } from 'ant-design-vue';
import { testWorkflow } from '#/api/ai/workflow';
import Tinyflow from '#/components/tinyflow/tinyflow.vue';
import { Tinyflow } from '#/components/tinyflow';
defineProps<{
provider: any;
@@ -28,26 +29,26 @@ const [Drawer, drawerApi] = useVbenDrawer({
modal: false,
});
/** 展示工作流测试抽屉 */
const testWorkflowModel = () => {
function testWorkflowModel() {
drawerApi.open();
const startNode = getStartNode();
// 获取参数定义
const parameters = startNode.data?.parameters || [];
const paramDefinitions = {};
const paramDefinitions: Record<string, any> = {};
// 加入参数选项方便用户添加非必须参数
parameters.forEach((param) => {
parameters.forEach((param: any) => {
paramDefinitions[param.name] = param;
});
function mergeIfRequiredButNotSet(target) {
function mergeIfRequiredButNotSet(target: any) {
const needPushList = [];
for (const key in paramDefinitions) {
const param = paramDefinitions[key];
if (param.required) {
const item = target.find((item) => item.key === key);
const item = target.find((item: any) => item.key === key);
if (!item) {
needPushList.push({
@@ -63,10 +64,10 @@ const testWorkflowModel = () => {
mergeIfRequiredButNotSet(params4Test.value);
paramsOfStartNode.value = paramDefinitions;
};
}
/** 运行流程 */
const goRun = async () => {
async function goRun() {
try {
const val = tinyflowRef.value.getData();
loading.value = true;
@@ -77,13 +78,13 @@ const goRun = async () => {
// 获取参数定义
const parameters = startNode.data?.parameters || [];
const paramDefinitions = {};
parameters.forEach((param) => {
const paramDefinitions: Record<string, any> = {};
parameters.forEach((param: any) => {
paramDefinitions[param.name] = param.dataType;
});
// 参数类型转换
const convertedParams = {};
const convertedParams: Record<string, any> = {};
for (const { key, value } of params4Test.value) {
const paramKey = key.trim();
if (!paramKey) continue;
@@ -95,8 +96,8 @@ const goRun = async () => {
try {
convertedParams[paramKey] = convertParamValue(value, dataType);
} catch (error_) {
throw new Error(`参数 ${paramKey} 转换失败: ${error_.message}`);
} catch (error: any) {
throw new Error(`参数 ${paramKey} 转换失败: ${error.message}`);
}
}
@@ -107,42 +108,42 @@ const goRun = async () => {
const response = await testWorkflow(data);
testResult.value = response;
} catch (error_) {
} catch (error: any) {
error.value =
error_.response?.data?.message || '运行失败,请检查参数和网络连接';
error.response?.data?.message || '运行失败,请检查参数和网络连接';
} finally {
loading.value = false;
}
};
}
/** 获取开始节点 */
const getStartNode = () => {
function getStartNode() {
const val = tinyflowRef.value.getData();
const startNode = val.nodes.find((node) => node.type === 'startNode');
const startNode = val.nodes.find((node: any) => node.type === 'startNode');
if (!startNode) {
throw new Error('流程缺少开始节点');
}
return startNode;
};
}
/** 添加参数项 */
const addParam = () => {
function addParam() {
params4Test.value.push({ key: '', value: '' });
};
}
/** 删除参数项 */
const removeParam = (index) => {
function removeParam(index: number) {
params4Test.value.splice(index, 1);
};
}
/** 类型转换函数 */
const convertParamValue = (value, dataType) => {
function convertParamValue(value: string, dataType: string) {
if (value === '') return null; // 空值处理
switch (dataType) {
case 'Number': {
const num = Number(value);
if (isNaN(num)) throw new Error('非数字格式');
if (!isNumber(num)) throw new Error('非数字格式');
return num;
}
case 'String': {
@@ -157,24 +158,24 @@ const convertParamValue = (value, dataType) => {
case 'Object': {
try {
return JSON.parse(value);
} catch (error_) {
throw new Error(`JSON格式错误: ${error_.message}`);
} catch (error: any) {
throw new Error(`JSON格式错误: ${error.message}`);
}
}
default: {
throw new Error(`不支持的类型: ${dataType}`);
}
}
};
}
/** 表单校验 */
const validate = async () => {
async function validate() {
// 获取最新的流程数据
if (!workflowData.value) {
throw new Error('请设计流程');
}
workflowData.value = tinyflowRef.value.getData();
return true;
};
}
defineExpose({ validate });
</script>

View File

@@ -6,8 +6,12 @@ import { ref } from 'vue';
import { createReusableTemplate } from '@vueuse/core';
import { Button, message, Textarea } from 'ant-design-vue';
import { DICT_TYPE, getIntDictOptions } from '#/utils';
import { AiWriteTypeEnum, WriteExample } from '#/utils/constants';
import {
AiWriteTypeEnum,
DICT_TYPE,
getIntDictOptions,
WriteExample,
} from '#/utils';
import Tag from './Tag.vue';
@@ -33,19 +37,19 @@ function omit(obj: Record<string, any>, keysToOmit: string[]) {
return result;
}
/** 点击示例的时候,将定义好的文章作为示例展示出来 */
const example = (type: 'reply' | 'write') => {
function example(type: 'reply' | 'write') {
formData.value = {
...initData,
...omit(WriteExample[type], ['data']),
};
emit('example', type);
};
}
/** 重置,将表单值作为初选值 */
const reset = () => {
function reset() {
formData.value = { ...initData };
emit('reset');
};
}
const selectedTab = ref<TabType>(AiWriteTypeEnum.WRITING);
const tabs: {
@@ -83,7 +87,7 @@ const formData = ref<AiWriteApi.WriteVO>({ ...initData });
/** 用来记录切换之前所填写的数据,切换的时候给赋值回来 */
const recordFormData = {} as Record<AiWriteTypeEnum, AiWriteApi.WriteVO>;
/** 切换tab */
const switchTab = (value: TabType) => {
function switchTab(value: TabType) {
if (value !== selectedTab.value) {
// 保存之前的久数据
recordFormData[selectedTab.value] = formData.value;
@@ -91,10 +95,10 @@ const switchTab = (value: TabType) => {
// 将之前的旧数据赋值回来
formData.value = { ...initData, ...recordFormData[value] };
}
};
}
/** 提交写作 */
const submit = () => {
function submit() {
if (selectedTab.value === 2 && !formData.value.originalContent) {
message.warning('请输入原文');
return;
@@ -111,7 +115,7 @@ const submit = () => {
/** 使用选中 tab 值覆盖当前的 type 类型 */
type: selectedTab.value,
});
};
}
</script>
<template>

View File

@@ -40,9 +40,9 @@ defineExpose({
/** 点击复制的时候复制内容 */
const showCopy = computed(() => props.content && !props.isWriting); // 是否展示复制按钮,在生成内容完成的时候展示
const copyContent = () => {
function copyContent() {
copy(props.content);
};
}
/** 复制成功的时候 copied.value 为 true */
watch(copied, (val) => {

View File

@@ -6,7 +6,7 @@ import { nextTick, ref } from 'vue';
import { alert, Page } from '@vben/common-ui';
import { writeStream } from '#/api/ai/write';
import { WriteExample } from '#/utils/constants';
import { WriteExample } from '#/utils';
import Left from './components/Left.vue';
import Right from './components/Right.vue';
@@ -16,15 +16,15 @@ const isWriting = ref(false); // 是否正在写作中
const abortController = ref<AbortController>(); // // 写作进行中 abort 控制器(控制 stream 写作)
/** 停止 stream 生成 */
const stopStream = () => {
function stopStream() {
abortController.value?.abort();
isWriting.value = false;
};
}
/** 执行写作 */
const rightRef = ref<InstanceType<typeof Right>>();
const submit = (data: Partial<AiWriteApi.WriteVO>) => {
function submit(data: Partial<AiWriteApi.WriteVO>) {
abortController.value = new AbortController();
writeResult.value = '';
isWriting.value = true;
@@ -51,17 +51,17 @@ const submit = (data: Partial<AiWriteApi.WriteVO>) => {
throw error;
},
});
};
}
/** 点击示例触发 */
const handleExampleClick = (type: keyof typeof WriteExample) => {
function handleExampleClick(type: keyof typeof WriteExample) {
writeResult.value = WriteExample[type].data;
};
}
/** 点击重置的时候清空写作的结果*/
const reset = () => {
function reset() {
writeResult.value = '';
};
}
</script>
<template>

View File

@@ -2,7 +2,7 @@ import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions } from '#/utils';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {
@@ -40,8 +40,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '创建时间',
component: 'RangePicker',
componentProps: {
placeholder: ['开始时间', '结束时间'],
valueFormat: 'YYYY-MM-DD HH:mm:ss',
...getRangePickerDefaultProps(),
allowClear: true,
},
},

View File

@@ -3,7 +3,12 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { z } from '#/adapter/form';
import { getSimpleUserList } from '#/api/system/user';
import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils';
import {
CommonStatusEnum,
DICT_TYPE,
getDictOptions,
getRangePickerDefaultProps,
} from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
@@ -87,7 +92,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '创建时间',
component: 'RangePicker',
componentProps: {
placeholder: ['开始时间', '结束时间'],
...getRangePickerDefaultProps(),
allowClear: true,
},
},

View File

@@ -2,7 +2,12 @@ import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { z } from '#/adapter/form';
import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils';
import {
CommonStatusEnum,
DICT_TYPE,
getDictOptions,
getRangePickerDefaultProps,
} from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
@@ -74,8 +79,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '创建时间',
component: 'RangePicker',
componentProps: {
placeholder: ['开始时间', '结束时间'],
valueFormat: 'YYYY-MM-DD HH:mm:ss',
...getRangePickerDefaultProps(),
allowClear: true,
},
},

View File

@@ -71,6 +71,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
component: 'RangePicker',
componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
},
];

View File

@@ -77,6 +77,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
component: 'RangePicker',
componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
},
];

View File

@@ -55,7 +55,6 @@ export function useGridFormSchema(
component: 'RangePicker',
componentProps: {
...getRangePickerDefaultProps(),
placeholder: ['开始日期', '结束日期'],
allowClear: true,
},
},
@@ -65,7 +64,6 @@ export function useGridFormSchema(
component: 'RangePicker',
componentProps: {
...getRangePickerDefaultProps(),
placeholder: ['开始日期', '结束日期'],
allowClear: true,
},
},

View File

@@ -21,6 +21,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
component: 'RangePicker',
componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
},
];

View File

@@ -50,13 +50,13 @@ export function useGridFormSchema(): VbenFormSchema[] {
allowClear: true,
},
},
// 发起时间
{
fieldName: 'createTime',
label: '发起时间',
component: 'RangePicker',
componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
},
];

View File

@@ -21,6 +21,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
component: 'RangePicker',
componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
},
];

View File

@@ -56,6 +56,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
component: 'RangePicker',
componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
},
];