AppML 案例 Employees

员工管理案例的完整实现:模型、数据、页面与日期处理。

Intermediate
Key Points员工案例的重点是日期字段:入职日期用 date 类型,排序按日期而不是字符串。

数据

JSON
[
  { "id": 101, "name": "张伟", "title": "后端工程师", "dept": "技术部", "hiredate": "2021-03-15", "email": "zhangwei@example.com" },
  { "id": 102, "name": "李娜", "title": "产品经理",   "dept": "产品部", "hiredate": "2019-08-01", "email": "lina@example.com" },
  { "id": 103, "name": "王强", "title": "测试工程师", "dept": "技术部", "hiredate": "2023-01-09", "email": "wangqiang@example.com" },
  { "id": 104, "name": "赵敏", "title": "设计师",     "dept": "设计部", "hiredate": "2022-11-21", "email": "zhaomin@example.com" }
]

Store dates as ISO YYYY-MM-DD so string order matches chronological order and timezones cannot shift them. With 2021/3/15 style, sorting compares strings and 2021/11/1 lands before 2021/3/15.

模型

XML
<appml>
  <datasource>
    <query>data/employees.json</query>
  </datasource>
  <html>
    <title>员工管理</title>
  </html>
  <items>
    <item name="id"       label="工号"     type="number" primarykey="true" readonly="true"/>
    <item name="name"     label="姓名"     required="true" maxlength="20"/>
    <item name="title"    label="职位"     required="true" maxlength="30"/>
    <item name="dept"     label="部门"     default="技术部"/>
    <item name="hiredate" label="入职日期" type="date" required="true"/>
    <item name="email"    label="邮箱"     type="email"/>
  </items>
</appml>

页面

HTML
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>员工管理</title>
  <script src="js/appml.js"></script>
  <style>
    body { font-family: system-ui, sans-serif; margin: 2rem; color: #1f2937; }
    table { border-collapse: collapse; min-width: 640px; }
    th, td { border: 1px solid #d1d5db; padding: .45rem .8rem; }
    th { background: #f3f4f6; text-align: left; }
    td:nth-child(1), td:nth-child(5) { text-align: right; }
  </style>
</head>
<body>
  <h1>员工管理</h1>
  <appml-app src="models/employees.xml">
    <appml-view view="list"></appml-view>
    <appml-view view="form"></appml-view>
  </appml-app>
</body>
</html>
Output
工号  姓名  职位        部门    入职日期      邮箱
101   张伟  后端工程师  技术部  2021-03-15   zhangwei@example.com
102   李娜  产品经理    产品部  2019-08-01   lina@example.com
103   王强  测试工程师  技术部  2023-01-09   wangqiang@example.com
104   赵敏  设计师      设计部  2022-11-21   zhaomin@example.com

按部门分组

JavaScript
function employeesController(appml) {
  appml.onload = function () {
    const groups = {};
    appml.data.forEach((e) => {
      (groups[e.dept] = groups[e.dept] || []).push(e);
    });
    console.log(groups);
    // { 技术部: [...], 产品部: [...], 设计部: [...] }
  };
}

AppML has no grouped view; aggregation from appml.data is up to you. Rendering a grouped UI means abandoning templates and building DOM yourself — a typical limit of the framework.

工龄计算

JavaScript
function yearsOfService(hiredate) {
  const start = new Date(hiredate);
  const now = new Date();
  let years = now.getFullYear() - start.getFullYear();
  const beforeAnniversary =
    now.getMonth() < start.getMonth() ||
    (now.getMonth() === start.getMonth() && now.getDate() < start.getDate());
  if (beforeAnniversary) years -= 1;
  return years;
}

Dividing a millisecond difference by 365 days is wrong across leap years and year boundaries. Compute the year difference and subtract one if this year's anniversary has not passed.

Dates are strings in JSON, and new Date('2021-03-15') parses as UTC midnight — 08:00 in UTC+8, and in some older browsers as local UTC-8 time, off by a day. Parse with split('-') when the exact date matters.

完整目录

Text
appml-employees/
├── index.html
├── js/appml.js
├── models/employees.xml
└── data/employees.json

Four files and it runs. In a real project the data comes from an API: point <query> at a URL returning JSON and nothing else changes.

Friends & Partners