add memo
This commit is contained in:
24
miniprogram/api/ToolApi.ts
Normal file
24
miniprogram/api/ToolApi.ts
Normal 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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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",
|
||||||
|
|||||||
BIN
miniprogram/assets/image/logo.jpg
Normal file
BIN
miniprogram/assets/image/logo.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 128 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 68 KiB |
@ -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"
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
7
miniprogram/pages/main/other/memo/index.json
Normal file
7
miniprogram/pages/main/other/memo/index.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"usingComponents": {
|
||||||
|
"t-icon": "tdesign-miniprogram/icon/icon",
|
||||||
|
"t-navbar": "tdesign-miniprogram/navbar/navbar"
|
||||||
|
},
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
66
miniprogram/pages/main/other/memo/index.less
Normal file
66
miniprogram/pages/main/other/memo/index.less
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
162
miniprogram/pages/main/other/memo/index.ts
Normal file
162
miniprogram/pages/main/other/memo/index.ts
Normal 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(/ /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 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
65
miniprogram/pages/main/other/memo/index.wxml
Normal file
65
miniprogram/pages/main/other/memo/index.wxml
Normal 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>
|
||||||
@ -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>
|
||||||
|
|||||||
@ -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: "专拍",
|
||||||
|
|||||||
@ -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": []
|
||||||
|
|||||||
Reference in New Issue
Block a user