From bca5170e229efe5b29d0228943a214a8708bba13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BF=97=E5=BC=BA?= <357099073@qq.com> Date: Wed, 15 Jul 2026 18:14:17 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E7=A8=8B=E7=95=8C?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uniapp/.mimocode/.cron-lock | 1 + uniapp/App.vue | 4 +- uniapp/api/note.js | 138 ++++++ uniapp/api/request.js | 24 + uniapp/api/schedule.js | 242 ++++++++++ uniapp/components/AppTabbar.vue | 118 +---- uniapp/pages.json | 35 ++ uniapp/pages/dashboard/dashboard.vue | 185 ++++---- uniapp/pages/features/features.vue | 619 ++++++++++--------------- uniapp/pages/login/login.vue | 180 +++---- uniapp/pages/profile/profile.vue | 437 ++--------------- uniapp/pages/tools/notepad/edit.vue | 290 ++++++++++++ uniapp/pages/tools/notepad/index.vue | 332 +++++++++++++ uniapp/pages/tools/schedule/detail.vue | 321 +++++++++++++ uniapp/pages/tools/schedule/edit.vue | 375 +++++++++++++++ uniapp/pages/tools/schedule/index.vue | 428 +++++++++++++++++ uniapp/src/styles/page-common.scss | 40 ++ uniapp/src/styles/theme.scss | 33 +- uniapp/utils/date.js | 73 +++ 19 files changed, 2805 insertions(+), 1070 deletions(-) create mode 100644 uniapp/.mimocode/.cron-lock create mode 100644 uniapp/api/note.js create mode 100644 uniapp/api/request.js create mode 100644 uniapp/api/schedule.js create mode 100644 uniapp/pages/tools/notepad/edit.vue create mode 100644 uniapp/pages/tools/notepad/index.vue create mode 100644 uniapp/pages/tools/schedule/detail.vue create mode 100644 uniapp/pages/tools/schedule/edit.vue create mode 100644 uniapp/pages/tools/schedule/index.vue create mode 100644 uniapp/src/styles/page-common.scss create mode 100644 uniapp/utils/date.js diff --git a/uniapp/.mimocode/.cron-lock b/uniapp/.mimocode/.cron-lock new file mode 100644 index 0000000..7817067 --- /dev/null +++ b/uniapp/.mimocode/.cron-lock @@ -0,0 +1 @@ +{"pid":4360,"startedAt":1784109827988} \ No newline at end of file diff --git a/uniapp/App.vue b/uniapp/App.vue index be529b4..d3b8474 100644 --- a/uniapp/App.vue +++ b/uniapp/App.vue @@ -20,8 +20,8 @@ page { height: 100%; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; - background-color: #f8fafc; - color: #1e293b; + background-color: #f5f7fa; + color: #303133; box-sizing: border-box; } diff --git a/uniapp/api/note.js b/uniapp/api/note.js new file mode 100644 index 0000000..e5d96ee --- /dev/null +++ b/uniapp/api/note.js @@ -0,0 +1,138 @@ +import { generateId } from '@/api/request.js' + +const STORAGE_KEY = 'app_notes' + +function readLocal() { + return uni.getStorageSync(STORAGE_KEY) || [] +} + +function writeLocal(list) { + uni.setStorageSync(STORAGE_KEY, list) +} + +function seedIfEmpty() { + const list = readLocal() + if (list.length) return list + const now = Date.now() + const seeded = [ + { + id: generateId(), + title: '欢迎使用记事本', + content: '在这里记录灵感、待办或任何想法。支持置顶、搜索与编辑,后续可一键接入云端同步。', + pinned: true, + createdAt: now - 86400000, + updatedAt: now - 3600000 + }, + { + id: generateId(), + title: '项目会议要点', + content: '1. 确认 Q3 目标\n2. 排期评审\n3. 接口联调时间', + pinned: false, + createdAt: now - 172800000, + updatedAt: now - 7200000 + } + ] + writeLocal(seeded) + return seeded +} + +function sortNotes(list) { + return [...list].sort((a, b) => { + if (a.pinned !== b.pinned) return a.pinned ? -1 : 1 + return (b.updatedAt || 0) - (a.updatedAt || 0) + }) +} + +/** + * 获取笔记列表 + * @param {{ keyword?: string }} params + * @returns {Promise<{ list: Array, total: number }>} + */ +export async function fetchNotes(params = {}) { + // TODO: return request({ url: '/api/notes', data: params }) + let list = seedIfEmpty() + const keyword = (params.keyword || '').trim().toLowerCase() + if (keyword) { + list = list.filter( + item => + item.title.toLowerCase().includes(keyword) || + item.content.toLowerCase().includes(keyword) + ) + } + list = sortNotes(list) + return { list, total: list.length } +} + +/** + * 获取单条笔记 + * @param {string} id + */ +export async function getNote(id) { + // TODO: return request({ url: `/api/notes/${id}` }) + const list = readLocal() + return list.find(item => item.id === id) || null +} + +/** + * 创建笔记 + * @param {{ title: string, content: string, pinned?: boolean }} data + */ +export async function createNote(data) { + // TODO: return request({ url: '/api/notes', method: 'POST', data }) + const now = Date.now() + const note = { + id: generateId(), + title: (data.title || '').trim() || '无标题', + content: (data.content || '').trim(), + pinned: !!data.pinned, + createdAt: now, + updatedAt: now + } + const list = readLocal() + list.unshift(note) + writeLocal(list) + return note +} + +/** + * 更新笔记 + * @param {string} id + * @param {{ title?: string, content?: string, pinned?: boolean }} data + */ +export async function updateNote(id, data) { + // TODO: return request({ url: `/api/notes/${id}`, method: 'PUT', data }) + const list = readLocal() + const index = list.findIndex(item => item.id === id) + if (index === -1) throw new Error('笔记不存在') + const note = { + ...list[index], + ...data, + title: data.title !== undefined ? (data.title.trim() || '无标题') : list[index].title, + content: data.content !== undefined ? data.content.trim() : list[index].content, + updatedAt: Date.now() + } + list[index] = note + writeLocal(list) + return note +} + +/** + * 删除笔记 + * @param {string} id + */ +export async function deleteNote(id) { + // TODO: return request({ url: `/api/notes/${id}`, method: 'DELETE' }) + const list = readLocal().filter(item => item.id !== id) + writeLocal(list) + return true +} + +/** + * 切换置顶 + * @param {string} id + */ +export async function toggleNotePin(id) { + const note = await getNote(id) + if (!note) throw new Error('笔记不存在') + return updateNote(id, { pinned: !note.pinned }) +} diff --git a/uniapp/api/request.js b/uniapp/api/request.js new file mode 100644 index 0000000..b71b174 --- /dev/null +++ b/uniapp/api/request.js @@ -0,0 +1,24 @@ +/** + * 统一请求封装,接入后端时在此配置 baseURL、token、错误处理。 + * + * 示例: + * export function request({ url, method = 'GET', data }) { + * return new Promise((resolve, reject) => { + * uni.request({ + * url: BASE_URL + url, + * method, + * data, + * header: { Authorization: 'Bearer ' + getToken() }, + * success: (res) => { + * if (res.statusCode >= 200 && res.statusCode < 300) resolve(res.data) + * else reject(res) + * }, + * fail: reject + * }) + * }) + * } + */ + +export function generateId() { + return `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}` +} diff --git a/uniapp/api/schedule.js b/uniapp/api/schedule.js new file mode 100644 index 0000000..69cc182 --- /dev/null +++ b/uniapp/api/schedule.js @@ -0,0 +1,242 @@ +import { generateId } from '@/api/request.js' +import { startOfDay, endOfDay } from '@/utils/date.js' + +const STORAGE_KEY = 'app_schedules' + +const PRIORITY = { + low: { value: 'low', label: '低', color: '#909399' }, + medium: { value: 'medium', label: '中', color: '#3c9cff' }, + high: { value: 'high', label: '高', color: '#f56c6c' } +} + +export const PRIORITY_OPTIONS = Object.values(PRIORITY) + +export const REMIND_CHANNEL_OPTIONS = [ + { value: 'sms', label: '短信' }, + { value: 'email', label: '邮件' }, + { value: 'bark', label: 'Bark推送' }, + { value: 'site', label: '站内信' }, + { value: 'app', label: 'APP' } +] + +export const REMIND_MINUTES_OPTIONS = [ + { label: '不提前', value: 0 }, + { label: '提前 5 分钟', value: 5 }, + { label: '提前 10 分钟', value: 10 }, + { label: '提前 15 分钟', value: 15 }, + { label: '提前 30 分钟', value: 30 }, + { label: '提前 1 小时', value: 60 }, + { label: '提前 2 小时', value: 120 }, + { label: '提前 1 天', value: 1440 } +] + +function readLocal() { + const list = uni.getStorageSync(STORAGE_KEY) || [] + return list.map(normalizeSchedule) +} + +function writeLocal(list) { + uni.setStorageSync(STORAGE_KEY, list) +} + +export function normalizeSchedule(item) { + const content = (item.content || item.title || '').trim() + const title = (item.title || content.split('\n')[0] || '无标题').trim().slice(0, 60) + let remindChannels = item.remindChannels + if (!Array.isArray(remindChannels)) { + remindChannels = item.remindMinutes > 0 ? ['app'] : [] + } + return { + ...item, + title, + content, + remindChannels, + remindMinutes: item.remindMinutes ?? 15 + } +} + +function buildTitle(content) { + const line = (content || '').split('\n')[0].trim() + return line.slice(0, 60) || '无标题' +} + +function seedIfEmpty() { + const raw = uni.getStorageSync(STORAGE_KEY) + if (raw && raw.length) return raw.map(normalizeSchedule) + const now = Date.now() + const today = new Date() + const seeded = [ + { + id: generateId(), + content: '团队周会\n汇报本周进度,讨论下周计划', + datetime: new Date(today.getFullYear(), today.getMonth(), today.getDate(), 10, 0).getTime(), + remindChannels: ['app', 'site'], + remindMinutes: 15, + priority: 'high', + completed: false, + createdAt: now - 86400000, + updatedAt: now - 86400000 + }, + { + id: generateId(), + content: '提交月报\n整理本月数据并发送给主管', + datetime: new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1, 18, 0).getTime(), + remindChannels: ['email', 'site'], + remindMinutes: 30, + priority: 'medium', + completed: false, + createdAt: now - 43200000, + updatedAt: now - 43200000 + }, + { + id: generateId(), + content: '健身打卡\n有氧运动 30 分钟', + datetime: new Date(today.getFullYear(), today.getMonth(), today.getDate() - 1, 19, 30).getTime(), + remindChannels: ['bark', 'app'], + remindMinutes: 10, + priority: 'low', + completed: true, + createdAt: now - 259200000, + updatedAt: now - 86400000 + } + ].map(normalizeSchedule) + writeLocal(seeded) + return seeded +} + +function sortSchedules(list) { + return [...list].sort((a, b) => { + if (a.completed !== b.completed) return a.completed ? 1 : -1 + return (a.datetime || 0) - (b.datetime || 0) + }) +} + +/** + * 获取日程列表 + */ +export async function fetchSchedules(params = {}) { + // TODO: return request({ url: '/api/schedules', data: params }) + let list = seedIfEmpty() + const keyword = (params.keyword || '').trim().toLowerCase() + const status = params.status || 'all' + + if (keyword) { + list = list.filter(item => { + const text = `${item.title} ${item.content}`.toLowerCase() + return text.includes(keyword) + }) + } + if (status === 'pending') list = list.filter(item => !item.completed) + if (status === 'done') list = list.filter(item => item.completed) + + if (params.date) { + const dayStart = startOfDay(params.date).getTime() + const dayEnd = endOfDay(params.date).getTime() + list = list.filter(item => item.datetime >= dayStart && item.datetime <= dayEnd) + } + + list = sortSchedules(list) + return { list, total: list.length } +} + +/** + * 获取单条日程 + */ +export async function getSchedule(id) { + // TODO: return request({ url: `/api/schedules/${id}` }) + const list = readLocal() + const item = list.find(entry => entry.id === id) + return item ? normalizeSchedule(item) : null +} + +/** + * 创建日程 + * @param {{ content: string, datetime: number, remindChannels?: string[], remindMinutes?: number }} data + */ +export async function createSchedule(data) { + // TODO: return request({ url: '/api/schedules', method: 'POST', data }) + const now = Date.now() + const content = (data.content || '').trim() + const schedule = normalizeSchedule({ + id: generateId(), + title: buildTitle(content), + content, + datetime: data.datetime, + remindChannels: data.remindChannels || [], + remindMinutes: data.remindMinutes ?? 15, + priority: data.priority || 'medium', + completed: false, + createdAt: now, + updatedAt: now + }) + const list = readLocal() + list.push(schedule) + writeLocal(list) + return schedule +} + +/** + * 更新日程 + */ +export async function updateSchedule(id, data) { + // TODO: return request({ url: `/api/schedules/${id}`, method: 'PUT', data }) + const list = readLocal() + const index = list.findIndex(item => item.id === id) + if (index === -1) throw new Error('日程不存在') + + const prev = list[index] + const content = data.content !== undefined ? data.content.trim() : prev.content + const schedule = normalizeSchedule({ + ...prev, + ...data, + title: data.content !== undefined ? buildTitle(content) : prev.title, + content, + updatedAt: Date.now() + }) + list[index] = schedule + writeLocal(list) + return schedule +} + +/** + * 删除日程 + */ +export async function deleteSchedule(id) { + // TODO: return request({ url: `/api/schedules/${id}`, method: 'DELETE' }) + const list = readLocal().filter(item => item.id !== id) + writeLocal(list) + return true +} + +/** + * 切换完成状态 + */ +export async function toggleScheduleComplete(id) { + const item = await getSchedule(id) + if (!item) throw new Error('日程不存在') + return updateSchedule(id, { completed: !item.completed }) +} + +export function getPriorityMeta(value) { + return PRIORITY[value] || PRIORITY.medium +} + +export function getRemindChannelLabel(value) { + return REMIND_CHANNEL_OPTIONS.find(item => item.value === value)?.label || value +} + +export function getRemindChannelLabels(channels = []) { + if (!channels.length) return '未设置' + return channels.map(getRemindChannelLabel).join('、') +} + +export function getRemindMinutesLabel(minutes) { + const item = REMIND_MINUTES_OPTIONS.find(option => option.value === minutes) + return item?.label || (minutes ? `提前 ${minutes} 分钟` : '不提前') +} + +export function getScheduleSummary(item) { + const text = (item?.content || item?.title || '').trim() + const line = text.split('\n')[0] + return line || '无内容' +} diff --git a/uniapp/components/AppTabbar.vue b/uniapp/components/AppTabbar.vue index 6bb9267..0a91c15 100644 --- a/uniapp/components/AppTabbar.vue +++ b/uniapp/components/AppTabbar.vue @@ -1,179 +1,87 @@ - - - - - - diff --git a/uniapp/pages.json b/uniapp/pages.json index 87e8015..037ed46 100644 --- a/uniapp/pages.json +++ b/uniapp/pages.json @@ -36,6 +36,41 @@ "navigationStyle": "custom", "navigationBarTitleText": "我的" } + }, + { + "path": "pages/tools/notepad/index", + "style": { + "navigationBarTitleText": "记事本", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "pages/tools/notepad/edit", + "style": { + "navigationBarTitleText": "新建笔记", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "pages/tools/schedule/index", + "style": { + "navigationBarTitleText": "日程提醒", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "pages/tools/schedule/detail", + "style": { + "navigationBarTitleText": "日程详情", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "pages/tools/schedule/edit", + "style": { + "navigationBarTitleText": "新建日程", + "navigationBarBackgroundColor": "#F8FAFC" + } } ], "globalStyle": { diff --git a/uniapp/pages/dashboard/dashboard.vue b/uniapp/pages/dashboard/dashboard.vue index 8a12f8e..8349c84 100644 --- a/uniapp/pages/dashboard/dashboard.vue +++ b/uniapp/pages/dashboard/dashboard.vue @@ -11,7 +11,7 @@ - + 搜索功能、数据... @@ -19,17 +19,20 @@ - {{ item.value }} {{ item.label }} - - {{ item.up ? '↑' : '↓' }} {{ item.trend }} - + {{ item.value }} + + + {{ item.trend }} + - 快捷入口 - + + 快捷入口 + + - + {{ item.name }} @@ -51,11 +54,14 @@ - + + + {{ item.title }} {{ item.time }} + @@ -121,149 +127,145 @@ function onQuickTap(item) { diff --git a/uniapp/pages/features/features.vue b/uniapp/pages/features/features.vue index e736182..92d21e7 100644 --- a/uniapp/pages/features/features.vue +++ b/uniapp/pages/features/features.vue @@ -1,451 +1,304 @@ - - - - - - diff --git a/uniapp/pages/login/login.vue b/uniapp/pages/login/login.vue index 9bc46b3..cab5be1 100644 --- a/uniapp/pages/login/login.vue +++ b/uniapp/pages/login/login.vue @@ -3,6 +3,9 @@ + 欢迎回来 登录云泽,开启你的旅程 @@ -22,7 +25,8 @@ - + +