diff --git a/2.Design/screens/web-editor-preview.png b/2.Design/screens/web-editor-preview.png new file mode 100644 index 0000000..4fd4488 Binary files /dev/null and b/2.Design/screens/web-editor-preview.png differ diff --git a/2.Design/screens/web-editor-write.png b/2.Design/screens/web-editor-write.png new file mode 100644 index 0000000..ea9649e Binary files /dev/null and b/2.Design/screens/web-editor-write.png differ diff --git a/web/e2e/shots-rich.mjs b/web/e2e/shots-rich.mjs new file mode 100644 index 0000000..5ff2f5a --- /dev/null +++ b/web/e2e/shots-rich.mjs @@ -0,0 +1,103 @@ +/** + * 截图:详情抽屉里的 Markdown 编辑器(写作态 + 预览态)。 + * 只用于留存界面现状,不做断言。 + */ +import { chromium } from "playwright-core"; + +const API = "http://127.0.0.1:8100/api/v1"; +const WEB = "http://127.0.0.1:5180"; +const stamp = String(Date.now()).slice(-7); +const phone = `137${stamp}0`; + +async function call(method, path, body, token) { + const headers = { "content-type": "application/json" }; + if (token) headers.authorization = `Bearer ${token}`; + if (method !== "GET") headers["idempotency-key"] = `shot-${Math.random()}`; + const res = await fetch(`${API}${path}`, { + method, + headers, + body: body ? JSON.stringify(body) : undefined, + }); + const json = JSON.parse(await res.text()); + if (json.code !== 0) throw new Error(`${path} ${json.code} ${json.message}`); + return json.data; +} + +const PNG = Buffer.from( + "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAAXklEQVR42u3BAQ0AAADCoPdPbQ8H" + + "FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4G8wAAAB" + + "T2nSywAAAABJRU5ErkJggg==", + "base64", +); + +await call("POST", "/auth/sms/send", { phone }); +const login = await call("POST", "/auth/login", { phone, code: "123456" }); +const token = login.tokens.access_token; +const ws = await call("POST", "/workspaces", { name: "远航工作室" }, token); + +const body = [ + "**快递只收顺丰**,其它快递到不了前台。", + "", + "寄之前先拍一张照片存档,并在下面写上单号。", + "", + "1. 抬头写「远航科技(上海)有限公司」", + "2. 备注「报销 - 十月」", + "3. 底单留在文件袋里", +].join("\n"); + +const task = await call( + "POST", + `/workspaces/${ws.id}/items`, + { title: "把十月报销单寄给财务", body_md: body, priority: 2 }, + token, +); + +const form = new FormData(); +form.append("file", new Blob([PNG], { type: "image/png" }), "底单照片.png"); +const uploaded = await fetch( + `${API}/workspaces/${ws.id}/items/${task.id}/attachments`, + { method: "POST", headers: { authorization: `Bearer ${token}` }, body: form }, +); +const att = (await uploaded.json()).data; + +await call( + "PATCH", + `/workspaces/${ws.id}/items/${task.id}`, + { + version: task.version, + body_md: `${body}\n\n![底单照片.png](/api/v1/workspaces/${ws.id}/attachments/${att.id}/raw?token=${token})`, + }, + token, +); + +const browser = await chromium.launch({ + executablePath: `${process.env.LOCALAPPDATA}\\ms-playwright\\chromium-1223\\chrome-win64\\chrome.exe`, +}); +const context = await browser.newContext({ viewport: { width: 1440, height: 960 } }); +const page = await context.newPage(); + +await page.goto(`${WEB}/login`); +await page.evaluate( + ([access, refresh]) => { + localStorage.setItem("dadao.access", access); + localStorage.setItem("dadao.refresh", refresh); + }, + [token, login.tokens.refresh_token], +); +await page.goto(`${WEB}/w/${ws.id}`); +await page.getByRole("heading", { name: "任务" }).waitFor(); +await page.getByRole("button", { name: "全部", exact: true }).click(); +await page.getByRole("button", { name: "把十月报销单寄给财务", exact: true }).click(); +const drawer = page.getByRole("dialog"); +await drawer.waitFor(); +await page.waitForTimeout(600); +await page.screenshot({ path: "../2.Design/screens/web-editor-write.png" }); + +await drawer.getByRole("button", { name: "预览" }).click(); +await page.waitForTimeout(900); +await page.screenshot({ path: "../2.Design/screens/web-editor-preview.png" }); + +await context.close(); +await browser.close(); +console.log("shots saved"); diff --git a/web/src/components/TaskDetail.tsx b/web/src/components/TaskDetail.tsx index d4b51f3..0f0b25c 100644 --- a/web/src/components/TaskDetail.tsx +++ b/web/src/components/TaskDetail.tsx @@ -475,7 +475,7 @@ export function TaskDetail({ value={tags} onChange={(e) => setTags(e.target.value)} onBlur={() => void saveTags()} - placeholder="周报 客户" + placeholder="空格分隔,例如:财务 十月" /> {item.tags.length > 0 ? ( diff --git a/web/src/index.css b/web/src/index.css index dd3a13b..880c195 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -104,7 +104,7 @@ placeholder:text-ink-400; } .label { - @apply mb-1.5 block text-xs font-medium tracking-wide text-ink-500; + @apply mb-1.5 block text-xs font-medium tracking-wide text-ink-600; } /* —— 徽标 —— */