diff --git a/.;.swp b/.;.swp new file mode 100644 index 000000000..7fddcd586 Binary files /dev/null and b/.;.swp differ diff --git a/packages/core/client/src/locale/en_US.json b/packages/core/client/src/locale/en_US.json index a91fe2f9e..aa51e9fb9 100644 --- a/packages/core/client/src/locale/en_US.json +++ b/packages/core/client/src/locale/en_US.json @@ -831,5 +831,10 @@ "Load": "Load", "Dump": "Dump", "Chang on Parent": "Chang on Parent", - "Please enter search content": "Please enter search content" + "Please enter search content": "Please enter search content", + "Is DownLoad":"Is DownLoad", + "Show Data":"Show Data", + "Setting Down Title":"Setting Down Title", + "The current return type is not a document type":"The current return type is not a document type", + "Test Data":"Test Data" } diff --git a/packages/core/client/src/locale/zh-CN.json b/packages/core/client/src/locale/zh-CN.json index d1d909ca0..237a68cb0 100644 --- a/packages/core/client/src/locale/zh-CN.json +++ b/packages/core/client/src/locale/zh-CN.json @@ -934,5 +934,10 @@ "Sorry, the page you visited does not exist.": "对不起,您访问的页面不存在。", "Back Home": "回到主页", "Chang on Parent": "选择父级", - "Please enter search content": "请输入查询内容" + "Please enter search content": "请输入查询内容", + "Is DownLoad":"下载文件", + "Show Data":"显示数据", + "Setting Down Title":"设置文件名称", + "The current return type is not a document type":"当前返回类型不是文档类型", + "Test Data":"测试数据" } diff --git a/packages/core/client/src/schema-component/antd/action/Action.Designer.tsx b/packages/core/client/src/schema-component/antd/action/Action.Designer.tsx index e78ed1005..6b859552b 100644 --- a/packages/core/client/src/schema-component/antd/action/Action.Designer.tsx +++ b/packages/core/client/src/schema-component/antd/action/Action.Designer.tsx @@ -787,6 +787,102 @@ export function SecondConFirm() { /> ); } +export function IsDownLoad() { + const { dn } = useDesignable(); + const fieldSchema = useFieldSchema(); + const { t } = useTranslation(); + + return ( + { + if (!fieldSchema?.['x-action-settings']?.onSuccess) { + fieldSchema['x-action-settings'] = { + ...fieldSchema?.['x-action-settings'], + onSuccess: { + down: false, + }, + }; + } + fieldSchema['x-action-settings'].onSuccess.down = value; + + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-action-settings': { ...fieldSchema['x-action-settings'] }, + }, + }); + }} + /> + ); +} +export function ShowData() { + const { dn } = useDesignable(); + const fieldSchema = useFieldSchema(); + const { t } = useTranslation(); + const field = useField(); + return ( + { + if (!fieldSchema?.['x-component-props']) { + fieldSchema['x-component-props'] = { showData: false }; + } + fieldSchema['x-component-props'].showData = value; + field.componentProps = fieldSchema['x-component-props']; + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-component-props': { ...fieldSchema['x-component-props'] }, + }, + }); + }} + /> + ); +} + +export function SettingDownTitle() { + const fieldSchema = useFieldSchema(); + const { dn } = useDesignable(); + const { t } = useTranslation(); + return ( + { + if (!fieldSchema?.['x-action-settings']) { + fieldSchema['x-action-settings'] = { + onSussess: { + downTitle: title, + }, + }; + } else { + fieldSchema['x-action-settings']['onSuccess'] = { + ...fieldSchema['x-action-settings']?.['onSuccess'], + downTitle: title, + }; + } + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-action-settings': { ...fieldSchema['x-action-settings'] }, + }, + }); + }} + schema={{ + type: 'item', + title: t('Setting Down Title'), + properties: { + title: { + 'x-component': 'Input', + default: fieldSchema['x-action-settings']?.['onSuccess']?.downTitle || 'document.docx', + }, + }, + }} + /> + ); +} /** * @deprecated diff --git a/packages/plugins/@tachybase/plugin-custom-request/package.json b/packages/plugins/@tachybase/plugin-custom-request/package.json index f8c94a044..5f5ff3b44 100644 --- a/packages/plugins/@tachybase/plugin-custom-request/package.json +++ b/packages/plugins/@tachybase/plugin-custom-request/package.json @@ -12,6 +12,7 @@ "@tachybase/components": "workspace:*", "@tachybase/schema": "workspace:*", "antd": "5.19.1", + "file-saver": "^2.0.5", "lodash": "~4.17.21", "react-i18next": "^14.1.2", "react-router-dom": "~6.25.1" diff --git a/packages/plugins/@tachybase/plugin-custom-request/src/client/hooks/useCustomizeRequestActionProps.ts b/packages/plugins/@tachybase/plugin-custom-request/src/client/hooks/useCustomizeRequestActionProps.ts index 38427ad84..3f95cd85b 100644 --- a/packages/plugins/@tachybase/plugin-custom-request/src/client/hooks/useCustomizeRequestActionProps.ts +++ b/packages/plugins/@tachybase/plugin-custom-request/src/client/hooks/useCustomizeRequestActionProps.ts @@ -11,8 +11,11 @@ import { useField, useFieldSchema, useForm } from '@tachybase/schema'; import { isURL } from '@tachybase/utils/client'; import { App } from 'antd'; +import { saveAs } from 'file-saver'; import { useNavigate } from 'react-router-dom'; +import { useTranslation } from '../locale'; + export const useCustomizeRequestActionProps = () => { const apiClient = useAPIClient(); const navigate = useNavigate(); @@ -26,6 +29,7 @@ export const useCustomizeRequestActionProps = () => { const actionField = useField(); const { setVisible } = useActionContext(); const { modal, message } = App.useApp(); + const { t } = useTranslation(); return { async onClick() { const { skipValidator, onSuccess } = actionSchema?.['x-action-settings'] ?? {}; @@ -42,9 +46,10 @@ export const useCustomizeRequestActionProps = () => { actionField.data ??= {}; actionField.data.loading = true; try { - await apiClient.request({ + const res = (await apiClient.request({ url: `/customRequests:send/${fieldSchema['x-uid']}`, method: 'POST', + responseType: onSuccess?.down ? 'blob' : 'json', data: { currentRecord: { id: record[getPrimaryKey()], @@ -52,7 +57,16 @@ export const useCustomizeRequestActionProps = () => { data: formValues, }, }, - }); + })) as any; + const headerContentType = res.headers.getContentType(); + if (onSuccess?.down) { + if (headerContentType === 'application/octet-stream') { + const downTitle = onSuccess.downTitle; + saveAs(res.data, downTitle); + } else { + message.error(t('The current return type is not a document type')); + } + } actionField.data.loading = false; if (!(resource instanceof TableFieldResource)) { __parent?.service?.refresh?.(); @@ -61,29 +75,39 @@ export const useCustomizeRequestActionProps = () => { if (xAction === 'customize:form:request') { setVisible?.(false); } - if (!onSuccess?.successMessage) { - return; - } - if (onSuccess?.manualClose) { - modal.success({ - title: compile(onSuccess?.successMessage), - onOk: async () => { - if (onSuccess?.redirecting && onSuccess?.redirectTo) { - if (isURL(onSuccess.redirectTo)) { - window.location.href = onSuccess.redirectTo; - } else { - navigate(onSuccess.redirectTo); - } - } - }, + + if (actionSchema?.['x-component-props']?.showData) { + modal.confirm({ + title: 'Test Data', + content: `${JSON.stringify(res.data)}`, + okText: t('Confirm'), + cancelText: t('Cancel'), }); } else { - message.success(compile(onSuccess?.successMessage)); - if (onSuccess?.redirecting && onSuccess?.redirectTo) { - if (isURL(onSuccess.redirectTo)) { - window.location.href = onSuccess.redirectTo; - } else { - navigate(onSuccess.redirectTo); + if (!onSuccess?.successMessage) { + return; + } + if (onSuccess?.manualClose) { + modal.success({ + title: compile(onSuccess?.successMessage), + onOk: async () => { + if (onSuccess?.redirecting && onSuccess?.redirectTo) { + if (isURL(onSuccess.redirectTo)) { + window.location.href = onSuccess.redirectTo; + } else { + navigate(onSuccess.redirectTo); + } + } + }, + }); + } else { + message.success(compile(onSuccess?.successMessage)); + if (onSuccess?.redirecting && onSuccess?.redirectTo) { + if (isURL(onSuccess.redirectTo)) { + window.location.href = onSuccess.redirectTo; + } else { + navigate(onSuccess.redirectTo); + } } } } diff --git a/packages/plugins/@tachybase/plugin-custom-request/src/client/schemaSettings.ts b/packages/plugins/@tachybase/plugin-custom-request/src/client/schemaSettings.ts index 64b659788..dcd99ca73 100644 --- a/packages/plugins/@tachybase/plugin-custom-request/src/client/schemaSettings.ts +++ b/packages/plugins/@tachybase/plugin-custom-request/src/client/schemaSettings.ts @@ -1,13 +1,17 @@ import { AfterSuccess, ButtonEditor, + IsDownLoad, RemoveButton, SchemaSettings, SchemaSettingsLinkageRules, SecondConFirm, + SettingDownTitle, + ShowData, useCollection, useSchemaToolbar, } from '@tachybase/client'; +import { useFieldSchema } from '@tachybase/schema'; import { CustomRequestACL, CustomRequestSettingsItem } from './components/CustomRequestActionDesigner'; @@ -41,6 +45,23 @@ export const customizeCustomRequestActionSettings = new SchemaSettings({ name: 'secondConFirm', Component: SecondConFirm, }, + { + name: 'isDownLoad', + Component: IsDownLoad, + }, + { + name: 'settingDownTitle', + Component: SettingDownTitle, + useVisible() { + const fieldSchema = useFieldSchema(); + const down = fieldSchema?.['x-action-settings']?.onSuccess?.down; + return down; + }, + }, + { + name: 'showData', + Component: ShowData, + }, { name: 'afterSuccessfulSubmission', Component: AfterSuccess, diff --git a/packages/plugins/@tachybase/plugin-custom-request/src/server/actions/send.ts b/packages/plugins/@tachybase/plugin-custom-request/src/server/actions/send.ts index a9317d793..86dbdb4b5 100644 --- a/packages/plugins/@tachybase/plugin-custom-request/src/server/actions/send.ts +++ b/packages/plugins/@tachybase/plugin-custom-request/src/server/actions/send.ts @@ -1,3 +1,5 @@ +import fs from 'fs'; +import http from 'http'; import { Context, Next } from '@tachybase/actions'; import { appendArrayColumn } from '@tachybase/evaluators'; import { parse } from '@tachybase/utils'; @@ -160,10 +162,14 @@ export async function send(this: CustomRequestPlugin, ctx: Context, next: Next) ); try { - ctx.body = await axios(axiosRequestConfig).then((res) => { - this.logger.info(`custom-request:send:${filterByTk} success`); - return res.data; - }); + const res = await axios({ ...axiosRequestConfig, responseType: 'stream' }); + ctx.set('Content-Type', `${res.headers['content-type']}`); + ctx.set('Content-disposition', `${res.headers['content-disposition']}`); + this.logger.info(`custom-request:send:${filterByTk} success`); + + const readable = res.data as http.IncomingMessage; + + ctx.body = readable; } catch (err) { if (axios.isAxiosError(err)) { ctx.status = err.response?.status || 500; diff --git a/packages/plugins/@tachybase/plugin-print-template/src/server/actions/printTemplates.ts b/packages/plugins/@tachybase/plugin-print-template/src/server/actions/printTemplates.ts index 242ae25b6..5f8877f69 100644 --- a/packages/plugins/@tachybase/plugin-print-template/src/server/actions/printTemplates.ts +++ b/packages/plugins/@tachybase/plugin-print-template/src/server/actions/printTemplates.ts @@ -18,7 +18,6 @@ export const generate = async (ctx: Context) => { }, appends: ['template'], }); - console.log(template.get()); const rawTemplate = template.get(); const templatePath = path.join(process.env.PWD, rawTemplate.template[0].get().url); @@ -27,18 +26,8 @@ export const generate = async (ctx: Context) => { try { // 生成定制的 docx 文件 const buffer = generateDocxFromTemplate(templatePath, data); - - // 创建一个可读流 - const readableStream = new Readable({ - read(size) { - this.push(buffer); - this.push(null); - }, - }); - ctx.withoutDataWrapping = true; - ctx.set('Content-Type', 'application/octet-stream'); - ctx.body = readableStream; + ctx.body = buffer; } catch (error) { console.error('Error:', error); ctx.status = 500; @@ -66,7 +55,6 @@ export const getTags = async (ctx: Context) => { // 获取所有占位符 const allTags = iModule.getAllTags(); - console.log('All tags in the document:', allTags); // 将 tags 转换为 JSON 格式的字符串 const tagsJson = JSON.stringify(allTags, null, 2); diff --git a/packages/plugins/@tachybase/plugin-print-template/src/server/plugin.ts b/packages/plugins/@tachybase/plugin-print-template/src/server/plugin.ts index 652c7dadd..dd98920ad 100644 --- a/packages/plugins/@tachybase/plugin-print-template/src/server/plugin.ts +++ b/packages/plugins/@tachybase/plugin-print-template/src/server/plugin.ts @@ -16,6 +16,7 @@ export class PluginPrintTemplateServer extends Plugin { getTags, }, }); + this.app.acl.allow('printTemplates', '*', 'public'); } async install() {} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1cb8a0a9c..addc49df3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2454,6 +2454,9 @@ importers: antd: specifier: 5.19.1 version: 5.19.1(react-dom@18.3.1)(react@18.3.1) + file-saver: + specifier: ^2.0.5 + version: 2.0.5 lodash: specifier: ~4.17.21 version: 4.17.21