241 lines
14 KiB
Python
241 lines
14 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""填充《采集表》中「软件的主要功能」「软件的主要特点」两栏。
|
||
源文件:C:/Users/15563/Desktop/软著/软著-机器人智慧服务系统/采集表.doc
|
||
内容依据:《用户操作手册-机器人智慧服务系统-完整版.docx》
|
||
"""
|
||
import zipfile, os, shutil, copy, re, time
|
||
from xml.etree import ElementTree as ET
|
||
|
||
W = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
|
||
def w(t): return '{%s}%s' % (W, t)
|
||
ET.register_namespace('w', W)
|
||
for pfx, uri in (
|
||
('w14', 'http://schemas.microsoft.com/office/word/2010/wordml'),
|
||
('mc', 'http://schemas.openxmlformats.org/markup-compatibility/2006'),
|
||
('v', 'urn:schemas-microsoft-com:vml'),
|
||
('wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'),
|
||
('r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'),
|
||
('m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'),
|
||
('wps', 'http://schemas.microsoft.com/office/word/2010/wordprocessingShape'),
|
||
('wpg', 'http://schemas.microsoft.com/office/word/2010/wordprocessingGroup'),
|
||
('wp14', 'http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing'),
|
||
('w10', 'urn:schemas-microsoft-com:office:word'),
|
||
('w15', 'http://schemas.microsoft.com/office/word/2012/wordml'),
|
||
):
|
||
try: ET.register_namespace(pfx, uri)
|
||
except Exception: pass
|
||
|
||
SRC = r'C:/Users/15563/Desktop/软著/软著-机器人智慧服务系统/采集表.doc'
|
||
TMP = r'D:/code/机器人智慧服务系统/.tmp/采集表_new.doc'
|
||
os.makedirs(os.path.dirname(TMP), exist_ok=True)
|
||
|
||
# ---------------- 内容 ----------------
|
||
FUNC_INTRO = ("本系统是面向光伏电站场景的机器人智能运维平台,采用前后端分离的 B/S 架构,"
|
||
"以三维电子地图为统一空间底座,把巡检机器人、除草机器人、无人机机场、清洗无人机等"
|
||
"智能装备的接入、调度、控制、作业与告警处置集中到统一的 Web 控制台,"
|
||
"实现“一张图指挥、一套流程闭环”。主要功能包括:")
|
||
|
||
FUNC = [
|
||
("(1)系统登录与权限管理:",
|
||
"支持账号密码登录与用户协议确认,未登录访问任意业务页面自动重定向至登录页,"
|
||
"登录态超时后提示并跳回登录页,重新登录可回到原页面。系统采用 RBAC 三级角色权限"
|
||
"(管理员、操作员、观察者),权限差异同时体现在菜单是否可见与按钮是否可操作两个层面;"
|
||
"并支持按组织与场站限定数据可见范围,跨场站数据不在列表中呈现。顶部栏提供场站切换、"
|
||
"全屏控制、中英文切换、用户头像与退出登录入口。"),
|
||
("(2)装备总览:",
|
||
"以五张状态统计卡(无人机机场状态、巡检机器人、除草机器人、清洗无人机、今日任务执行)"
|
||
"按场站汇总装备数量、在线台数与任务完成率;提供基于 Cesium 三维地图与场站正射影像的"
|
||
"装备协同态势图,叠加设备位置、作业路径、分区、障碍物、返航点等图层,支持图层开关与"
|
||
"“定位到机器人”一键聚焦;装备调度列表展示装备名称、类型、当前状态、电量、位置与通讯状态,"
|
||
"支持刷新、编辑设备 SN(可一键复制)、设备类型与设备别名,并可打开设备参数设置弹窗;"
|
||
"设备控制面板展示在线状态、电量、产品类型、SN、激活时间、固件版本,提供控制、回充、返航、"
|
||
"生成任务等快捷操作,无人机展示风速/温度/降雨等飞行条件,地面机器人展示累计作业里程、"
|
||
"面积与时长;另提供 AI 分析与操作建议、控制日志与告警记录、任务执行时间线,便于回溯与研判。"),
|
||
("(3)机器人任务:",
|
||
"顶部六张任务统计卡展示当日作业指标并给出较昨日的变化趋势;机器人路径规划与监控地图"
|
||
"实时显示机器人位置、规划路线与历史轨迹,支持控制模式(本地/自动任务/远程)显示与切换、"
|
||
"定位图层与视频开关、寻车与返航快捷按钮,以及清空实时轨迹、清空规划区域等视图清理操作;"
|
||
"任务下发支持按路线下发(单选,点击路线地图自动飞至该路线)与按区域下发(可多选,"
|
||
"多条路径可拖拽调节执行顺序)两种方式,任务类型分为立即执行与定时任务,定时任务可按天、"
|
||
"按周、按月重复并设置执行日期、执行时间与周期范围,提交前自动校验路径、执行机器人与"
|
||
"定时时间;任务列表分任务池、任务执行计划、历史任务三个页签,支持按状态、机器人与日期"
|
||
"范围筛选,行内提供暂停、恢复、取消(普通取消/强制取消)、删除与继续作业操作,"
|
||
"任务状态覆盖待执行、执行中、已暂停、已完成、执行失败、已取消六种。"),
|
||
("(4)机器人控制:",
|
||
"设备状态面板以列表形式实时刷新电机温度、电流、电压、电量、速度、航向与姿态等十四项"
|
||
"运行参数,每项标注单位与含义;实时视频监控通过 WebRTC 拉取机载摄像头画面,支持前视角、"
|
||
"左视角、右视角、后视角与全景五个视角切换、播放与停止控制,后视角自动叠加倒车辅助线;"
|
||
"设备态势地图实时显示航向角、横滚角与俯仰角,支持清空轨迹与定位到机器人;手柄控制支持"
|
||
"游戏手柄按键映射、控制器连接状态显示以及请求控制、释放控制与权限状态标签;方向盘控制"
|
||
"提供前进、后退、左转、右转与中键停止的屏幕虚拟方向盘,行驶速度可在 0–100% 之间调节,"
|
||
"控制指令以 100 毫秒为周期下发,并集成点火/熄火、底盘升起/下降、割刀加速/减速等执行机构"
|
||
"按钮;功能控制区提供五项辅助开关与红色急停按钮,急停触发后立即下发停车指令并自动补发"
|
||
"复位帧。"),
|
||
("(5)地图编辑:",
|
||
"提供返航点、分区、障碍物点、路径生成四种绘制模式,以及点选工具、机器人选择、撤销与清空"
|
||
"操作,地图区实时显示操作提示与已选点位数量;返航点支持在地图上标注多点、核对坐标后保存,"
|
||
"并可在已配置列表中编辑与删除;分区需不少于三个点位闭合边界,保存时可填写分区名称、"
|
||
"分区编码、默认线路与绑定线路(可多选),用于按区域编排任务;障碍物点用于标记支架基础、"
|
||
"水塘、电杆等固定障碍,标记后路径规划与自动作业自动绕开;路径生成可配置路径名称、"
|
||
"规划类型与作业模式,保存后进入预设路线列表,供任务下发页面直接引用。"),
|
||
("(6)告警中心:",
|
||
"顶部四张统计卡展示今日总告警、今日严重告警、今日待处理与今日已关闭数量并附昨日对比与"
|
||
"升降趋势,下方以折线图、饼图与柱状图分别展示告警趋势、告警类型比例与告警状态统计;"
|
||
"筛选栏支持按告警级别、处理状态、设备 ID 与时间范围组合查询,并提供重置、查询与结果导出;"
|
||
"告警列表展示告警编号、标题、级别、类型、来源设备、发生时间、处理状态等字段;"
|
||
"点击查看可从右侧展开告警详情抽屉,展示告警完整描述并提供联系处理人与一键生成工单入口,"
|
||
"填写处理状态、处理结果、根原因与处理备注后确认处理,告警由待处理流转为已关闭;"
|
||
"告警分提示、一般、重要、严重四级,支持修改告警标题、级别与类型并保留操作记录。"),
|
||
("(7)实时监控与数据统计:",
|
||
"基于 Cesium 三维地图与 MQTT 遥测通道,对设备位置、状态与运动轨迹进行实时渲染与回放,"
|
||
"支持电子围栏与场站可视化监控;历史任务、控制日志与告警记录长期留存并支持多维查询与"
|
||
"趋势分析,运营数据可导出为报表,为作业计划编排、绩效考核与管理决策提供数据支撑。"),
|
||
("(8)工单联动处置:",
|
||
"对需要现场处置的告警可一键转为运维工单,系统自动带出告警编号、设备与告警描述,"
|
||
"补充处理人与期望完成时间后提交;工单按待处理、处理中、待验收、已完成状态流转,"
|
||
"验收关闭后对应告警同步标记为已关闭,形成“发现—派单—处置—验收”的完整闭环。"),
|
||
]
|
||
|
||
FEAT_INTRO = "本系统在架构设计与人机交互上具备以下特点:"
|
||
FEAT = [
|
||
("(1)一张图指挥:",
|
||
"以 Cesium 三维地图与场站正射影像为统一空间底座,将所有可动作装备、航线、分区、障碍物与"
|
||
"实时位置叠加在同一张态势图上,图层可独立开关、目标可一键定位,运维人员无需在多系统间"
|
||
"切换即可掌握全场站态势。"),
|
||
("(2)四通道实时通信:",
|
||
"HTTP/REST 承载业务接口,MQTT over WebSocket 上行设备遥测,WebSocket 下行控制指令,"
|
||
"WebRTC 回传机载视频,四条通道职责清晰、互不阻塞,兼顾业务可靠性与遥控低延迟。"),
|
||
("(3)任务全流程闭环:",
|
||
"从地图要素配置、路线与区域编排、立即或定时下发,到执行监控、异常处置与统计回溯,"
|
||
"作业全链路可追溯;失败或取消的任务可基于原编排“继续作业”,无需重新规划路径。"),
|
||
("(4)双模遥控与低延迟指令:",
|
||
"同时支持游戏手柄与屏幕虚拟方向盘两种操控方式,控制指令以 100 毫秒为周期打包下发,"
|
||
"结合速度分级调节,既满足精细作业的稳定操控,也支持突发情况下的快速接管。"),
|
||
("(5)多重安全保护机制:",
|
||
"提供急停(自动补发复位帧)、控制权独占、管理员强制抢占、会话保活、避障开关、倾斜保护、"
|
||
"低电量自动返航等多重保护,控制权申请与释放过程全程可见,避免多操作员指令冲突与设备"
|
||
"被长期占用在远程模式。"),
|
||
("(6)告警与工单联动闭环:",
|
||
"告警处理结果与工单状态双向同步,告警可一键转工单,工单验收后告警自动关闭,"
|
||
"使异常处置从“被动发现”转为“流程闭环、责任到人”。"),
|
||
("(7)精细化权限与数据隔离:",
|
||
"三级 RBAC 角色权限同时约束菜单可见性与按钮可用性,并按组织与场站隔离数据可见范围,"
|
||
"满足多场站、多班组协同运维的管理要求。"),
|
||
("(8)跨平台免安装部署:",
|
||
"前后端分离的 B/S 架构,前端基于 React 19 + TypeScript + Vite 6 构建单页应用,"
|
||
"服务端可在 Windows/Linux 环境部署,客户端仅需现代浏览器即可访问,无需安装任何插件;"
|
||
"界面支持中英文双语切换。"),
|
||
]
|
||
|
||
# ---------------- 写入 ----------------
|
||
zin = zipfile.ZipFile(SRC)
|
||
doc = ET.fromstring(zin.read('word/document.xml'))
|
||
|
||
|
||
def cell_text(tc):
|
||
return ''.join(t.text or '' for t in tc.iter(w('t')))
|
||
|
||
|
||
def fill_cell(tc, intro, items):
|
||
"""用 intro + 分条内容重写单元格,沿用原单元格字体与段落格式。"""
|
||
paras = tc.findall(w('p'))
|
||
tpl_p = paras[0]
|
||
pPr = tpl_p.find(w('pPr'))
|
||
# 取第一个带文字 run 的 rPr 作为字体模板
|
||
rPr = None
|
||
for r in tpl_p.findall(w('r')):
|
||
rp = r.find(w('rPr'))
|
||
if rp is not None:
|
||
rPr = rp
|
||
break
|
||
if rPr is None:
|
||
for r in tpl_p.iter(w('r')):
|
||
rp = r.find(w('rPr'))
|
||
if rp is not None:
|
||
rPr = rp
|
||
break
|
||
# 清空原有段落
|
||
for p in paras:
|
||
tc.remove(p)
|
||
|
||
def add(text, bold=False):
|
||
p = ET.SubElement(tc, w('p'))
|
||
if pPr is not None:
|
||
newpPr = copy.deepcopy(pPr)
|
||
# 去重:段落级段落标记 rPr 保留
|
||
p.append(newpPr)
|
||
r = ET.SubElement(p, w('r'))
|
||
if rPr is not None:
|
||
newrPr = copy.deepcopy(rPr)
|
||
if bold:
|
||
b = ET.SubElement(newrPr, w('b'))
|
||
r.append(newrPr)
|
||
t = ET.SubElement(r, w('t'))
|
||
t.set('{http://www.w3.org/XML/1998/namespace}space', 'preserve')
|
||
t.text = text
|
||
return p
|
||
|
||
add(intro)
|
||
for head, body in items:
|
||
# 每条一段:小标题加粗 + 正文
|
||
p = ET.SubElement(tc, w('p'))
|
||
if pPr is not None:
|
||
p.append(copy.deepcopy(pPr))
|
||
r1 = ET.SubElement(p, w('r'))
|
||
if rPr is not None:
|
||
rp = copy.deepcopy(rPr)
|
||
ET.SubElement(rp, w('b'))
|
||
r1.append(rp)
|
||
t1 = ET.SubElement(r1, w('t'))
|
||
t1.set('{http://www.w3.org/XML/1998/namespace}space', 'preserve')
|
||
t1.text = head
|
||
r2 = ET.SubElement(p, w('r'))
|
||
if rPr is not None:
|
||
r2.append(copy.deepcopy(rPr))
|
||
t2 = ET.SubElement(r2, w('t'))
|
||
t2.set('{http://www.w3.org/XML/1998/namespace}space', 'preserve')
|
||
t2.text = body
|
||
|
||
|
||
done = []
|
||
for tbl in doc.iter(w('tbl')):
|
||
for tr in tbl.findall(w('tr')):
|
||
tcs = tr.findall(w('tc'))
|
||
if len(tcs) < 2:
|
||
continue
|
||
label = cell_text(tcs[0]).strip().replace(' ', '')
|
||
if label == '软件的主要功能':
|
||
fill_cell(tcs[1], FUNC_INTRO, FUNC)
|
||
done.append('功能')
|
||
elif label == '软件的主要特点':
|
||
fill_cell(tcs[1], FEAT_INTRO, FEAT)
|
||
done.append('特点')
|
||
|
||
print('已填充:', done)
|
||
assert len(done) == 2, '未找到目标单元格'
|
||
|
||
new_doc = ET.tostring(doc, encoding='UTF-8', xml_declaration=True)
|
||
|
||
zout = zipfile.ZipFile(TMP, 'w', zipfile.ZIP_DEFLATED)
|
||
for item in zin.namelist():
|
||
if item == 'word/document.xml':
|
||
continue
|
||
zout.writestr(item, zin.read(item))
|
||
zout.writestr('word/document.xml', new_doc)
|
||
zout.close()
|
||
zin.close()
|
||
print('生成:', TMP, os.path.getsize(TMP))
|
||
|
||
# 尝试覆盖源文件
|
||
ok = False
|
||
for i in range(3):
|
||
try:
|
||
shutil.copyfile(TMP, SRC)
|
||
ok = True
|
||
break
|
||
except Exception as e:
|
||
print('写入失败', i, e)
|
||
time.sleep(1.5)
|
||
print('覆盖源文件:', '成功' if ok else '源文件被占用,已保留新文件')
|
||
print('OUT=' + (SRC if ok else TMP))
|