2026-10-03 16:12:25 +08:00
<!doctype html>
< html lang = "zh-CN" >
< head >
< meta charset = "utf-8" >< meta name = "viewport" content = "width=device-width,initial-scale=1" >
2026-10-03 20:05:05 +08:00
< title > 赵府智家 · 家庭空间</ title >< link rel = "icon" type = "image/png" href = "/zhao-icon.png" >< link rel = "apple-touch-icon" href = "/zhao-icon.png" >< meta name = "theme-color" content = "#10191d" >< link rel = "stylesheet" href = "/style.css?v=__ASSET_VERSION__" >< link rel = "stylesheet" href = "/family-map.css?v=__ASSET_VERSION__" >
< script defer src = "/vendor/hls.min.js?v=__ASSET_VERSION__" ></ script >< script defer src = "/live-player.js?v=__ASSET_VERSION__" ></ script >< script defer src = "/kinship.js?v=__ASSET_VERSION__" ></ script >< script defer src = "/family-graph.js?v=__ASSET_VERSION__" ></ script >< script defer src = "/calendar.js?v=__ASSET_VERSION__" ></ script >< script defer src = "/app.js?v=__ASSET_VERSION__" ></ script >< script defer src = "/monitor.js?v=__ASSET_VERSION__" ></ script >< script defer src = "/date-fields.js?v=__ASSET_VERSION__" ></ script >< script defer src = "/family-map.js?v=__ASSET_VERSION__" ></ script >< script defer src = "/family.js?v=__ASSET_VERSION__" ></ script >< script defer src = "/family-events.js?v=__ASSET_VERSION__" ></ script >
2026-10-04 04:52:39 +08:00
< script defer src = "/family-history.js?v=__ASSET_VERSION__" ></ script >
< script defer src = "/camera-settings.js?v=__ASSET_VERSION__" ></ script >
2026-10-04 08:33:00 +08:00
< script defer src = "/recording-ranges.js?v=__ASSET_VERSION__" ></ script >< script defer src = "/recording-ui.js?v=__ASSET_VERSION__" ></ script >< script defer src = "/snapshot.js?v=__ASSET_VERSION__" ></ script >
2026-10-03 16:12:25 +08:00
</ head >
< body >
< aside class = "sidebar" >
2026-10-03 18:29:18 +08:00
< a class = "brand" href = "/" >< img class = "brand-icon" src = "/zhao-icon.png" alt = "赵字古文字风格标识" >< span > 赵府智家< small > HOME / 本地家庭空间</ small ></ span ></ a >
2026-10-03 16:12:25 +08:00
< div class = "nav-label" > 工作空间</ div >
< nav aria-label = "主导航" >
< button data-page = "live" class = "active" > ◫ < span > 实时画面</ span ></ button >
< button data-page = "playback" > ◷ < span > 录像回放</ span ></ button >
2026-10-03 17:41:52 +08:00
< button data-page = "family" > ♧ < span > 家谱</ span ></ button >
< button data-page = "users" data-admin > ♙ < span > 账号与关系</ span ></ button >
2026-10-03 16:12:25 +08:00
< button data-page = "objects" > ▣ < span > 摄像头对象</ span ></ button >< button data-page = "recorders" > ▤ < span > 录像机</ span ></ button >< button data-page = "cameras" > ◫ < span > 镜头通道</ span ></ button >
< button data-page = "sites" > ⌂ < span > 空间档案</ span ></ button >
< button data-page = "storage" > ▤ < span > 录像与存储</ span ></ button >
</ nav >
< div class = "side-note" >< span class = "dot" ></ span > 自有部署 · 本地存储< p > 按空间组织画面< br > 让每一段记录有处可寻</ p ></ div >
2026-10-04 04:52:39 +08:00
< p id = "current-user" class = "description" ></ p >< button id = "account-password" class = "quiet" hidden > 修改我的密码</ button >< button id = "logout" class = "quiet" > 退出登录</ button >
2026-10-03 16:12:25 +08:00
</ aside >
< main >
2026-10-03 17:41:52 +08:00
< header >< div >< div class = "eyebrow" > ZHAOFU HOME / FAMILY</ div >< h1 id = "page-title" > 实时画面</ h1 >< p id = "page-note" > 从一个空间,看到每一个位置。</ p ></ div >< div class = "header-status" >< span id = "service-status" class = "badge" > 等待连接</ span >< span id = "clock" ></ span ></ div ></ header >
2026-10-03 16:12:25 +08:00
< div id = "banner" class = "banner" hidden ></ div >
< section class = "metrics" >< div >< span > 摄像头</ span >< strong id = "metric-all" > —</ strong ></ div >< div >< span > 已接通码流</ span >< strong id = "metric-ready" > —</ strong ></ div >< div >< span > 录像占用</ span >< strong id = "metric-used" > —</ strong ></ div >< div >< span > 空间档案</ span >< strong id = "metric-sites" > —</ strong ></ div ></ section >
< div class = "filter-row" >< label > 空间范围 < select id = "site-filter" >< option value = "" > 全部空间</ option ></ select ></ label >< span id = "filter-caption" > 家庭与公司,分别管理</ span >< button id = "refresh" class = "quiet" > ↻ 刷新状态</ button ></ div >
2026-10-04 08:33:00 +08:00
< section id = "page-live" class = "page" >< div class = "section-head" >< h2 > 现场画面 < small > LIVE VIEW</ small ></ h2 >< div >< label > 清晰度 < select id = "quality" >< option value = "hd" > 主码流</ option >< option value = "compat" > 子码流</ option ></ select ></ label >< button data-action = "new-camera" > + 添加镜头通道</ button ></ div ></ div >< p class = "description" id = "quality-note" > 主码流画面更清晰,最高 1920×1080;子码流更流畅,最高 768×432,适合网络较慢时使用。</ p >< div class = "wall-toolbar" >< label > 分屏 < select id = "wall-layout" >< option value = "auto" > 自适应</ option >< option value = "1" > 1 画面</ option >< option value = "2" > 2 画面</ option >< option value = "4" > 4 画面</ option >< option value = "6" > 6 画面</ option >< option value = "9" > 9 画面</ option >< option value = "16" > 16 画面</ option ></ select ></ label >< label class = "check" >< input id = "wall-arrange" type = "checkbox" > 调整顺序</ label >< div class = "wall-paging" >< button id = "wall-prev" class = "quiet" aria-label = "上一组画面" > ‹ </ button >< span id = "wall-page" ></ span >< button id = "wall-next" class = "quiet" aria-label = "下一组画面" > › </ button ></ div >< span id = "wall-clock" ></ span >< button id = "wall-fullscreen" > 全屏监控</ button ></ div >< div id = "live-grid" class = "live-grid" ></ div >< section id = "ptz-panel" class = "ptz-panel" hidden >< div >< strong id = "ptz-title" > 云台</ strong >< p id = "ptz-status" role = "status" ></ p ></ div >< div class = "ptz-pad" >< button data-ptz-action = "up" aria-label = "云台向上" > ↑</ button >< button data-ptz-action = "left" aria-label = "云台向左" > ←</ button >< button data-ptz-action = "stop" > 停止</ button >< button data-ptz-action = "right" aria-label = "云台向右" > →</ button >< button data-ptz-action = "down" aria-label = "云台向下" > ↓</ button ></ div >< div id = "ptz-presets" >< div class = "section-head" >< strong > 常用位置 < small id = "preset-count" ></ small ></ strong >< button id = "preset-reload" class = "quiet" > 重新读取</ button ></ div >< p id = "preset-status" role = "status" ></ p >< div id = "preset-list" ></ div >< p class = "description" > 调整位置后可另存为新预置位。本版不覆盖已有位置,避免设备固件拒绝或误改。</ p >< form id = "preset-form" hidden >< label > 当前位置名称< input id = "preset-name" required maxlength = "40" placeholder = "例如:大门、院子" ></ label >< button type = "submit" > 保存当前位置</ button ></ form >< div id = "preset-confirmation" hidden >< p id = "preset-confirm-text" ></ p >< button id = "preset-confirm-yes" > 确认</ button >< button id = "preset-confirm-cancel" class = "quiet" > 取消</ button ></ div ></ div >< button id = "ptz-close" class = "quiet" > 收起云台</ button ></ section ></ section >
2026-10-03 16:12:25 +08:00
< section id = "page-playback" class = "page" hidden >
< div class = "section-head" >< h2 > 回到那一刻 < small > PLAYBACK</ small ></ h2 ></ div >
< div class = "panel playback-controls" >< label > 摄像头< select id = "play-camera" ></ select ></ label >< label > 录像来源< select id = "archive-source" >< option value = "recorder" > 录像机原有录像</ option >< option value = "local" > 小电脑本机录像</ option ></ select ></ label >< label > 日期< input id = "play-date" type = "date" ></ label >< button id = "query-recordings" > 查找录像</ button >< span id = "play-info" > 选择日期,查看实际录像时段</ span ></ div >
< div class = "video-panel" >< video id = "play-video" controls playsinline ></ video >< div id = "play-empty" class = "video-empty" > 选择一个有录像的时间段</ div ></ div >
2026-10-03 17:10:06 +08:00
< div class = "panel" >< div class = "timeline-head" >< strong > 当日时间轴</ strong >< span >< i class = "legend" ></ i > 有录像的时段 · 点击定位</ span ></ div >< canvas id = "timeline" height = "76" aria-label = "录像时间轴" ></ canvas >< div class = "time-labels" >< span > 00:00</ span >< span > 06:00</ span >< span > 12:00</ span >< span > 18:00</ span >< span > 24:00</ span ></ div >< div class = "seek-row" >< label > 定位时间 < input id = "seek-time" type = "time" step = "1" value = "12:00:00" ></ label >< button id = "seek-button" class = "secondary" > 定位播放</ button >< a id = "download" class = "button secondary" hidden > 下载原始片段</ a ></ div ></ div >
2026-10-04 08:33:00 +08:00
< div class = "panel" >< div class = "playback-tools" >< label class = "check" >< input id = "play-autonext" type = "checkbox" checked > 自动续播下一时段(跳过空档)</ label >< button id = "play-snapshot" class = "quiet" > 回放截图</ button >< span id = "play-position" role = "status" ></ span ></ div >< details class = "clip-editor" >< summary > 选取并下载指定片段</ summary >< form id = "clip-form" >< div class = "form-grid" >< label > 开始时间< input id = "clip-start" type = "datetime-local" step = "1" required ></ label >< label > 结束时间< input id = "clip-end" type = "datetime-local" step = "1" required ></ label ></ div >< div class = "playback-tools" >< button type = "button" class = "quiet" data-clip-mark = "start" > 当前位置作起点</ button >< button type = "button" class = "quiet" data-clip-mark = "end" > 当前位置作终点</ button >< button type = "submit" > 生成下载链接</ button >< a id = "clip-download" class = "button secondary" hidden > 下载所选片段</ a ></ div >< p id = "clip-status" role = "status" class = "description" ></ p >< p class = "description" > 每段最多一小时,不可跨越无录像时段。下载保留原始编码,剪辑边界可能受设备关键帧影响。</ p ></ form ></ details ></ div >< div id = "recording-list" class = "recording-list" ></ div >
2026-10-03 16:12:25 +08:00
</ section >
< section id = "page-cameras" class = "page" hidden >< div class = "section-head" >< h2 > 镜头通道 < small > CHANNELS</ small ></ h2 >< button data-action = "new-camera" > + 添加镜头通道</ button ></ div >< div class = "panel discovery" >< div >< strong > 发现局域网设备</ strong >< p > 探测 RTSP 服务,添加后用设备账号连接。</ p ></ div >< input id = "scan-network" placeholder = "例如 192.168.1.0/24" aria-label = "局域网网段" >< button id = "scan-button" class = "secondary" > 开始探测</ button ></ div >< div id = "scan-result" ></ div >< div id = "camera-list" ></ div ></ section >
< section id = "page-objects" class = "page" hidden >< div class = "section-head" >< h2 > 摄像头对象 < small > CAMERA ASSETS</ small ></ h2 >< button data-action = "new-asset" > + 新建摄像头对象</ button ></ div >< p class = "description" > 一台实体摄像头对应一个对象,双镜头在对象下建立两个镜头通道;每个镜头分别有主码流和子码流。</ p >< div id = "asset-list" class = "site-grid" ></ div ></ section >
< section id = "page-recorders" class = "page" hidden >< div class = "section-head" >< h2 > 录像机 < small > RECORDERS</ small ></ h2 >< button data-action = "new-recorder" > + 添加录像机</ button ></ div >< p class = "description" > 统一保存录像机地址与账号,镜头通道关联录像机。实时取流使用 RTSP;读取录像机已有历史录像,需要该型号的回放接口适配。</ p >< div id = "recorder-list" class = "site-grid" ></ div ></ section >
< section id = "page-sites" class = "page" hidden >< div class = "section-head" >< h2 > 空间档案 < small > PLACES</ small ></ h2 >< button data-action = "new-site" > + 新建空间</ button ></ div >< p class = "description" > 为家庭、公司或其他场所建立地址档案,再关联摄像头。地区、小区、楼栋和门牌都是独立属性。</ p >< div id = "site-list" class = "site-grid" ></ div ></ section >
2026-10-03 17:21:25 +08:00
< section id = "page-storage" class = "page" hidden >< div class = "section-head" >< h2 > 录像与存储 < small > STORAGE</ small ></ h2 ></ div >< div class = "storage-grid" >< form id = "storage-form" class = "panel" >< h3 > 录像保留策略</ h3 >< label > 保留天数< input name = "retentionDays" type = "number" min = "1" max = "365" required ></ label >< label > 录像容量上限(GB) < input name = "maxGB" type = "number" min = "5" max = "100000" required ></ label >< label > 磁盘预留空间(GB) < input name = "reserveGB" type = "number" min = "2" max = "1000" required ></ label >< p class = "description" > 超过保留天数的录像会自动删除。达到容量上限或预留空间不足时暂停录像;调整策略后自动恢复。容量每 20 秒检查一次,可能有少量超出。</ p >< button type = "submit" > 保存策略</ button >< span class = "form-error" ></ span ></ form >< div class = "panel" >< h3 > 运行状态</ h3 >< dl id = "storage-status" ></ dl >< p class = "description" > 开启摄像头的“持续录像”后,服务会保存主码流。预览默认使用主码流高清画面(最高 1920×1080、15 帧/秒),也可切换子码流流畅画面(最高 768×432、10 帧/秒)。本机录像保留设备原始编码。</ p >< h3 > 最近操作</ h3 >< div id = "audit-list" ></ div ></ div ></ div ></ section >
2026-10-03 17:41:52 +08:00
< section id = "page-family" class = "page" hidden >
< div class = "section-head" >< h2 > 家族的来处与延续 < small > FAMILY REGISTER</ small ></ h2 >< div >< button id = "family-reload" class = "quiet" > 重新载入</ button >< button id = "family-export" class = "quiet" > 导出家谱</ button >< button id = "new-person" > + 录入人物</ button ></ div ></ div >
2026-10-03 20:02:07 +08:00
< p class = "description" > 从祖辈到后辈,一张图看全家。点击人物查看档案,暖金色卡片是当前账号关联的本人。</ p >
< div class = "panel family-toolbar" >< label > 关系参照人物< select id = "family-reference" ></ select ></ label >< label > 查找人物< input id = "family-search" type = "search" placeholder = "姓名、别名或籍贯" ></ label >< button id = "family-find" class = "quiet" hidden > 定位搜索结果</ button >< label class = "check" >< input id = "family-archived" type = "checkbox" > 显示归档人物</ label >< span id = "family-count" ></ span ></ div >
2026-10-03 17:41:52 +08:00
< div id = "family-error" class = "form-error" role = "status" ></ div >
2026-10-03 20:02:07 +08:00
< div id = "family-workspace" class = "family-workspace" >
< section id = "family-canvas-panel" class = "family-canvas-panel" aria-label = "全家关系图" >
< div class = "family-map-heading" >< div >< span class = "eyebrow" > FAMILY CONNECTIONS</ span >< h2 id = "family-view-title" > 全家关系图</ h2 ></ div >< div class = "family-view-tabs" role = "group" aria-label = "家谱显示方式" >< button id = "family-view-tree" class = "quiet" aria-pressed = "true" > 关系图</ button >< button id = "family-view-list" class = "quiet" aria-pressed = "false" > 人物名册</ button >< button id = "family-view-timeline" class = "quiet" aria-pressed = "false" > 家族时间线</ button ></ div ></ div >
< div id = "family-map-controls" class = "family-map-controls" >< div class = "family-zoom-controls" >< button id = "family-zoom-out" class = "quiet" aria-label = "缩小家谱" > − </ button >< output id = "family-zoom-value" aria-live = "polite" > 100%</ output >< button id = "family-zoom-in" class = "quiet" aria-label = "放大家谱" > + </ button >< button id = "family-fit" class = "quiet" > 查看全谱</ button ></ div >< button id = "family-locate-self" class = "quiet" > ◎ 定位本人</ button >< button id = "family-fullscreen" class = "quiet" > 全屏家谱</ button ></ div >
< div id = "family-tree" class = "family-map-viewport" tabindex = "0" role = "region" aria-label = "家谱关系图,可拖动空白处或使用滚动条浏览" ></ div >
< div id = "family-people" class = "family-people family-register" hidden ></ div >
< section id = "family-events" hidden aria-label = "家族重大记事" >
< div class = "family-event-intro" >< div >< h3 > 把值得记住的事,留给后来的人</ h3 >< p class = "description" > 按事情发生的日期排列,可关联多位亲人,并附上详细记载或报道链接。</ p ></ div >< button id = "family-new-event" > + 写一则记事</ button ></ div >
< div class = "family-event-filters" >< label > 关联人物< select id = "family-event-person" >< option value = "" > 全家</ option ></ select ></ label >< label > 年份< select id = "family-event-year" >< option value = "" > 所有年份</ option ></ select ></ label >< label > 排列< select id = "family-event-order" >< option value = "desc" > 从近到远</ option >< option value = "asc" > 从远到近</ option ></ select ></ label >< label > 搜索记事< input id = "family-event-search" type = "search" placeholder = "标题、摘要或正文" ></ label >< label class = "check" >< input id = "family-event-relatives" type = "checkbox" > 包括此人的父母、配偶和子女</ label >< label id = "family-event-state-label" > 状态< select id = "family-event-state" >< option value = "published" > 已发布</ option >< option value = "draft" > 草稿箱</ option >< option value = "archived" > 已归档</ option >< option value = "all" > 全部</ option ></ select ></ label >< button id = "family-event-clear" class = "quiet" > 清除筛选</ button ></ div >
< p id = "family-event-count" class = "description" role = "status" ></ p >< div id = "family-timeline" class = "family-timeline" ></ div >
</ section >
< div id = "family-map-footer" class = "family-map-footer" >< div class = "family-map-legend" >< span >< i class = "legend-self" ></ i > 本人</ span >< span >< i class = "legend-selected" ></ i > 正在查看</ span >< span >< i class = "legend-parent" ></ i > 父母 → 子女</ span >< span >< i class = "legend-spouse" ></ i > 配偶</ span >< span >< i class = "legend-adoptive" ></ i > 收养 / 继亲</ span ></ div >< p id = "family-map-note" class = "description" role = "status" ></ p >< span class = "description" > 拖动空白处移动 · 点击人物查看档案 · 关系称谓按参照人物计算</ span ></ div >
</ section >
< aside id = "family-detail" class = "panel family-inspector" aria-label = "人物档案" ></ aside >
</ div >
2026-10-03 17:41:52 +08:00
</ section >
< section id = "page-users" class = "page" hidden >< div class = "section-head" >< h2 > 账号与人物关系 < small > ACCOUNTS</ small ></ h2 >< button id = "new-user" > + 新建账号</ button ></ div >< p class = "description" > 亲属称呼用于描述人物关系。摄像头空间权限、家谱权限和管理员身份分别设置。无需为每一位家谱人物创建账号。</ p >< div id = "user-list" ></ div ></ section >
< footer >< span > 赵府智家 · 家庭空间</ span >< span id = "version" > 独立部署 / 数据自有</ span ></ footer >
2026-10-03 16:12:25 +08:00
</ main >
2026-10-03 17:41:52 +08:00
< dialog id = "auth-dialog" >< form id = "auth-form" >< span class = "eyebrow" > WELCOME HOME</ span >< h2 id = "auth-title" > 欢迎回来</ h2 >< p id = "auth-note" > 使用自己的账号,进入家庭空间。</ p >< label id = "setup-code-label" hidden > 初始化码< input name = "code" autocomplete = "off" ></ label >< label > 用户名< input name = "username" value = "admin" maxlength = "32" required autocomplete = "username" ></ label >< label > 密码< input name = "password" type = "password" minlength = "8" maxlength = "128" required autocomplete = "current-password" ></ label >< p class = "form-error" ></ p >< button type = "submit" class = "wide" > 进入系统</ button ></ form ></ dialog >
2026-10-03 16:12:25 +08:00
< dialog id = "site-dialog" >< form id = "site-form" >< div class = "dialog-heading" >< h2 > 空间档案</ h2 >< button type = "button" class = "quiet" data-close = "site-dialog" > 关闭</ button ></ div >< input name = "id" type = "hidden" >< div class = "form-grid" >< label > 空间名称 *< input name = "name" required maxlength = "100" placeholder = "例如:莱阳老家" ></ label >< label > 用途< select name = "kind" >< option value = "home" > 家庭</ option >< option value = "company" > 公司</ option >< option value = "other" > 其他</ option ></ select ></ label >< label > 所属家庭 / 单位< input name = "owner" maxlength = "100" ></ label >< label > 省 / 直辖市< input name = "province" maxlength = "100" ></ label >< label > 城市< input name = "city" maxlength = "100" ></ label >< label > 区 / 县< input name = "district" maxlength = "100" ></ label >< label > 街道 / 乡镇< input name = "street" maxlength = "100" ></ label >< label > 小区 / 园区 / 村< input name = "community" maxlength = "100" ></ label >< label > 楼栋< input name = "building" maxlength = "100" placeholder = "例如:3 号楼" ></ label >< label > 单元< input name = "unit" maxlength = "100" ></ label >< label > 楼层< input name = "floor" maxlength = "100" ></ label >< label > 门牌号< input name = "door" maxlength = "100" placeholder = "例如:502" ></ label >< label class = "full" > 详细地址< input name = "address" maxlength = "240" ></ label >< label class = "full" > 备注< input name = "note" maxlength = "240" ></ label ></ div >< p class = "form-error" ></ p >< div class = "dialog-footer" >< button type = "submit" > 保存空间</ button ></ div ></ form ></ dialog >
2026-10-03 16:16:23 +08:00
< dialog id = "camera-dialog" >< form id = "camera-form" >< div class = "dialog-heading" >< h2 > 镜头通道配置</ h2 >< button type = "button" class = "quiet" data-close = "camera-dialog" > 关闭</ button ></ div >< input name = "id" type = "hidden" >< div class = "form-grid" >< label class = "full" > 所属摄像头对象 *< select name = "assetId" required ></ select ></ label >< label > 接入方式< select name = "sourceKind" >< option value = "recorder" > 通过录像机</ option >< option value = "direct" > 直接连接摄像头</ option ></ select ></ label >< label > 关联录像机< select name = "recorderId" >< option value = "" > 请选择</ option ></ select ></ label >< label > 录像机通道编号< input name = "channelNumber" maxlength = "30" placeholder = "按录像机实际通道填写" ></ label >< label > 录像存储设备< select name = "archiveRecorderId" >< option value = "" > 尚未绑定</ option ></ select ></ label >< label > 历史录像主要保存于< select name = "archiveSource" >< option value = "recorder" > 录像机</ option >< option value = "local" > 本机</ option ></ select ></ label >< label > 镜头 / 通道名称 *< input name = "name" required maxlength = "120" placeholder = "例如:大门口" ></ label >< label > 所属空间 *< select name = "siteId" required ></ select ></ label >< label > 安装位置< input name = "point" maxlength = "120" placeholder = "例如:院门外侧" ></ label >< label > 品牌 / 型号< input name = "model" maxlength = "120" ></ label >< label > 设备 IP *< input name = "host" required placeholder = "局域网 IPv4 地址" ></ label >< label > RTSP 端口< input name = "port" type = "number" value = "554" min = "1" max = "65535" required ></ label >< label > 设备用户名< input name = "username" maxlength = "120" autocomplete = "off" ></ label >< label > 设备密码< input name = "password" type = "password" maxlength = "256" autocomplete = "new-password" placeholder = "编辑时留空,保留原密码" ></ label >< div class = "full" >< button id = "onvif-read" type = "button" class = "secondary" > 读取 ONVIF 镜头配置</ button >< p class = "description" > 直接接入摄像头时,可读取设备实际提供的媒体配置。默认 ONVIF HTTP 端口为 80。</ p >< div id = "onvif-result" ></ div ></ div >< label class = "full" > 常见码流路径< select id = "path-preset" >< option value = "custom" > 手动填写</ option >< option value = "tplink" > TP-Link 单镜头</ option >< option value = "hikvision" > 海康威视 / 兼容路径 · 通道 1</ option >< option value = "dahua" > 大华 / 兼容路径 · 通道 1</ option ></ select ></ label >< label class = "full" > 主码流路径 *< input name = "mainPath" required maxlength = "500" value = "/stream1" ></ label >< label class = "full" > 子码流路径 *< input name = "subPath" required maxlength = "500" value = "/stream2" ></ label >< label class = "check" >< input name = "enabled" type = "checkbox" checked > 启用连接</ label >< label class = "check" >< input name = "record" type = "checkbox" > 在小电脑额外保存录像(可选)</ label ></ div >< p class = "description" > 账号和密码只保存在本机受限数据目录。RTSP 服务响应代表设备可达,实际码流接通后才显示在线。路径预设需要与设备型号、通道一致。</ p >< p class = "form-error" ></ p >< div class = "dialog-footer" >< button type = "submit" > 保存设备</ button ></ div ></ form ></ dialog >
2026-10-03 16:12:25 +08:00
< dialog id = "asset-dialog" >< form id = "asset-form" >< div class = "dialog-heading" >< h2 > 摄像头对象</ h2 >< button type = "button" class = "quiet" data-close = "asset-dialog" > 关闭</ button ></ div >< input name = "id" type = "hidden" >< div class = "form-grid" >< label > 对象名称 *< input name = "name" required maxlength = "120" placeholder = "例如:院门双镜头摄像头" ></ label >< label > 所属空间 *< select name = "siteId" required ></ select ></ label >< label > 品牌< input name = "brand" maxlength = "120" ></ label >< label > 型号< input name = "model" maxlength = "120" ></ label >< label > 序列号< input name = "serial" maxlength = "120" ></ label >< label > 物理镜头数< input name = "lensCount" type = "number" value = "2" min = "1" max = "16" required ></ label >< label > 安装位置< input name = "point" maxlength = "120" ></ label >< label > 备注< input name = "note" maxlength = "120" ></ label ></ div >< p class = "form-error" ></ p >< div class = "dialog-footer" >< button type = "submit" > 保存对象</ button ></ div ></ form ></ dialog >
< dialog id = "recorder-dialog" >< form id = "recorder-form" >< div class = "dialog-heading" >< h2 > 录像机配置</ h2 >< button type = "button" class = "quiet" data-close = "recorder-dialog" > 关闭</ button ></ div >< input name = "id" type = "hidden" >< div class = "form-grid" >< label > 录像机名称 *< input name = "name" required maxlength = "120" ></ label >< label > 所属空间 *< select name = "siteId" required ></ select ></ label >< label > 品牌< input name = "brand" maxlength = "120" ></ label >< label > 型号< input name = "model" maxlength = "120" ></ label >< label > 录像机 IP *< input name = "host" required ></ label >< label > RTSP 端口< input name = "port" type = "number" value = "554" min = "1" max = "65535" required ></ label >< label > 登录用户名< input name = "username" maxlength = "120" autocomplete = "off" ></ label >< label > 设备密码< input name = "password" type = "password" maxlength = "256" placeholder = "留空保留原密码" autocomplete = "new-password" ></ label >< label class = "full" > 接入驱动< select name = "driver" >< option value = "generic-rtsp" > 通用 RTSP / 手动通道路径</ option >< option value = "hikvision-rtsp" > 海康 / 兼容型号 RTSP 路径</ option >< option value = "tplink-rtsp" > TP-Link RTSP 路径</ option >< option value = "dahua-rtsp" > 大华 / 兼容型号 RTSP 路径</ option ></ select ></ label ></ div >< p class = "description" > 驱动在当前版本提供路径模板。录像机历史录像检索、回放及通道自动导入,需要型号确认后接入,当前尚未实现。</ p >< p class = "form-error" ></ p >< div class = "dialog-footer" >< button type = "submit" > 保存录像机</ button ></ div ></ form ></ dialog >
2026-10-03 18:29:18 +08:00
< dialog id = "user-dialog" >< form id = "user-form" >< div class = "dialog-heading" >< h2 > 账号档案</ h2 >< button type = "button" class = "quiet" data-close = "user-dialog" > 关闭</ button ></ div >< input name = "id" type = "hidden" >< div class = "form-grid" >< label > 用户名 *< input name = "username" required minlength = "3" maxlength = "32" autocomplete = "off" ></ label >< label > 显示名称 *< input name = "name" required maxlength = "80" ></ label >< label > 密码< input name = "password" type = "password" minlength = "8" maxlength = "128" autocomplete = "new-password" placeholder = "编辑时留空保留" ></ label >< label > 系统角色< select name = "role" >< option value = "member" > 个人账号</ option >< option value = "admin" > 管理员</ option ></ select ></ label >< label > 家谱权限< select name = "familyAccess" >< option value = "none" > 不可访问</ option >< option value = "read" > 查看家谱</ option >< option value = "edit" > 录入和维护家谱</ option ></ select ></ label >< label > 关联家谱人物< select name = "personId" ></ select ></ label >< label > 这个账号是< select name = "relatedToId" ></ select ></ label >< label > 的什么关系< input name = "relationship" list = "relationship-choices" maxlength = "40" placeholder = "可选择或自行填写" ></ label >< fieldset class = "full" >< legend > 允许查看摄像头的空间</ legend >< div id = "user-sites" ></ div >< p class = "description" > 个人账号仅能观看已选空间的实时画面和回放;管理员可以管理全部空间。</ p ></ fieldset >< label class = "check" >< input name = "ptzControl" type = "checkbox" > 允许控制已授权空间的摄像头云台</ label >< label class = "check" >< input name = "disabled" type = "checkbox" > 停用账号</ label ></ div >< p class = "form-error" ></ p >< div class = "dialog-footer" >< button type = "submit" > 保存账号</ button ></ div ></ form ></ dialog >
2026-10-03 17:41:52 +08:00
< datalist id = "relationship-choices" ></ datalist >
2026-10-03 18:29:18 +08:00
< dialog id = "person-dialog" >< form id = "person-form" >< div class = "dialog-heading" >< h2 > 家谱人物</ h2 >< button type = "button" class = "quiet" data-close = "person-dialog" > 关闭</ button ></ div >< input name = "id" type = "hidden" >< input name = "revision" type = "hidden" >< div class = "form-grid" >< label > 姓名 / 称呼 *< input name = "name" required maxlength = "80" placeholder = "姓名暂不知时可先填称呼" ></ label >< label > 别名 / 字 / 号< input name = "alias" maxlength = "120" ></ label >< label > 性别< select name = "gender" >< option value = "unknown" > 待确认</ option >< option value = "male" > 男</ option >< option value = "female" > 女</ option ></ select ></ label >< label > 在世情况< select name = "lifeStatus" >< option value = "alive" > 在世</ option >< option value = "deceased" > 不在世</ option >< option value = "unknown" > 待确认</ option ></ select ></ label >< fieldset class = "family-date" data-date-field = "birthDate" >< legend > 出生日期</ legend >< input name = "birthDate" type = "hidden" >< label > 历法< select data-calendar aria-label = "出生日期历法" >< option value = "solar" > 公历</ option >< option value = "lunar" > 农历</ option ></ select ></ label >< label > 日期< input data-date-value aria-label = "出生日期" type = "text" inputmode = "numeric" placeholder = "YYYY-MM-DD" maxlength = "10" ></ label >< label data-leap-label class = "check" hidden >< input data-date-leap type = "checkbox" > 闰月</ label >< output data-date-hint aria-live = "polite" > 日期不详可留空</ output ></ fieldset >< fieldset class = "family-date" data-date-field = "deathDate" hidden >< legend > 去世日期</ legend >< input name = "deathDate" type = "hidden" >< label > 历法< select data-calendar aria-label = "去世日期历法" >< option value = "solar" > 公历</ option >< option value = "lunar" > 农历</ option ></ select ></ label >< label > 日期< input data-date-value aria-label = "去世日期" type = "text" inputmode = "numeric" placeholder = "YYYY-MM-DD" maxlength = "10" ></ label >< label data-leap-label class = "check" hidden >< input data-date-leap type = "checkbox" > 闰月</ label >< output data-date-hint aria-live = "polite" > 日期不详可留空</ output ></ fieldset >< label class = "full" > 籍贯 / 出生地< input name = "birthplace" maxlength = "160" ></ label >< label class = "full" > 生平简介< textarea name = "biography" rows = "4" maxlength = "2000" ></ textarea ></ label >< label class = "full" > 备注 / 信息来源< textarea name = "note" rows = "3" maxlength = "500" placeholder = "例如:长辈口述、族谱记载、待考证信息" ></ textarea ></ label >< label class = "check" >< input name = "archived" type = "checkbox" > 归档人物(保留关系,可恢复)</ label ></ div >< p class = "form-error" ></ p >< div class = "dialog-footer" >< button type = "submit" > 保存人物</ button ></ div ></ form ></ dialog >
2026-10-03 17:41:52 +08:00
< dialog id = "relation-dialog" >< form id = "relation-form" >< div class = "dialog-heading" >< h2 > 连接人物关系</ h2 >< button type = "button" class = "quiet" data-close = "relation-dialog" > 关闭</ button ></ div >< input name = "id" type = "hidden" >< input name = "revision" type = "hidden" >< div class = "form-grid" >< label > 关系类型< select name = "kind" >< option value = "parent" > 父母 → 子女</ option >< option value = "spouse" > 配偶 ↔ 配偶</ option ></ select ></ label >< label > 亲子属性< select name = "lineage" >< option value = "unspecified" > 未注明</ option >< option value = "biological" > 亲生</ option >< option value = "adoptive" > 收养</ option >< option value = "step" > 继亲</ option ></ select ></ label >< label > 父母一方 / 配偶一方< select name = "fromId" required ></ select ></ label >< label > 子女 / 另一位配偶< select name = "toId" required ></ select ></ label >< label class = "full" > 关系备注< input name = "note" maxlength = "300" ></ label >< label class = "check" >< input name = "active" type = "checkbox" checked > 关系有效(取消后保留记录,可恢复)</ label ></ div >< p class = "description" > 每条亲子关系连接一位父母与一位子女。录入另一位父母时,再建立一条关系。</ p >< p class = "form-error" ></ p >< div class = "dialog-footer" >< button type = "submit" > 保存关系</ button ></ div ></ form ></ dialog >
2026-10-03 20:27:11 +08:00
< dialog id = "event-dialog" aria-labelledby = "event-editor-title" >< form id = "event-form" >< div class = "dialog-heading" >< h2 id = "event-editor-title" > 写一则家族记事</ h2 >< button type = "button" class = "quiet" data-close = "event-dialog" > 关闭</ button ></ div >< input name = "id" type = "hidden" >< input name = "revision" type = "hidden" >< div class = "form-grid" >< label class = "full" > 记事标题 *< input name = "title" required maxlength = "160" placeholder = "用一句话概括这件事" ></ label >< fieldset class = "family-date full" data-date-field = "eventDate" >< legend > 事情发生的日期 *</ legend >< input name = "eventDate" type = "hidden" >< label > 历法< select data-calendar aria-label = "记事日期历法" >< option value = "solar" > 公历</ option >< option value = "lunar" > 农历</ option ></ select ></ label >< label > 日期< input data-date-value aria-label = "记事日期" required type = "text" inputmode = "numeric" placeholder = "YYYY-MM-DD" maxlength = "10" ></ label >< label data-leap-label class = "check" hidden >< input data-date-leap type = "checkbox" > 闰月</ label >< output data-date-hint aria-live = "polite" ></ output ></ fieldset >< fieldset class = "full" >< legend > 关联人物(可多选)</ legend >< input id = "event-person-search" type = "search" placeholder = "查找要关联的亲人" aria-label = "查找关联人物" >< div id = "event-person-choices" ></ div >< p class = "description" > 未选择人物时记为全家记事。每位关联人物的档案都可以追溯到这条记事。</ p ></ fieldset >< label class = "full" > 摘要< textarea name = "summary" maxlength = "400" rows = "2" placeholder = "简要说明这件事" ></ textarea ></ label >< label class = "full" > 详细记载< textarea name = "body" maxlength = "12000" rows = "7" placeholder = "记录经过、意义、长辈口述或资料出处。可分段书写。" ></ textarea ></ label >< label > 报道 / 资料来源< input name = "sourceName" maxlength = "160" placeholder = "例如:报刊名称、个人博客" ></ label >< label > 原始报道链接< input name = "sourceUrl" type = "url" maxlength = "2000" placeholder = "https://…" ></ label >< label class = "check full" >< input name = "archived" type = "checkbox" > 归档记事(保留内容,可恢复)</ label ></ div >< p class = "description" > 正式发布后,有家谱查看权限的账号即可在时间线看到;草稿只对有编辑权限的人可见。</ p >< p class = "form-error" role = "status" ></ p >< div class = "dialog-footer event-editor-actions" >< button type = "submit" data-save-event value = "draft" class = "secondary" > 保存草稿</ button >< button type = "submit" data-publish-event value = "published" > 发布记事</ button >< button type = "submit" data-withdraw-event value = "draft" class = "secondary" hidden > 撤回为草稿</ button ></ div ></ form ></ dialog >
2026-10-03 20:02:07 +08:00
< dialog id = "event-detail-dialog" aria-labelledby = "event-detail-title" >< div class = "dialog-heading" >< span class = "eyebrow" > FAMILY CHRONICLE</ span >< button type = "button" class = "quiet" data-close = "event-detail-dialog" > 关闭</ button ></ div >< article id = "event-detail-content" ></ article ></ dialog >
2026-10-04 04:52:39 +08:00
< dialog id = "history-dialog" aria-labelledby = "history-title" >< div class = "dialog-heading" >< h2 id = "history-title" > 修改记录</ h2 >< button type = "button" class = "quiet" data-close = "history-dialog" > 关闭</ button ></ div >< p class = "description" > 人物、关系与记事每次保存都会留存版本。仅有家谱编辑权限的账号可查阅和恢复。</ p >< p id = "history-error" class = "form-error" role = "status" ></ p >< div id = "history-list" ></ div >< button id = "history-more" class = "quiet" hidden > 加载更早记录</ button >< article id = "history-detail" ></ article ></ dialog >
< dialog id = "password-dialog" aria-labelledby = "password-title" >< form id = "password-form" >< div class = "dialog-heading" >< h2 id = "password-title" > 修改我的密码</ h2 >< button type = "button" class = "quiet" data-close = "password-dialog" > 关闭</ button ></ div >< p id = "password-account" class = "description" ></ p >< label > 当前密码< input name = "currentPassword" type = "password" required maxlength = "128" autocomplete = "current-password" ></ label >< label > 新密码< input name = "newPassword" type = "password" required minlength = "8" maxlength = "128" autocomplete = "new-password" ></ label >< label > 再次输入新密码< input name = "confirmPassword" type = "password" required minlength = "8" maxlength = "128" autocomplete = "new-password" ></ label >< p class = "description" > 保存后,这个账号在所有设备上都需要用新密码重新登录。</ p >< p class = "form-error" role = "status" ></ p >< div class = "dialog-footer" >< button type = "submit" > 保存新密码</ button ></ div ></ form ></ dialog >
2026-10-04 08:33:00 +08:00
< dialog id = "camera-settings-dialog" aria-labelledby = "camera-settings-title" >< div class = "dialog-heading" >< h2 id = "camera-settings-title" > 摄像机参数</ h2 >< button class = "quiet" data-close = "camera-settings-dialog" > 关闭</ button ></ div >< div class = "section-head" >< label > 设置码流< select id = "camera-settings-quality" >< option value = "main" > 主码流</ option >< option value = "sub" > 子码流</ option ></ select ></ label >< button id = "camera-settings-reload" class = "quiet" > 重新读取</ button ></ div >< div id = "camera-settings-info" ></ div >< p id = "camera-settings-status" class = "form-error" role = "status" ></ p >< form id = "camera-image-form" >< h3 > 图像与日夜模式</ h3 >< p class = "description" > 作用于当前物理镜头,主、子码流共用这些图像参数。</ p >< div id = "camera-image-fields" class = "form-grid" ></ div >< div class = "dialog-footer" >< button type = "submit" disabled > 保存图像参数</ button ></ div ></ form >< form id = "camera-video-form" >< h3 > 码流与清晰度</ h3 >< p class = "description" > 作用于上方选定的码流。保存后画面可能短暂重连,录像机也会使用调整后的码流。本页保留原有视频编码。</ p >< div id = "camera-video-fields" class = "form-grid" ></ div >< div class = "dialog-footer" >< button type = "submit" disabled > 保存码流参数</ button ></ div ></ form >< details >< summary > 其他萤石功能的接入情况</ summary >< ul >< li > 云台方向微调与预置位:在实时画面的“云台”中使用,按设备能力启用。</ li >< li > 实时声音与全屏:通过画面播放器控制。</ li >< li > 双向对讲、智能追踪、声光告警、隐私遮蔽、设备翻转、云录像和消息推送:当前尚未接入,请使用萤石 App。</ li >< li > 录像机原有录像:仍通过录像机或原厂 App 查看;本系统已支持本机额外录像的回放。</ li ></ ul >< p class = "description" > 功能按设备实际开放能力逐项接入,型号与固件不同可能有差异。</ p ></ details ></ dialog >
2026-10-03 16:12:25 +08:00
< div id = "toast" role = "status" hidden ></ div >
2026-10-04 08:33:00 +08:00
< dialog id = "snapshot-dialog" aria-labelledby = "snapshot-title" >< div class = "dialog-heading" >< h2 id = "snapshot-title" > 画面截图</ h2 >< button data-close = "snapshot-dialog" class = "quiet" > 关闭</ button ></ div >< img id = "snapshot-image" alt = "当前视频画面截图" >< p id = "snapshot-info" class = "description" ></ p >< a id = "snapshot-save" class = "button" download > 下载 PNG 图片</ a ></ dialog >
2026-10-03 16:12:25 +08:00
</ body >
</ html >