This commit is contained in:
binghuai
2025-08-29 10:02:18 +08:00
parent 376b58bdd7
commit 4699007138
12 changed files with 528 additions and 57 deletions

3
.obsidian/app.json vendored
View File

@@ -1,3 +1,4 @@
{
"promptDelete": false
"promptDelete": false,
"defaultViewMode": "source"
}

View File

@@ -8,5 +8,6 @@
"obsidian-pandoc",
"univer",
"obsidian-image-auto-upload-plugin",
"obsidian-git"
"obsidian-git",
"remember-cursor-position"
]

View File

@@ -7,7 +7,7 @@
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"properties": false,
"properties": true,
"page-preview": true,
"daily-notes": true,
"templates": true,

View File

@@ -0,0 +1 @@
{"月度/8月/8月.md":{"scroll":371.8766,"cursor":{"from":{"ch":6,"line":481},"to":{"ch":6,"line":481}}}}

View File

@@ -0,0 +1,302 @@
/*
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
if you want to view the source visit the plugins github repository
*/
'use strict';
var obsidian = require('obsidian');
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
const SAFE_DB_FLUSH_INTERVAL = 5000;
const DEFAULT_SETTINGS = {
dbFileName: '.obsidian/plugins/remember-cursor-position/cursor-positions.json',
delayAfterFileOpening: 100,
saveTimer: SAFE_DB_FLUSH_INTERVAL,
};
class RememberCursorPosition extends obsidian.Plugin {
constructor() {
super(...arguments);
this.loadedLeafIdList = [];
this.loadingFile = false;
}
onload() {
return __awaiter(this, void 0, void 0, function* () {
yield this.loadSettings();
try {
this.db = yield this.readDb();
this.lastSavedDb = yield this.readDb();
}
catch (e) {
console.error("Remember Cursor Position plugin can\'t read database: " + e);
this.db = {};
this.lastSavedDb = {};
}
this.addSettingTab(new SettingTab(this.app, this));
this.registerEvent(this.app.workspace.on('file-open', (file) => this.restoreEphemeralState()));
this.registerEvent(this.app.workspace.on('quit', () => { this.writeDb(this.db); }));
this.registerEvent(this.app.vault.on('rename', (file, oldPath) => this.renameFile(file, oldPath)));
this.registerEvent(this.app.vault.on('delete', (file) => this.deleteFile(file)));
//todo: replace by scroll and mouse cursor move events
this.registerInterval(window.setInterval(() => this.checkEphemeralStateChanged(), 100));
this.registerInterval(window.setInterval(() => this.writeDb(this.db), this.settings.saveTimer));
this.restoreEphemeralState();
});
}
renameFile(file, oldPath) {
let newName = file.path;
let oldName = oldPath;
this.db[newName] = this.db[oldName];
delete this.db[oldName];
}
deleteFile(file) {
let fileName = file.path;
delete this.db[fileName];
}
checkEphemeralStateChanged() {
var _a;
let fileName = (_a = this.app.workspace.getActiveFile()) === null || _a === void 0 ? void 0 : _a.path;
//waiting for load new file
if (!fileName || !this.lastLoadedFileName || fileName != this.lastLoadedFileName || this.loadingFile)
return;
let st = this.getEphemeralState();
if (!this.lastEphemeralState)
this.lastEphemeralState = st;
if (!isNaN(st.scroll) && !this.isEphemeralStatesEquals(st, this.lastEphemeralState)) {
this.saveEphemeralState(st);
this.lastEphemeralState = st;
}
}
isEphemeralStatesEquals(state1, state2) {
if (state1.cursor && !state2.cursor)
return false;
if (!state1.cursor && state2.cursor)
return false;
if (state1.cursor) {
if (state1.cursor.from.ch != state2.cursor.from.ch)
return false;
if (state1.cursor.from.line != state2.cursor.from.line)
return false;
if (state1.cursor.to.ch != state2.cursor.to.ch)
return false;
if (state1.cursor.to.line != state2.cursor.to.line)
return false;
}
if (state1.scroll && !state2.scroll)
return false;
if (!state1.scroll && state2.scroll)
return false;
if (state1.scroll && state1.scroll != state2.scroll)
return false;
return true;
}
saveEphemeralState(st) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
let fileName = (_a = this.app.workspace.getActiveFile()) === null || _a === void 0 ? void 0 : _a.path;
if (fileName && fileName == this.lastLoadedFileName) { //do not save if file changed or was not loaded
this.db[fileName] = st;
}
});
}
restoreEphemeralState() {
var _a, _b, _c;
return __awaiter(this, void 0, void 0, function* () {
let fileName = (_a = this.app.workspace.getActiveFile()) === null || _a === void 0 ? void 0 : _a.path;
if (fileName && this.loadingFile && this.lastLoadedFileName == fileName) //if already started loading
return;
let activeLeaf = this.app.workspace.getMostRecentLeaf();
if (activeLeaf && this.loadedLeafIdList.includes(activeLeaf.id + ':' + activeLeaf.getViewState().state.file))
return;
this.loadedLeafIdList = [];
this.app.workspace.iterateAllLeaves((leaf) => {
if (leaf.getViewState().type === "markdown") {
this.loadedLeafIdList.push(leaf.id + ':' + leaf.getViewState().state.file);
}
});
this.loadingFile = true;
if (this.lastLoadedFileName != fileName) {
this.lastEphemeralState = {};
this.lastLoadedFileName = fileName;
let st;
if (fileName) {
st = this.db[fileName];
if (st) {
//waiting for load note
yield this.delay(this.settings.delayAfterFileOpening);
let scroll;
for (let i = 0; i < 20; i++) {
scroll = (_c = (_b = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView)) === null || _b === void 0 ? void 0 : _b.currentMode) === null || _c === void 0 ? void 0 : _c.getScroll();
if (scroll !== null)
break;
yield this.delay(10);
}
// TODO: if note opened by link like [link](note.md#header), do not scroll it
yield this.delay(10);
this.setEphemeralState(st);
}
}
this.lastEphemeralState = st;
}
this.loadingFile = false;
});
}
readDb() {
return __awaiter(this, void 0, void 0, function* () {
let db = {};
if (yield this.app.vault.adapter.exists(this.settings.dbFileName)) {
let data = yield this.app.vault.adapter.read(this.settings.dbFileName);
db = JSON.parse(data);
}
return db;
});
}
writeDb(db) {
return __awaiter(this, void 0, void 0, function* () {
//create folder for db file if not exist
let newParentFolder = this.settings.dbFileName.substring(0, this.settings.dbFileName.lastIndexOf("/"));
if (!(yield this.app.vault.adapter.exists(newParentFolder)))
this.app.vault.adapter.mkdir(newParentFolder);
if (JSON.stringify(this.db) !== JSON.stringify(this.lastSavedDb)) {
this.app.vault.adapter.write(this.settings.dbFileName, JSON.stringify(db));
this.lastSavedDb = JSON.parse(JSON.stringify(db));
}
});
}
getEphemeralState() {
// let state: EphemeralState = this.app.workspace.getActiveViewOfType(MarkdownView)?.getEphemeralState(); //doesn't work properly
var _a, _b, _c;
let state = {};
state.scroll = Number((_c = (_b = (_a = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView)) === null || _a === void 0 ? void 0 : _a.currentMode) === null || _b === void 0 ? void 0 : _b.getScroll()) === null || _c === void 0 ? void 0 : _c.toFixed(4));
let editor = this.getEditor();
if (editor) {
let from = editor.getCursor("anchor");
let to = editor.getCursor("head");
if (from && to) {
state.cursor = {
from: {
ch: from.ch,
line: from.line
},
to: {
ch: to.ch,
line: to.line
}
};
}
}
return state;
}
setEphemeralState(state) {
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
if (state.cursor) {
let editor = this.getEditor();
if (editor) {
editor.setSelection(state.cursor.from, state.cursor.to);
}
}
if (view && state.scroll) {
view.setEphemeralState(state);
// view.previewMode.applyScroll(state.scroll);
// view.sourceMode.applyScroll(state.scroll);
}
}
getEditor() {
var _a;
return (_a = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView)) === null || _a === void 0 ? void 0 : _a.editor;
}
loadSettings() {
return __awaiter(this, void 0, void 0, function* () {
let settings = Object.assign({}, DEFAULT_SETTINGS, yield this.loadData());
if ((settings === null || settings === void 0 ? void 0 : settings.saveTimer) < SAFE_DB_FLUSH_INTERVAL) {
settings.saveTimer = SAFE_DB_FLUSH_INTERVAL;
}
this.settings = settings;
});
}
saveSettings() {
return __awaiter(this, void 0, void 0, function* () {
yield this.saveData(this.settings);
});
}
delay(ms) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise(resolve => setTimeout(resolve, ms));
});
}
}
class SettingTab extends obsidian.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.plugin = plugin;
}
display() {
let { containerEl } = this;
containerEl.empty();
containerEl.createEl('h2', { text: 'Remember cursor position - Settings' });
new obsidian.Setting(containerEl)
.setName('Data file name')
.setDesc('Save positions to this file')
.addText((text) => text
.setPlaceholder('Example: cursor-positions.json')
.setValue(this.plugin.settings.dbFileName)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
this.plugin.settings.dbFileName = value;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName('Delay after opening a new note')
.setDesc("This plugin shouldn't scroll if you used a link to the note header like [link](note.md#header). If it did, then increase the delay until everything works. If you are not using links to page sections, set the delay to zero (slider to the left). Slider values: 0-300 ms (default value: 100 ms).")
.addSlider((text) => text
.setLimits(0, 300, 10)
.setValue(this.plugin.settings.delayAfterFileOpening)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
this.plugin.settings.delayAfterFileOpening = value;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName('Delay between saving the cursor position to file')
.setDesc("Useful for multi-device users. If you don't want to wait until closing Obsidian to the cursor position been saved.")
.addSlider((text) => text
.setLimits(SAFE_DB_FLUSH_INTERVAL, SAFE_DB_FLUSH_INTERVAL * 10, 10)
.setValue(this.plugin.settings.saveTimer)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
this.plugin.settings.saveTimer = value;
yield this.plugin.saveSettings();
})));
}
}
module.exports = RememberCursorPosition;
/* nosourcemap */

View File

@@ -0,0 +1,10 @@
{
"id": "remember-cursor-position",
"name": "Remember cursor position",
"version": "1.0.9",
"minAppVersion": "0.9.12",
"description": "Remember cursor and scroll position for each note",
"author": "Dmitry Savosh",
"authorUrl": "https://github.com/dy-sh/",
"isDesktopOnly": false
}

8
.obsidian/types.json vendored Normal file
View File

@@ -0,0 +1,8 @@
{
"types": {
"aliases": "aliases",
"cssclasses": "multitext",
"tags": "tags",
"图片": "multitext"
}
}

View File

@@ -4,34 +4,22 @@
"type": "split",
"children": [
{
"id": "eb8d36499b2770da",
"id": "01b1a1c13ef56ab5",
"type": "tabs",
"children": [
{
"id": "09209a9a39e1187e",
"id": "f3b163eeb312320d",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "月度/8月/8月.md",
"mode": "source",
"source": true
"source": false
},
"icon": "lucide-file",
"title": "8月"
}
},
{
"id": "753de844edc5016c",
"type": "leaf",
"state": {
"type": "docx-view",
"state": {
"file": "月度/8月/1.《新疆学生常见病监测信息管理系统》V5.3需求确认书(优化部分).docx"
},
"icon": "lucide-file",
"title": "1.《新疆学生常见病监测信息管理系统》V5.3需求确认书(优化部分)"
}
}
]
}
@@ -115,25 +103,6 @@
"title": "8月 的大纲"
}
},
{
"id": "28e5320c71cac0db",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"file": "月度/8月/8月.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-coming-in",
"title": "8月 的反向链接列表"
}
},
{
"id": "7c3be5a7fa146fb4",
"type": "leaf",
@@ -172,13 +141,58 @@
"icon": "git-pull-request",
"title": "Source Control"
}
},
{
"id": "395ec3c7b07dfe34",
"type": "leaf",
"state": {
"type": "file-properties",
"state": {
"file": "月度/8月/8月.md"
},
"icon": "lucide-info",
"title": "8月的笔记属性"
}
},
{
"id": "87b7b54ecdb86451",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"file": "月度/8月/8月.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-coming-in",
"title": "8月 的反向链接列表"
}
},
{
"id": "93f13e559958fc6b",
"type": "leaf",
"state": {
"type": "all-properties",
"state": {
"sortOrder": "frequency",
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-archive",
"title": "添加笔记属性"
}
}
],
"currentTab": 4
"currentTab": 2
}
],
"direction": "horizontal",
"width": 286.5
"width": 327.5
},
"left-ribbon": {
"hiddenItems": {
@@ -196,39 +210,44 @@
"obsidian-git:Open Git source control": false
}
},
"active": "09209a9a39e1187e",
"active": "f3b163eeb312320d",
"lastOpenFiles": [
"月度/8月/1.《新疆学生常见病监测信息管理系统》V5.3需求确认书(优化部分).docx",
"月度/8月/8月.md",
"月度/3月/3月.md",
"月度/4月/4月.md",
"月度/5月/5月.md",
"月度/6月/6月.md",
"月度/7月/7月.md",
"月度/封面.base",
"图片/8月.png",
"图片/1756350239430_d.png",
"图片/1756348666259_d.png",
"图片",
"月度/8月/晨午检学校上报统计.xlsx",
"材料/转正材料/~$【20250314】技术部工作总结汇报.pptx",
"月度/8月/8.8技术部研讨会议纪要.md",
"Untitled 1.md",
"Untitled.md",
"月度/8月/1.《新疆学生常见病监测信息管理系统》V5.3需求确认书(优化部分).docx",
"月度/7月/7月工作总结及8月工作计划.md",
"材料/配置/Obsidian快捷键.md",
"月度/8月/资源发展中心汇报/资源发展中心问题.md",
"材料/转正材料/转正述职报告.md",
"月度/3月/3月.md",
"月度/8月/CA身份认证app/CA身份认证app流程图.md",
"材料/服务器.md",
"月度/6月/6月份晨午检bug修复.md",
"月度/7月/华为服务器测试报告.md",
"月度/8月/8.8技术部研讨会议纪要.md",
"月度/6月/6月.md",
"月度/7月/7月份晨午检bug修复.md",
"月度/7月/ca会议纪要.md",
"月度/7月/设备管理中心研发记录.md",
"月度/4月/4月.md",
"月度/5月/5月.md",
"月度/7月/7月.md",
"月度/8月/新疆青卫舜源2025年8月技术部KPI-研发工程师-颜准.xlsx",
"月度/8月/未命名.md",
"月度/8月/~$《新疆学生常见病监测信息管理系统》V5.3需求确认书(优化部分).docx",
"月度/7月/Attachments/设备管理中心优化需求文档.png",
"月度/8月/晨午检学校上报统计.xlsx",
"月度/晨午检学校上报统计.xlsx",
"1755743563407_d.png",
"月度/8月/CA身份认证app/移动认证中心需求.docx",
"材料/code/dbcenter-master.zip",
"材料/code/spidercenter-main.zip",
"周报/技术部《第33周》颜准 周报2025年8月15日)~C8F6E.tmp",
"周报/技术部《第33周》颜准 周报2025年8月15日)~BEF36.tmp",
"8.8技术部研讨会议纪要.md",
"月度/8月/8.8技术部研讨会议纪要 - 副本.md",
"Pasted image 20250808165433.png",
@@ -238,12 +257,7 @@
"月度/8月/ca身份认证/未命名.canvas",
"月度/8月/ca身份认证/Drawing 2025-08-08 12.42.17.excalidraw.md",
"月度/7月/Attachments/设备管理中心优化需求文档 1.png",
"().md",
"1日报/8月.md",
"月度/7月/Attachments/设备管理中心优化需求文档 2.png",
"3月度/7月/Attachments/设备管理中心优化需求文档.png",
"3月度/7月/Attachments/设备管理中心优化需求文档 2.png",
"3月度/7月/Attachments/设备管理中心优化需求文档 1.png",
"未命名.canvas"
]
}

BIN
图片/8月.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

@@ -1,3 +1,5 @@
![[8月.png]]
# 8.1
1.撰写技术部7月总结8月计划ppt
[[7月工作总结及8月工作计划]]
@@ -362,3 +364,119 @@ A071A01
A071A02
A071A03
A071A04
# 8.28
1. <span style="color:#3EC1D3 !important;">常见病app</span>refactor(physicalcheck): 重构体检数据漏项处理逻辑
- 更新 MissItemEntity 和 MissItemModel 以适应新的数据结构
- 优化学院体检新页面的数据保存和上传逻辑
- 改进历史数据页面的学生详情弹窗,支持动态字段显示
- 优化数据删除和重新上传功能
<span style="color:#3EC1D3 !important;">常见病后端</span>feat(query): 优化体检结果漏项检查功能
- 新增 MissingItemGroupVo 类用于封装遗漏项目的组信息
- 重构 TestingResultController 中的 checkMissingTestingResultTtemByApp 方法
- 更新 TestingResultServiceImpl 中的 checkTestingResultMissingItem 方法
- 在 TestingResultVo 中添加 yaowei 字段用于记录腰围信息
- 新增 ReflexObjectUtil 工具类用于反射操作对象属性
2. 备份<span style="color:#3EC1D3 !important;">晨午检系统</span>学生数据表(8.28),删除所有没有班级的学生信息
3. <span style="color:#3EC1D3 !important;">晨午检系统</span>refactor(teacher): 修复教职工页面修改、删除打不开的bug
- 添加编辑和删除按钮的点击事件处理
- 优化导入数据功能的代码结构
- 移除冗余的空格和注释
- 统一代码格式和风格
1. <span style="color:#3EC1D3 !important;">晨午检系统</span>将部署在152上的两个节点切换至了<span style="color:#ffff00 !important;">10.10.35.23统信达梦</span>服务器上
脊柱侧弯检查部分
**一(1)** 可多选1-6选1不能选别的
**一(2)** 可多选1-4选1不能选别的
**一(3)** 三个部位得ATR必填0-30
**一(4)** 只能选1或2选1后面三个ATR值需填写选2直接跳转至第二部分
**二(4)** 选1不能选别的2、3可多选选1直接跳转第三部分选2或3或2和3回答二(5)
**二(5)** 选1不能选别的2、3可多选选2筛查结果为4选3筛查结果为5
**疾病史**可多选1-4
**筛查结果**
选1不能选别的
选2不能选别的
3、4、5可同时多选
如果选的有3要填脊柱侧弯级别
```brainfuck
请实现一个脊柱侧弯筛查结果自动判定函数,根据用户输入的表单数据自动计算初筛结果,具体要求如下:
### 输入参数(对应字段名):
- `generalExamination`: 一(1)一般检查结果(数组,可多选)
- `adamsTest`: 一(2)前屈试验结果(数组,可多选)
- `chestSegment`: 一(3)胸段检查结果(对象:{ option: string, atr: number }
- `waistChestSegment`: 一(3)腰胸段检查结果(同上)
- `waistSegment`: 一(3)腰段检查结果(同上)
- `spineMovementExperiment`: 一(4)是否进行脊柱运动试验booleantrue为是
- `movementChestATR`: 一(4)运动试验后胸段ATRnumber可选
- `movementWaistChestATR`: 一(4)运动试验后腰胸段ATRnumber可选
- `movementWaistATR`: 一(4)运动试验后腰段ATRnumber可选
- `frontBackGeneral`: 二(4)前后弯曲一般检查(字符串,可选值:正常、前凸体征、后凸体征)
- `proneTest`: 二(5)俯卧试验结果(字符串,可选值:前后凸体征消失、前凸体征、后凸体征)
### 逻辑要求:
1. **脊柱侧弯部分判定**
- 若一(1)为“正常”、一(2)为“正常”且一(3)三个ATR均<5°则初筛结果为“正常”。
- 否则,若一(4)为“是”且运动试验后三个ATR均<5°则初筛结果为“姿态不良”。
- 否则若任一运动试验后ATR≥5°则初筛结果为“脊柱侧弯”并需根据最大ATR值判定等级
- 5°≤ATR<7°
- 7°≤ATR<10°Ⅱ级
- ATR≥10°Ⅲ级
2. **脊柱前后弯曲部分判定**
- 若二(4)为“正常”,不影响初筛结果。
- 若二(4)为“前凸体征”或“后凸体征”,则必须进行二(5)俯卧试验:
- 若二(5)为“前后凸体征消失”,则初筛结果为“姿态不良”(覆盖原有结果)。
- 若二(5)为“前凸体征”,则初筛结果为“脊柱前凸异常”。
- 若二(5)为“后凸体征”,则初筛结果为“脊柱后凸异常”。
3. **最终结果合并**
- 若脊柱侧弯部分已判定为“脊柱侧弯”或“姿态不良”,且前后弯曲部分也判定为异常,则最终结果为多选(如:["脊柱侧弯(Ⅱ级)", "脊柱前凸异常"])。
- 若脊柱侧弯部分为“正常”,则前后弯曲异常可覆盖结果为异常。
### 输出:
- 返回初筛结果数组,如:`["正常"]`、`["姿态不良"]`、`["脊柱侧弯(Ⅱ级)"]`、`["脊柱前凸异常", "脊柱后凸异常"]`等。
### 代码建议:
- 使用条件分支if/else 或 switch实现多级判断。
- 使用数组存储多选结果。
- 对ATR值进行范围校验030
- 可使用常量或枚举定义选项值,提高可读性。
```

16
月度/封面.base Normal file
View File

@@ -0,0 +1,16 @@
formulas:
图片: file.embeds.filter(value.containsAny("png","jpg","webp","svg","jpeg"))[0]
properties:
formula.图片:
displayName: first_image
views:
- type: cards
name: 视图
filters:
and:
- file.basename.endsWith("月")
- file.ext == "md"
image: formula.图片
imageFit: ""
imageAspectRatio: 1.2
cardSize: 160