diff --git a/.env b/.env
new file mode 100644
index 0000000..9cf3b4f
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+PROXY_PORT=1081
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3a58136
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,27 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+.idea
+.vscode
+
+# dependencies
+.cache
+node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+~$*
+
diff --git a/yarn/Dockerfile b/yarn/Dockerfile
new file mode 100644
index 0000000..a568e24
--- /dev/null
+++ b/yarn/Dockerfile
@@ -0,0 +1,11 @@
+# 1. 指定基础镜像
+FROM ghcr.io/anomalyco/opencode:1.14.20
+
+# 2. 设置非交互式安装,更新包列表并安装 Python3 和 pip
+# 使用 && 连接命令以减少镜像层数
+RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
+ apk update && \
+ apk add --no-cache python3 py3-pip docker-cli curl bash git yarn
+
+# 3. (可选)创建一个工作目录
+WORKDIR /workspace
\ No newline at end of file
diff --git a/yarn/config/AGENTS.md b/yarn/config/AGENTS.md
new file mode 100644
index 0000000..84a2480
--- /dev/null
+++ b/yarn/config/AGENTS.md
@@ -0,0 +1,501 @@
+
+ # 全局规则
+
+## 交互语言
+- 所有交互一律使用中文(包括问题回答、代码解释、错误说明等)
+- 代码注释使用中文
+- 变量名、函数名等代码标识符使用英文(遵循编程惯例)
+
+## 代码风格
+- 保持代码简洁、易读
+- 遵循项目现有的代码规范和约定
+- 不要添加不必要的注释或解释
+- 字符串排序(如日期 `YYYY-MM-DD`)用纯比较运算符 `a > b ? 1 : a < b ? -1 : 0`,不用 `localeCompare` —— 后者走 ICU 规则,与字典序不严格等价
+
+### observer 使用规范
+
+`observer` 必须跟随 `export`,而非组件定义:
+
+```javascript
+// ✅ 正确:定义与导出分离
+const MyComponent = () => { ... };
+export default observer(MyComponent);
+
+// ✅ 正确:定义与导出合一时
+export const MyComponent = observer(() => { ... });
+
+// ❌ 错误:observer 包裹定义,单独导出
+const MyComponent = observer(() => { ... });
+export default MyComponent;
+```
+
+## 工作原则
+- 优先理解用户意图,必要时主动提问澄清
+- 修改代码前先了解项目结构和现有模式
+- 完成修改后运行测试验证(如果项目有测试)
+- 除非用户明确要求,否则不要提交代码变更
+- **代码查阅确认机制**:当需要阅读代码来确认 API 细节或具体用法时,必须先向用户说明:
+ 1. 为什么要阅读代码(目的)
+ 2. 准备阅读哪些代码(范围)
+ 3. 等待用户决定:
+ - 同意按方案继续阅读
+ - 直接告知具体用法
+ - 修正阅读范围,指定应该阅读哪些代码
+
+## 代码查阅原则
+
+- 当 AGENTS.md 中已提供了完整的代码模板和规范时(如 Entity、Dao、Service、MyBatis XML 等模板),
+ 必须直接按照模板和规范编写代码,**不得**先去阅读现有代码来"学习风格"
+- 只有在以下情况才允许阅读现有代码:
+ 1. 确认某个框架 API 的具体用法或参数
+ 2. 了解某个模块的具体业务逻辑或实现细节
+ 3. 模板和规范中未覆盖的特殊场景
+- 简单说:规范已覆盖的内容 → 直接按规范写;规范未覆盖的内容 → 再去看代码
+- **禁止在规划阶段启动 agent 或工具去阅读现有代码**。
+ 规划必须仅基于两份 AGENTS.md 中的信息进行。
+ 只有在进入实现阶段、且需要确认模板未覆盖的框架 API 细节时,
+ 才允许按「代码查阅确认机制」经用户同意后阅读代码。
+
+## 项目初始化规则
+
+当用户要求"了解项目"、"熟悉规范"或类似指令时:
+
+### 必须做的:
+1. 阅读并理解**全局 AGENTS.md**(`/root/.config/opencode/AGENTS.md`,即本文件)和**项目级 AGENTS.md**(`/workspace/AGENTS.md`,位于项目根目录)中的所有规范
+2. 基于两份 AGENTS.md 中的信息回答项目相关问题
+3. 直接使用两份 AGENTS.md 中的代码模板和规范进行开发
+
+### 禁止做的:
+1. 不要主动阅读实际代码文件来"学习风格"
+2. 不要查看现有模块来"理解代码组织"
+3. 不要假设 AGENTS.md 中的信息不够用
+4. 不要只阅读其中一份 AGENTS.md 而忽略另一份——两份都必须阅读
+
+### 标准回复:
+"已阅读全局和项目级 AGENTS.md,项目采用 [技术栈],包含 [模块数量] 个模块。
+命名规范:[简述]。代码模板已就绪,可以开始开发。"
+
+## 前端项目开发原则(仅限 React 项目)
+
+> **适用范围说明:** 以下原则仅适用于前端 React 项目开发。对于后端项目(Java、Python 等)或其他类型项目,这些规则不适用。
+
+### 1. 架构思维
+
+**分层计算原则**
+- 数据计算按层级划分:原始数据 → 单实体衍生 → 跨实体汇总 → 展示
+- 每一层只做自己该做的事,不越界
+- 体现"关注点分离"的核心思想
+
+**响应式数据流**
+- 状态变化自动触发相关更新,而非手动调用
+- 使用观察者模式(如 autorun)实现自动响应
+- 体现"声明式编程"优于"命令式编程"的理念
+
+### 2. 命名哲学
+
+**语义优先,避免冗余**
+- 命名要清晰表达含义,但不重复上下文
+- 在已知上下文中,省略冗余前缀
+- 嵌套结构表达关联关系(如 `compare.scale.daily`)
+- 体现"代码即文档"的自解释原则
+
+### 3. 职责分离
+
+**逻辑与展示分离**
+- 业务逻辑集中在状态管理层
+- 组件只负责展示和 UI 配置
+- 体现"单一职责原则"
+
+**全局与局部分离**
+- 全局参数集中管理(日期、汇率等)
+- 业务数据按领域分离
+- 体现"高内聚、低耦合"的设计原则
+
+### 4. 工程实践
+
+**渐进式改进**
+- 逐步消除技术债务(如硬编码数据)
+- 暂时不处理的部分明确标注,不阻塞整体进度
+- 体现"持续重构"的工程思维
+
+**一致性原则**
+- 相关文件集中组织(Store、API、Mock 一一对应)
+- 统一的命名规范和文件结构
+- 体现"约定优于配置"的理念
+
+### 5. 数据驱动
+
+**以最细粒度实体为基础**
+- 所有数据围绕最小业务单元组织
+- 汇总数据从细粒度数据派生
+- 体现"数据规范化"的思想
+
+**确定性 Mock**
+- Mock 数据基于种子生成,保证可重复性
+- 体现"可测试性"和"可预测性"的要求
+
+## 代码模板
+
+### Store 模板
+
+```javascript
+import {action, computed, observable} from "mobx";
+import {LocalStore} from "./local.store"; // 如需本地存储继承
+import {XxxApi} from "../api";
+
+export class XxxStore extends LocalStore {
+
+ @observable
+ list = []
+
+ @observable
+ detail = null
+
+ @computed
+ get derivedData() {
+ // 计算衍生数据
+ return this.list.map(item => ({
+ ...item,
+ computedField: item.field * 2
+ }));
+ }
+
+ get storeName() {
+ return "xxx"; // 本地存储 key
+ }
+
+ @action
+ fetchData = async (params) => {
+ this.list = await XxxApi.getList(params);
+ }
+
+ @action
+ fetchDetail = async (id) => {
+ this.detail = await XxxApi.getDetail(id);
+ }
+
+ @action
+ reset = () => {
+ this.list = [];
+ this.detail = null;
+ }
+}
+
+export default new XxxStore();
+```
+
+### API 模板
+
+```javascript
+import request from "../utils/request";
+import qs from "query-string";
+
+// GET 请求
+export const getList = async (query) => {
+ return request.get(qs.stringifyUrl({
+ url: '/xxx', query
+ }, {skipNull: true, skipEmptyString: true}));
+}
+
+// GET 详情
+export const getDetail = async (id) => {
+ return request.get(`/xxx/${id}`);
+}
+
+// POST 创建
+export const create = async (data) => {
+ return request.post('/xxx', {data});
+}
+
+// PUT 更新
+export const update = async (id, data) => {
+ return request.put(`/xxx/${id}`, {data});
+}
+
+// DELETE 删除
+export const remove = async (id) => {
+ return request.delete(`/xxx/${id}`);
+}
+```
+
+### Page 组件模板
+
+```javascript
+import React, {useEffect} from "react";
+import {observer} from 'mobx-react';
+import {PageContainer} from "@ant-design/pro-layout";
+import {useStores} from "../../hooks";
+
+const XxxPage = () => {
+ const {xxxStore} = useStores();
+
+ useEffect(() => {
+ xxxStore.fetchData();
+ }, []);
+
+ return (
+
+ {/* 页面内容 */}
+
+ );
+}
+
+export default observer(XxxPage);
+```
+
+### Hook 模板
+
+```javascript
+import {useState, useEffect, useCallback} from "react";
+
+export const useXxx = (initialValue) => {
+ const [value, setValue] = useState(initialValue);
+
+ const doSomething = useCallback(() => {
+ // 逻辑
+ }, []);
+
+ return {value, setValue, doSomething};
+}
+```
+
+### Mock 数据模板
+
+```javascript
+// mock/xxx.js
+module.exports = {
+ _apis: {
+ getList: "GET /api/v1.0/xxx",
+ getDetail: "GET /api/v1.0/xxx/:id",
+ create: "POST /api/v1.0/xxx",
+ },
+
+ "GET /api/v1.0/xxx": (req, res) => {
+ res.send({
+ status: "success",
+ body: {
+ content: [
+ {id: 1, name: "示例1", field: "value1"},
+ {id: 2, name: "示例2", field: "value2"},
+ ],
+ total: 2,
+ page: 0,
+ size: 20,
+ last: true
+ },
+ success: true
+ });
+ },
+
+ "GET /api/v1.0/xxx/:id": {
+ status: "success",
+ body: {id: 1, name: "示例", field: "value"},
+ success: true
+ },
+
+ "POST /api/v1.0/xxx": {
+ status: "success",
+ body: {id: 3},
+ success: true
+ }
+}
+```
+
+**模板约定说明:**
+
+- **`_apis`**:别名 → 路由字符串的映射,供环境变量细粒度屏蔽指定接口(如 `REACT_APP_MOCK_IGNORE=xxx.create`)。**别名必须与 API 层的导出方法名完全一致**,聚合入口依赖此对应关系做过滤
+- **`_getData()`**:返回模块内数据数组,供其他 mock 模块交叉引用(如创建时校验关联实体是否存在)。仅在模块间有引用需求时提供
+- **路由注册顺序**:具体路由必须**先于**参数路由注册,否则 `:id` 会吞掉字面量路径(如 `/xxx/settings` 必须先于 `/xxx/:id`)
+- **聚合入口**:若用统一入口(如 `mock/index.js`)合并多模块,展开时必须剔除非路由键(`_apis`、`_getData`),否则同名键会被后注册模块覆盖;模块间交叉引用应直接 `require` 目标模块,不经聚合对象
+
+### 图表组件模板
+
+```javascript
+import React from "react";
+import {observer} from 'mobx-react';
+import {Line, Column, Pie} from "@ant-design/charts";
+import {Card, Row, Col, Statistic} from "antd";
+import {useStores} from "../../hooks";
+
+const XxxChart = () => {
+ const {xxxStore} = useStores();
+ const {chartData, summary} = xxxStore;
+
+ // 折线图配置
+ const lineConfig = {
+ data: chartData.lineData,
+ xField: 'date',
+ yField: 'value',
+ seriesField: 'type',
+ };
+
+ // 饼图配置
+ const pieConfig = {
+ data: chartData.pieData,
+ angleField: 'value',
+ colorField: 'type',
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default observer(XxxChart);
+```
+
+## 装饰器语法
+
+项目使用 MobX 5,需要以下 Babel 配置:
+
+```javascript
+// craco.config.js
+babel: {
+ plugins: [
+ ['@babel/plugin-proposal-decorators', {legacy: true}],
+ ["@babel/plugin-proposal-class-properties", {loose: true}],
+ ]
+}
+```
+
+常用装饰器:
+- `@observable` - 声明可观察状态
+- `@action` - 声明修改状态的方法
+- `@computed` - 声明计算属性
+
+## 样式规范
+
+### CSS Modules
+- 文件命名:`xxx.scss` 或 `xxx.module.scss`
+- 自动启用:`src/` 和 `@chaosoft/` 下的 `.scss` 文件
+- 类名转换:kebab-case → camelCase
+
+```scss
+// component.scss
+.container {
+ padding: 16px;
+}
+
+.title-text {
+ font-size: 16px;
+}
+```
+
+```javascript
+// component.js
+import styles from './component.scss';
+
+const Component = () => (
+
+ 标题
+
+);
+```
+
+## VERSION.md 编写规范
+
+### 文件位置
+项目根目录:`{project-root}/VERSION.md`
+
+### 版本号规则
+
+采用语义化版本(Semantic Versioning):`MAJOR.MINOR.PATCH`
+
+| 部分 | 说明 | 示例 |
+|------|------|------|
+| MAJOR | 不兼容的 API 变更 | 1.0.0 → 2.0.0 |
+| MINOR | 向下兼容的功能新增 | 1.0.0 → 1.1.0 |
+| PATCH | 向下兼容的问题修复 | 1.0.0 → 1.0.1 |
+
+### 内容结构
+
+```markdown
+# 项目版本记录
+
+## 当前版本
+v1.0.0 (2026-09-22)
+
+## 版本历史
+
+| 版本 | 日期 | 说明 |
+|------|------|------|
+| v1.0.0 | 2026-09-22 | 初始发布版本 |
+
+## 版本明细
+
+### 待发布
+
+**发布日期:** 待定
+
+**新增功能:**
+- 无
+
+**修复问题:**
+- 无
+
+**变更说明:**
+- 无
+
+---
+
+### v1.0.0
+
+**发布日期:** 2026-09-22
+
+**新增功能:**
+- 客户管理模块(CRUD)
+- 租约管理模块(CRUD)
+
+**修复问题:**
+- 无
+
+**变更说明:**
+- 无
+```
+
+### 待发布章节
+
+- **位置**:固定位于「版本明细」最上面,在所有已发布版本章节之上;全文有且仅有一个
+- **结构**:与版本章节同构 —— `**发布日期:** 待定` + 新增功能 / 修复问题 / 变更说明,以 `---` 与下一章节分隔
+- **用途**:累积当前未发布周期内用户可感知的净变化,同受「记录范围(产品视角)」与「对比基线(净变化原则)」约束
+- **发版迁移**:发版时将其内容整体转为新版本章节(标题改为版本号、发布日期改为实际日期,并同步「当前版本」与「版本历史」表格),随后在其上方重建一个空的「待发布」章节,保证其恒在最上面
+- **常驻保留**:即使本周期无待记录内容,也保留空的「待发布」章节(三项均填「无」),不得删除
+
+### 编写要求
+
+1. **当前版本**:始终显示最新版本号和发布日期
+2. **版本历史表格**:按时间倒序排列(最新版本在最上面)
+3. **版本明细**:
+ - 每个版本一个章节,标题为版本号(如 `### v1.0.0`)
+ - 包含:发布日期、新增功能、修复问题、变更说明
+ - 按时间倒序排列(最新版本在最上面)
+ - 「待发布」章节恒置于最上面(在所有已发布版本章节之上),详见「待发布章节」
+4. **更新时机**:每次发布新版本时更新此文件
+5. **记录范围(产品视角)**:只记录用户可感知的产品功能变化,按最终功能归类为新增 / 修复 / 变更
+ - ✅ 记录:新增页面与菜单、新增图表与指标卡、功能行为与数据口径变化、界面呈现调整、缺陷修复、交付形态变更
+ - ❌ 不记录:技术实现细节(Store / API / 组件拆分、状态管理调整)、代码重构与规范修正、
+ Mock 数据与辅助文档(AGENTS.md、docs/)调整、构建脚本与依赖变更、
+ API 数据结构变更(仅后端可感知的字段调整、接口重构等)
+ - 判断标准:以最终用户(产品使用者)是否可感知为唯一标准,后端开发者的感知不纳入记录范围
+ - 描述以功能名称与用户可见效果表述,不堆砌文件路径、类名、行数等技术标识
+6. **对比基线(净变化原则)**:所有条目必须是「当前状态 vs 上一个已发布版本」的净变化
+ - 同一未发布周期内先新增、后又修复或调整的内容,不单独记录修复/变更,只记录最终功能形态
+ - 判断方法:若某缺陷或行为在上一发布版本中不存在(属本周期新增功能自带),则不写入「修复问题」「变更说明」
+ - 「新增功能」与「变更说明」不重复描述同一动作
+ - 发版前按上一版本 tag 重新逐条核对
diff --git a/yarn/config/opencode.json b/yarn/config/opencode.json
new file mode 100644
index 0000000..c6aea2c
--- /dev/null
+++ b/yarn/config/opencode.json
@@ -0,0 +1,81 @@
+{
+ "$schema": "https://opencode.ai/config.json",
+ "model": "alibaba-cn/qwen3.8-max",
+ "provider": {
+ "bailian-payg": {
+ "npm": "@ai-sdk/anthropic",
+ "name": "Alibaba Cloud Model Studio",
+ "options": {
+ "baseURL": "https://llm-725mrgwyn1rzglgb.cn-beijing.maas.aliyuncs.com/apps/anthropic/v1",
+ "apiKey": "{env:ALIBABA_API_KEY}"
+ },
+ "models": {
+ "qwen3.7-max": {
+ "name": "Qwen3.7 Max",
+ "options": {
+ "thinking": {
+ "type": "enabled",
+ "budgetTokens": 8192
+ }
+ }
+ },
+ "qwen3.7-plus": {
+ "name": "Qwen3.7 Plus",
+ "modalities": {
+ "input": ["text", "image"],
+ "output": ["text"]
+ },
+ "options": {
+ "thinking": {
+ "type": "enabled",
+ "budgetTokens": 8192
+ }
+ }
+ },
+ "qwen3.6-plus": {
+ "name": "Qwen3.6 Plus",
+ "modalities": {
+ "input": ["text", "image"],
+ "output": ["text"]
+ },
+ "options": {
+ "thinking": {
+ "type": "enabled",
+ "budgetTokens": 8192
+ }
+ }
+ }
+ }
+ },
+ "alibaba-cn": {
+ "options": {
+ "apiKey": "{env:ALIBABA_API_KEY}",
+ "baseURL": "https://dashscope.aliyuncs.com/compatible-mode/v1"
+ }
+ }
+ },
+ "mcp": {
+ "chrome-devtools": {
+ "type": "local",
+ "command": [
+ "docker", "run", "--rm", "-i",
+ "-v", "E:/Work/jftech/findash/srcs/findash-admin:/workspace",
+ "chrome-devtools-mcp:node24-v1.1.1",
+ "--browserUrl=http://192.168.3.236:9222"
+ ],
+ "enabled": false
+ }
+ },
+ "server": {
+ "port": 4096,
+ "hostname": "0.0.0.0"
+ },
+ "permission": {
+ "external_directory": {
+ "/var/store/**": "allow"
+ },
+ "edit": {
+ "/var/store/**": "deny"
+ }
+ }
+}
diff --git a/yarn/docker-compose.yml b/yarn/docker-compose.yml
new file mode 100644
index 0000000..98a9fbb
--- /dev/null
+++ b/yarn/docker-compose.yml
@@ -0,0 +1,23 @@
+services:
+ opencode-yarn:
+ image: opencode:yarn1-1.14.20
+ container_name: opencode-yarn
+ environment:
+ - TZ=Asia/Shanghai
+ - ALIBABA_API_KEY=sk-6026a1b171b84c2985c316d063136105
+ - HTTP_PROXY=http://host.docker.internal:${PROXY_PORT}
+ - HTTPS_PROXY=http://host.docker.internal:${PROXY_PORT}
+ - NO_PROXY=localhost,127.0.0.1,host.docker.internal
+ volumes:
+ - ./config:/root/.config/opencode
+ - /var/run/docker.sock:/var/run/docker.sock
+ - ./node/.cache:/usr/local/share/.cache
+ - ./node/.yarnrc:/usr/local/share/.yarnrc
+ - ./projects/${PROJECT_NAME}/node_modules:/workspace/node_modules
+ - ${SRC_PATH}:/workspace
+ working_dir: /workspace
+ networks:
+ - "opencode-net"
+networks:
+ opencode-net:
+ driver: bridge
diff --git a/yarn/node/.yarnrc b/yarn/node/.yarnrc
new file mode 100644
index 0000000..cbb24d8
--- /dev/null
+++ b/yarn/node/.yarnrc
@@ -0,0 +1,9 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+registry "https://registry.npmmirror.com"
+"@chaosoft:registry" "https://nexus.chaosoft.com.cn/repository/npm-public/"
+lastUpdateCheck 1793555433346
+sass_binary_site "https://npmmirror.com/mirrors/node-sass/"
+strict-ssl false
diff --git a/yarn/projects/biz-office-rent-web/.env b/yarn/projects/biz-office-rent-web/.env
new file mode 100644
index 0000000..ce8e3a1
--- /dev/null
+++ b/yarn/projects/biz-office-rent-web/.env
@@ -0,0 +1 @@
+PROJECT_NAME=biz-office-rent-web
\ No newline at end of file
diff --git a/yarn/projects/biz-office-rent-web/startup.bat b/yarn/projects/biz-office-rent-web/startup.bat
new file mode 100644
index 0000000..794cc02
--- /dev/null
+++ b/yarn/projects/biz-office-rent-web/startup.bat
@@ -0,0 +1,36 @@
+@echo off
+chcp 65001 >nul
+setlocal enabledelayedexpansion
+
+set "COMPOSE_CMD=docker compose"
+
+set "PROJECT_ROOT=%~dp0"
+set "PROJECT_ROOT=%PROJECT_ROOT:~0,-1%"
+for %%i in ("%PROJECT_ROOT%\..\..") do set "YARN_ROOT=%%~fi"
+for %%i in ("%YARN_ROOT%\..") do set "SYSTEM_ROOT=%%~fi"
+
+echo %PROJECT_ROOT%
+echo %YARN_ROOT%
+echo %SYSTEM_ROOT%
+
+for %%R in ("%SYSTEM_ROOT%" "%YARN_ROOT%" "%PROJECT_ROOT%") do (
+ if exist "%%R\.env" (
+ set "COMPOSE_CMD=!COMPOSE_CMD! --env-file %%R\.env"
+ echo [FOUND] %%R\.env
+ )
+ if exist "%%R\.env.local" (
+ set "COMPOSE_CMD=!COMPOSE_CMD! --env-file %%R\.env.local"
+ echo [FOUND] %%R\.env.local
+ )
+)
+
+echo.
+
+cd %YARN_ROOT%
+
+::端口跳转,为了使用chrome mcp
+::netsh interface portproxy add v4tov4 listenport=9222 listenaddress=0.0.0.0 connectport=9222 connectaddress=127.0.0.1
+
+echo 执行命令: !COMPOSE_CMD! run --rm opencode-yarn
+!COMPOSE_CMD! run --rm opencode-yarn
+