This commit is contained in:
Timi
2026-01-28 16:35:31 +08:00
parent 965743be38
commit e67d9eeecc
13 changed files with 331 additions and 6 deletions

View File

@ -0,0 +1,24 @@
import { Network } from "../utils/Network";
/**
* Tool 工具 API
*/
export class ToolApi {
/**
* 获取备忘录内容
*/
static getMemo(): Promise<string> {
return Network.get<string>("/journal/tool/memo");
}
/**
* 更新备忘录内容
*
* @param data - 备忘录内容
*/
static updateMemo(data: string): Promise<void> {
return Network.post<void>("/journal/tool/memo/update", {
data
});
}
}

View File

@ -10,6 +10,7 @@
"pages/main/journal/editor/index", "pages/main/journal/editor/index",
"pages/main/journal/map/index", "pages/main/journal/map/index",
"pages/main/journal/date/index", "pages/main/journal/date/index",
"pages/main/other/memo/index",
"pages/main/other/portfolio/index", "pages/main/other/portfolio/index",
"pages/main/travel/detail/index", "pages/main/travel/detail/index",
"pages/main/travel/editor/index", "pages/main/travel/editor/index",

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

View File

@ -1,12 +1,12 @@
const envArgs = { const envArgs = {
develop: { develop: {
url: "http://localhost:8091" // url: "http://localhost:8091"
// url: "https://api.imyeyu.dev" // url: "https://api.imyeyu.dev"
// url: "https://api.imyeyu.com" // url: "https://api.imyeyu.com"
// url: "http://192.168.3.123:8091" // url: "http://192.168.3.123:8091"
// url: "http://192.168.3.137:8091" // url: "http://192.168.3.137:8091"
// url: "http://192.168.3.173:8091" // url: "http://192.168.3.173:8091"
// url: "http://192.168.3.174:8091" url: "http://192.168.3.174:8091"
}, },
trial: { trial: {
url: "https://api.imyeyu.com" url: "https://api.imyeyu.com"

View File

@ -2,7 +2,7 @@
<scroll-view class="index" scroll-y type="list"> <scroll-view class="index" scroll-y type="list">
<view class="container"> <view class="container">
<view class="header"> <view class="header">
<image class="logo" src="/assets/image/logo.png"></image> <image class="logo" src="/assets/image/logo.jpg"></image>
<text> <text>
<text class="name gao">小糕</text> <text class="name gao">小糕</text>
<text>和</text> <text>和</text>

View File

@ -0,0 +1,7 @@
{
"usingComponents": {
"t-icon": "tdesign-miniprogram/icon/icon",
"t-navbar": "tdesign-miniprogram/navbar/navbar"
},
"disableScroll": true
}

View File

@ -0,0 +1,66 @@
// pages/main/other/memo/index.less
.memo {
width: 100%;
min-height: 100vh;
position: relative;
.content {
width: 100%;
min-height: 100vh;
position: relative;
}
.status-card {
padding: 2rem 1.5rem;
display: flex;
justify-content: center;
}
.empty-hint {
padding: 1.5rem 1rem 0 1rem;
}
.container {
top: 0;
left: 0;
width: 100%;
position: absolute;
.editor {
width: 100%;
height: 100%;
border: .0625rem solid var(--theme-border-light);
padding: 1rem 1rem 2rem 1rem;
overflow: auto;
font-size: 1rem;
background: var(--theme-bg-primary);
box-sizing: border-box;
line-height: 1.5;
}
}
.toolbar {
left: 0;
width: 100%;
right: 100%;
height: 3.125rem;
bottom: 0;
border: .0625rem solid var(--theme-border-light);
padding: 0 1rem;
display: flex;
position: fixed;
background: var(--theme-bg-primary);
box-sizing: border-box;
align-items: center;
border-left: none;
border-right: none;
justify-content: space-between;
.icon {
&.active {
color: var(--theme-wx);
}
}
}
}

View File

@ -0,0 +1,162 @@
// 备忘录页面逻辑
import { ToolApi } from "../../../../api/ToolApi";
type EditorInputEvent = WechatMiniprogram.CustomEvent<{
html?: string;
text?: string;
}>;
interface MemoData {
formats: Record<string, unknown>;
placeholder: string;
editorHeight: number;
keyboardHeight: number;
isIOS: boolean;
isSaving: boolean;
isEditorReady: boolean;
contentHtml: string;
contentText: string;
}
Page({
data: <MemoData>{
formats: {},
placeholder: "开始输入...",
editorHeight: 300,
keyboardHeight: 0,
isIOS: false,
isSaving: false,
isEditorReady: false,
contentHtml: "",
contentText: ""
},
editorCtx: null as WechatMiniprogram.EditorContext | null,
pendingHtml: "",
hasSavedOnLeave: false,
hasLoadFailed: false,
async onLoad() {
const platform = wx.getSystemInfoSync().platform;
const isIOS = platform === "ios";
this.setData({ isIOS });
this.updatePosition(0);
this.bindKeyboardHeightChange();
await this.loadMemo();
},
onShow() {
this.hasSavedOnLeave = false;
},
async onUnload() {
await this.saveMemoOnLeave();
},
async onHide() {
await this.saveMemoOnLeave();
},
bindKeyboardHeightChange() {
let keyboardHeight = 0;
wx.onKeyboardHeightChange((res) => {
if (res.height === keyboardHeight) {
return;
}
const duration = 0 < res.height ? res.duration * 1000 : 0;
keyboardHeight = res.height;
setTimeout(() => {
wx.pageScrollTo({
scrollTop: 0,
success: () => {
this.updatePosition(keyboardHeight);
this.editorCtx?.scrollIntoView();
}
});
}, duration);
});
},
updatePosition(keyboardHeight: number) {
const toolbarHeight = 50;
const { windowHeight } = wx.getSystemInfoSync();
const editorHeight = 0 < keyboardHeight
? windowHeight - keyboardHeight - toolbarHeight
: windowHeight;
this.setData({ editorHeight, keyboardHeight });
},
onEditorReady() {
const query = wx.createSelectorQuery();
query.select("#memo-editor").context((res) => {
this.editorCtx = (res as { context?: WechatMiniprogram.EditorContext }).context || null;
this.setData({ isEditorReady: true });
this.applyPendingContent();
});
query.exec();
},
applyPendingContent() {
if (!this.editorCtx || !this.pendingHtml) {
return;
}
this.editorCtx.setContents({
html: this.pendingHtml
});
this.pendingHtml = "";
},
onStatusChange(e: WechatMiniprogram.CustomEvent<Record<string, unknown>>) {
this.setData({ formats: e.detail || {} });
},
format(e: WechatMiniprogram.BaseEvent) {
const { name, value } = e.target.dataset as { name?: string; value?: string | number };
if (!name || !this.editorCtx) {
return;
}
this.editorCtx.format(name, value);
},
onEditorInput(e: EditorInputEvent) {
const { html = "", text = "" } = e.detail || {};
this.setData({
contentHtml: html,
contentText: text
});
},
async loadMemo() {
wx.showLoading({ title: "加载中..", mask: true });
let shouldGoBack = false;
try {
const contentHtml = await ToolApi.getMemo();
this.pendingHtml = contentHtml;
this.setData({
contentHtml,
contentText: this.normalizeMemoText(contentHtml)
});
this.applyPendingContent();
} catch (error) {
console.error("加载备忘录失败", error);
this.hasLoadFailed = true;
shouldGoBack = true;
} finally {
wx.hideLoading();
if (shouldGoBack) {
wx.navigateBack({ delta: 1 });
}
}
},
normalizeMemoText(html: string) {
const normalized = html
.replace(/<[^>]*>/g, "")
.replace(/&nbsp;/g, " ")
.replace(/\s+/g, " ")
.trim();
return normalized;
},
async saveMemoOnLeave() {
if (this.hasLoadFailed || this.data.isSaving || this.hasSavedOnLeave) {
return;
}
this.hasSavedOnLeave = true;
this.setData({ isSaving: true });
wx.showLoading({ title: "保存中..", mask: true });
try {
await ToolApi.updateMemo(this.data.contentHtml || "");
} catch (error) {
console.error("保存备忘录失败", error);
} finally {
wx.hideLoading();
this.setData({ isSaving: false });
}
}
});

View File

@ -0,0 +1,65 @@
<!-- 备忘录页面 -->
<view class="custom-navbar">
<t-navbar class="custom-navbar" title="备忘录" left-arrow placeholder />
</view>
<view class="memo setting-bg">
<view class="content">
<view class="container" style="height:{{editorHeight}}px;">
<editor
id="memo-editor"
class="editor"
placeholder="{{placeholder}}"
bindready="onEditorReady"
bindinput="onEditorInput"
bindstatuschange="onStatusChange"
show-img-size="{{false}}"
show-img-toolbar="{{false}}"
show-img-resize="{{false}}"
/>
</view>
<view
class="toolbar"
catchtouchend="format"
hidden="{{0 < keyboardHeight ? false : true}}"
style="bottom: {{isIOS ? keyboardHeight : 0}}px"
>
<text
class="icon {{formats.header === 2 ? 'active' : ''}}"
data-name="header"
data-value="{{2}}"
>H2</text>
<text
class="icon {{formats.header === 3 ? 'active' : ''}}"
data-name="header"
data-value="{{3}}"
>H3</text>
<t-icon
class="icon {{formats.bold ? 'active' : ''}}"
name="textformat-bold"
data-name="bold"
/>
<t-icon
class="icon {{formats.italic ? 'active' : ''}}"
name="textformat-italic"
data-name="italic"
/>
<t-icon
class="icon {{formats.underline ? 'active' : ''}}"
name="textformat-underline"
data-name="underline"
/>
<t-icon
class="icon"
name="task"
data-name="list"
data-value="check"
/>
<t-icon
class="icon {{formats.list === 'bullet' ? 'active' : ''}}"
name="bulletpoint"
data-name="list"
data-value="bullet"
/>
</view>
</view>
</view>

View File

@ -4,7 +4,7 @@
<scroll-view class="info" scroll-y> <scroll-view class="info" scroll-y>
<view class="cotainer"> <view class="cotainer">
<view class="header"> <view class="header">
<image class="logo" src="/assets/image/logo.png"></image> <image class="logo" src="/assets/image/logo.jpg"></image>
<view> <view>
<text>记录</text> <text>记录</text>
<text class="name gao">小糕</text> <text class="name gao">小糕</text>

View File

@ -14,7 +14,7 @@ Page({
{ {
title: "备忘录", title: "备忘录",
icon: "task-checked", icon: "task-checked",
url: "/pages/main/other/portfolio/index" url: "/pages/main/other/memo/index"
}, },
{ {
title: "专拍", title: "专拍",

View File

@ -42,7 +42,7 @@
"tabIndent": "tab", "tabIndent": "tab",
"tabSize": 4 "tabSize": 4
}, },
"libVersion": "3.10.1", "libVersion": "3.11.3",
"packOptions": { "packOptions": {
"ignore": [], "ignore": [],
"include": [] "include": []