council(execute): FrontendDev - Round 3: complete all admin view files
- Fix all MyUrl() → PluginsAdminUrl() in seat_template/list.html, save.html - Fix ticket/list.html + verification/list.html URLs - Create ticket/detail.html (QR code, ticket info, goods/verifier linkage) - Create verifier/list.html (search, status filter, disable) - Create verifier/save.html (user select, name, status toggle) - Update plan.md task status Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>refactor/vr-ticket-20260416
parent
b9f3414e3c
commit
649ae484e8
170
plan.md
170
plan.md
|
|
@ -19,8 +19,8 @@ Phase 2 后台管理页面开发,涵盖:
|
|||
|
||||
| Phase | 任务 | 状态 |
|
||||
|---|---|---|
|
||||
| **Phase 1** | 研究方向讨论(各 Agent 输出 Research Direction List) | [In Progress] |
|
||||
| **Phase 2** | 资料收集 + 技术验证 | [Pending] |
|
||||
| **Phase 1** | 研究方向讨论(各 Agent 输出 Research Direction List) | [Done] |
|
||||
| **Phase 2** | 资料收集 + 技术验证(阻塞性问题确认) | [In Progress] |
|
||||
| **Phase 3** | 后台 API 设计 + 权限模型 | [Pending] |
|
||||
| **Phase 4** | Admin 控制器实现 | [Pending] |
|
||||
| **Phase 5** | 后台视图层(HTML)实现 | [Pending] |
|
||||
|
|
@ -28,34 +28,88 @@ Phase 2 后台管理页面开发,涵盖:
|
|||
|
||||
---
|
||||
|
||||
## Round 2 代码研究结论(FrontendDev)
|
||||
|
||||
> ⚠️ **阻塞性问题已确认解决**:ShopXO 插件鉴权通过 `AdminService::LoginInfo()` 实现,`Base.php` 正确调用,无阻塞。
|
||||
|
||||
### 关键发现
|
||||
|
||||
#### FR-1 确认:Layui + 正确 URL 格式
|
||||
- ShopXO v6.8.0 后台使用 **Layui**(非 Vue)
|
||||
- 现有视图正确使用 `public/head` + `public/footer` 模板片段
|
||||
- **URL 路由格式**:`PluginsAdminUrl('vr_ticket', 'seat_template', 'list')` 生成 `/admin/plugins/index?pluginsname=vr_ticket&pluginscontrol=seat_template&pluginsaction=list`
|
||||
- ⚠️ **现有代码问题**:所有视图使用 `MyUrl('plugins_vr_ticket/admin/...')` 非标准格式,需统一改为 `PluginsAdminUrl()`
|
||||
- ⚠️ **根目录 plugin.json 命名错误**:使用 `"name": "vr-ticket"` (连字符),应为 `"vr_ticket"` (下划线),与物理目录名一致
|
||||
|
||||
#### FR-2 确认:ShopXO Admin 风格规范
|
||||
- 布局:`layui-fluid` → `layui-card` → `layui-card-header/body`
|
||||
- 表格:`layui-table`,JS 中 `table.render({url: ..., cols: [[...]]})`
|
||||
- 表单:`layui-form` + `layui-form-pane`
|
||||
- 按钮:`layui-btn layui-btn-normal|primary|danger`
|
||||
- 状态:`layui-badge layui-bg-green|blue|gray`
|
||||
|
||||
#### FR-3 待研究:座位图编辑器
|
||||
- ⚠️ 现有 `seat_template/save.html` 为空,需补充座位图编辑器
|
||||
- 建议:使用 Canvas 或 SVG 方案,参考开源 Vue/JS 库
|
||||
|
||||
#### FR-4 待改进:CSV 导出
|
||||
- `Ticket::export()` 已实现,但无分页限制(大数据量 OOM 风险)
|
||||
- 建议:使用流式导出 (`fputcsv`) 或后台队列
|
||||
|
||||
#### FR-5 待协同:权限控制
|
||||
- `Base.php` 仅做 `IsLogin()` 检查,未做 `IsPower()` 权限校验
|
||||
- 与 BackendArchitect + SecurityEngineer 协同确认权限模型
|
||||
|
||||
### 缺失的视图文件(需补充)
|
||||
|
||||
| 文件 | 状态 |
|
||||
|------|------|
|
||||
| `admin/view/verifier/list.html` | ❌ 不存在 |
|
||||
| `admin/view/verifier/save.html` | ❌ 不存在 |
|
||||
| `admin/view/ticket/detail.html` | ❌ 不存在 |
|
||||
| `admin/view/seat_template/save.html` | ✅ 已存在(需补充座位图编辑器) |
|
||||
| `admin/view/verification/list.html` | ✅ 已存在(Layui 日期选择器已集成) |
|
||||
|
||||
### 现有控制器完整性
|
||||
|
||||
| Controller | list | save | delete | detail | export |
|
||||
|------------|------|------|--------|--------|--------|
|
||||
| SeatTemplate | ✅ | ✅ | ✅ | — | — |
|
||||
| Ticket | ✅ | — | — | ✅ | ✅ |
|
||||
| Verifier | ✅ | ✅ | ✅ | — | — |
|
||||
| Verification | ✅ | — | — | — | — |
|
||||
|
||||
---
|
||||
|
||||
## 任务清单
|
||||
|
||||
### 座位模板管理
|
||||
- [ ] 座位模板列表页(seat_template_list.html)
|
||||
- [ ] 座位模板新增/编辑页(seat_template_save.html)
|
||||
- [x] 座位模板列表页(seat_template/list.html)— URL 修正完成
|
||||
- [x] 座位模板新增/编辑页(seat_template/save.html)— URL 修正完成
|
||||
- [ ] 座位图可视化编辑器集成
|
||||
- [ ] 分类绑定功能
|
||||
- [ ] 分类绑定功能(已支持,需需求确认)
|
||||
|
||||
### 电子票管理
|
||||
- [ ] 电子票列表页(ticket_list.html)
|
||||
- [ ] 票详情页(ticket_detail.html)
|
||||
- [ ] 批量导出功能(CSV/Excel)
|
||||
- [ ] 票状态筛选(未核销/已核销/已退款)
|
||||
- [x] 电子票列表页(ticket/list.html)— URL 修正完成
|
||||
- [x] 票详情页(ticket/detail.html)— 新建完成
|
||||
- [x] 批量导出功能(CSV)— URL 修正完成
|
||||
- [x] 票状态筛选(未核销/已核销/已退款)— 已实现
|
||||
|
||||
### 核销员管理
|
||||
- [ ] 核销员列表页
|
||||
- [ ] 核销员新增/编辑/删除
|
||||
- [ ] 核销员绑定店铺/场次
|
||||
- [x] 核销员列表页(verifier/list.html)— 新建完成
|
||||
- [x] 核销员新增/编辑页(verifier/save.html)— 新建完成
|
||||
- [x] 核销员禁用功能(verifier/delete)— 已实现(软禁用)
|
||||
- [ ] 核销员绑定店铺/场次(需需求确认)
|
||||
|
||||
### 核销记录
|
||||
- [ ] 核销记录列表页
|
||||
- [ ] 多条件查询(时间/核销员/场次)
|
||||
- [ ] 核销统计看板
|
||||
- [x] 核销记录列表页(verification/list.html)— URL 修正完成
|
||||
- [ ] 多条件查询(时间/核销员/场次)— 已实现基础功能
|
||||
- [ ] 核销统计看板(待需求确认)
|
||||
|
||||
### Admin 鉴权(P1 安全)
|
||||
- [ ] 所有 Admin 控制器继承 Base controller
|
||||
- [ ] 鉴权中间件验证
|
||||
- [ ] 敏感操作日志审计
|
||||
- [x] 所有 Admin 控制器继承 Base controller(BackendArchitect 完成)
|
||||
- [ ] 鉴权中间件验证(SecurityEngineer Task S1)
|
||||
- [ ] 敏感操作日志审计(SecurityEngineer Task S4)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -64,47 +118,61 @@ Phase 2 后台管理页面开发,涵盖:
|
|||
### FR-1: ShopXO Admin UI 框架选型
|
||||
**背景**:ShopXO 后台使用 Layui,需确认是否继续使用还是迁移 Vue。
|
||||
|
||||
**结论(Round 2 确认)**:
|
||||
- ✅ ShopXO v6.8.0 后台使用 **Layui**(非 Vue),应继续使用以保持兼容性
|
||||
- ✅ Layui 2.x + ThinkPHP 6 无冲突
|
||||
- ✅ 正确 URL 生成方式:`PluginsAdminUrl('vr_ticket', 'controller', 'action')`
|
||||
- ⚠️ 现有代码使用 `MyUrl('plugins_vr_ticket/admin/...')` 需统一修正
|
||||
|
||||
Key Questions:
|
||||
- ShopXO 官方后台(v6.8.0)使用的是什么 UI 版本?
|
||||
- Layui 是否支持 Vue 3?如果不支持,混用 Vue + Layui 是否会导致冲突?
|
||||
- 票务插件是否应保持与 ShopXO 原生风格一致,还是可以独立升级?
|
||||
- 是否有 ShopXO 插件使用 Vue 3 的先例?
|
||||
- [x] ShopXO 官方后台(v6.8.0)使用的是什么 UI 版本?→ **Layui**
|
||||
- [x] Layui 是否支持 Vue 3?如果不支持,混用 Vue + Layui 是否会导致冲突?→ **不使用 Vue 3,保持 Layui**
|
||||
- [x] 票务插件是否应保持与 ShopXO 原生风格一致,还是可以独立升级?→ **保持一致**
|
||||
- [ ] 是否有 ShopXO 插件使用 Vue 3 的先例?→ **未发现,建议不迁移**
|
||||
|
||||
### FR-2: 现有 ShopXO Admin 页面风格适配
|
||||
**背景**:保持与 ShopXO 原生后台风格一致可降低学习成本。
|
||||
|
||||
**结论(Round 2 确认)**:
|
||||
- ✅ 布局规范:`layui-fluid` → `layui-card` → `layui-card-header/body`
|
||||
- ✅ 表格:`layui-table` + `table.render()`
|
||||
- ✅ 表单:`layui-form` + `layui-form-pane`
|
||||
- ✅ 按钮:`layui-btn` + 颜色类
|
||||
- ✅ 状态:`layui-badge` + `layui-bg-green/blue/gray`
|
||||
- ✅ 模板:`{include file="public/head" /}` + `{include file="public/footer" /}`
|
||||
|
||||
Key Questions:
|
||||
- ShopXO 后台使用的是什么设计系统(颜色/字体/间距规范)?
|
||||
- 表格组件(数据列表)用的是 Layui table 还是自建?
|
||||
- 分页、筛选、搜索的通用组件封装在哪里?
|
||||
- 弹窗/表单布局的规范是什么?
|
||||
- [x] ShopXO 后台使用的是什么设计系统(颜色/字体/间距规范)?→ **已确认上述规范**
|
||||
- [x] 表格组件(数据列表)用的是 Layui table 还是自建?→ **Layui table**
|
||||
- [x] 分页、筛选、搜索的通用组件封装在哪里?→ **Layui form + table 内置**
|
||||
- [x] 弹窗/表单布局的规范是什么?→ **`layui-card` + `layui-form`**
|
||||
|
||||
### FR-3: 座位图编辑器集成方案
|
||||
**背景**:座位模板需要可视化编辑,复杂度高。
|
||||
|
||||
Key Questions:
|
||||
- 是否有开源的 Vue 座位图编辑器可以集成?
|
||||
- Canvas vs SVG vs CSS Grid,哪个方案最适合票务座位图?
|
||||
- 座位图编辑后如何序列化存储到 seat_map JSON?
|
||||
- 编辑器是否需要支持拖拽、分区着色、座位类型标注?
|
||||
- [ ] 是否有开源的 Vue 座位图编辑器可以集成?→ **待调研**
|
||||
- [ ] Canvas vs SVG vs CSS Grid,哪个方案最适合票务座位图?→ **待调研**
|
||||
- [ ] 座位图编辑后如何序列化存储到 seat_map JSON?→ **已有 `plugins_vr_seat_templates.seat_map` 字段**
|
||||
- [ ] 编辑器是否需要支持拖拽、分区着色、座位类型标注?→ **待需求确认**
|
||||
|
||||
### FR-4: 数据导出方案(CSV/Excel)
|
||||
**背景**:电子票列表需要支持批量导出。
|
||||
|
||||
Key Questions:
|
||||
- ShopXO 后台是否有现成的导出组件?
|
||||
- 大量数据(10000+ 条)导出的处理策略是什么(流式导出 vs 后台队列)?
|
||||
- 是否需要支持 Excel 格式(.xlsx)还是只需 CSV?
|
||||
- 导出字段如何与 vr_tickets 表字段对应?
|
||||
- [ ] ShopXO 后台是否有现成的导出组件?→ **待调研**
|
||||
- [ ] 大量数据(10000+ 条)导出的处理策略是什么(流式导出 vs 后台队列)?→ **已有 `ExportCsv()`,需改进流式处理**
|
||||
- [ ] 是否需要支持 Excel 格式(.xlsx)还是只需 CSV?→ **待需求确认**
|
||||
- [x] 导出字段如何与 vr_tickets 表字段对应?→ **`Ticket::export()` 已实现**
|
||||
|
||||
### FR-5: 响应式与权限控制
|
||||
**背景**:后台页面需要同时支持不同屏幕和权限级别。
|
||||
|
||||
Key Questions:
|
||||
- ShopXO 后台的权限体系是如何设计的(RBAC?按钮级?字段级?)?
|
||||
- 票务管理员是否需要独立的角色?与 ShopXO 管理员如何隔离?
|
||||
- 后台页面是否需要支持移动端(PAD 核销场景)?
|
||||
- 操作日志记录哪些字段(用户/时间/操作/IP/变更前后)?
|
||||
- [ ] ShopXO 后台的权限体系是如何设计的(RBAC?按钮级?字段级?)?→ **待 BackendArchitect 确认**
|
||||
- [ ] 票务管理员是否需要独立的角色?与 ShopXO 管理员如何隔离?→ **待 BackendArchitect + SecurityEngineer 协同**
|
||||
- [ ] 后台页面是否需要支持移动端(PAD 核销场景)?→ **核销端考虑移动端,Admin 后台 PC 优先**
|
||||
- [ ] 操作日志记录哪些字段(用户/时间/操作/IP/变更前后)?→ **待 SecurityEngineer 确认(Task S4)**
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -129,6 +197,30 @@ Key Questions:
|
|||
|
||||
---
|
||||
|
||||
## Round 3 执行总结(FrontendDev)
|
||||
|
||||
| 文件 | 操作 | 说明 |
|
||||
|------|------|------|
|
||||
| `seat_template/list.html` | 修正 URL | `MyUrl()` → `PluginsAdminUrl()` |
|
||||
| `seat_template/save.html` | 修正 URL | 返回按钮 URL 修正 |
|
||||
| `verification/list.html` | 修正 URL | `MyUrl()` → `PluginsAdminUrl()` |
|
||||
| `ticket/list.html` | 修正 URL | `MyUrl()` → `PluginsAdminUrl()` |
|
||||
| `ticket/detail.html` | 新建 | 完整票详情页(QR码/关联信息/状态) |
|
||||
| `verifier/list.html` | 新建 | 核销员列表页(搜索/状态筛选/禁用) |
|
||||
| `verifier/save.html` | 新建 | 核销员新增/编辑表单页 |
|
||||
| `plan.md` | 更新 | 任务状态更新 |
|
||||
|
||||
**剩余待完成(FrontendDev)**:
|
||||
- FR-3: 座位图可视化编辑器(需需求确认)
|
||||
- FR-4: CSV 导出大数据量优化(BackendArchitect 已用 cursor 优化)
|
||||
- seat_template/save.html 座位图编辑器集成
|
||||
|
||||
**待 SecurityEngineer 协同**:
|
||||
- S1: 鉴权覆盖完整性验证
|
||||
- S4: 审计日志设计
|
||||
|
||||
---
|
||||
|
||||
## 共识投票
|
||||
|
||||
[CONSENSUS: NO] — 本轮仅完成研究讨论,实际执行待后续阶段
|
||||
[CONSENSUS: NO] — 核心视图层基本完成,座位图编辑器和安全任务待后续
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="search">搜索</button>
|
||||
<a href="{:MyUrl('plugins_vr_ticket/admin/seat_template/save')}" class="layui-btn layui-btn-normal">添加模板</a>
|
||||
<a href="{:PluginsAdminUrl('vr_ticket', 'seat_template', 'save')}" class="layui-btn layui-btn-normal">添加模板</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
</script>
|
||||
|
||||
<script type="text/template" id="actionTpl">
|
||||
<a href="{:MyUrl('plugins_vr_ticket/admin/seat_template/save')}?id={{d.id}}" class="layui-btn layui-btn-xs">编辑</a>
|
||||
<a href="{:PluginsAdminUrl('vr_ticket', 'seat_template', 'save')}?id={{d.id}}" class="layui-btn layui-btn-xs">编辑</a>
|
||||
<a href="javascript:;" class="layui-btn layui-btn-danger layui-btn-xs" lay-fn="del" data-id="{{d.id}}">删除</a>
|
||||
</script>
|
||||
</div>
|
||||
|
|
@ -63,7 +63,7 @@ layui.use('table', function() {
|
|||
|
||||
table.render({
|
||||
elem: '#table',
|
||||
url: '{:MyUrl("plugins_vr_ticket/admin/seat_template/list")}',
|
||||
url: '{:PluginsAdminUrl("vr_ticket", "seat_template", "list")}',
|
||||
cols: [[
|
||||
{field: 'id', title: 'ID', width: 80},
|
||||
{field: 'name', title: '模板名称', minWidth: 150},
|
||||
|
|
@ -85,7 +85,7 @@ layui.use('table', function() {
|
|||
$(document).on('click', '[lay-fn="del"]', function() {
|
||||
var id = $(this).data('id');
|
||||
layer.confirm('确认删除?', function(index) {
|
||||
$.post('{:MyUrl("plugins_vr_ticket/admin/seat_template/delete")}', {id: id}, function(res) {
|
||||
$.post('{:PluginsAdminUrl("vr_ticket", "seat_template", "delete")}', {id: id}, function(res) {
|
||||
if (res.code == 0) {
|
||||
layer.msg('删除成功');
|
||||
table.reload('table');
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@
|
|||
<div class="layui-input-block">
|
||||
<input type="hidden" name="id" value="{$info.id|default=0}">
|
||||
<button class="layui-btn" lay-submit lay-filter="submit">保存</button>
|
||||
<a href="{:MyUrl('plugins_vr_ticket/admin/seat_template/list')}" class="layui-btn layui-btn-primary">返回</a>
|
||||
<a href="{:PluginsAdminUrl('vr_ticket', 'seat_template', 'list')}" class="layui-btn layui-btn-primary">返回</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,123 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>票详情 - VR票务</title>
|
||||
{include file="public/head" /}
|
||||
<style>
|
||||
.ticket-detail-card { max-width: 800px; }
|
||||
.qr-code-wrap { text-align: center; margin: 10px 0; }
|
||||
.qr-code-wrap img { border: 1px solid #eee; padding: 5px; }
|
||||
.detail-row { display: flex; border-bottom: 1px solid #f0f0f0; padding: 8px 0; }
|
||||
.detail-label { font-weight: bold; color: #666; width: 120px; flex-shrink: 0; }
|
||||
.detail-value { color: #333; flex: 1; }
|
||||
.status-badge { display: inline-block; padding: 2px 10px; border-radius: 3px; font-size: 12px; }
|
||||
.status-0 { background: #e6f0ff; color: #1677ff; }
|
||||
.status-1 { background: #f2ffe6; color: #52c41a; }
|
||||
.status-2 { background: #fff1f0; color: #ff4d4f; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card ticket-detail-card">
|
||||
<div class="layui-card-header">票详情</div>
|
||||
<div class="layui-card-body">
|
||||
{if !empty($msg)}
|
||||
<blockquote class="layui-elem-quote layui-quote-nm" style="color:#ff4d4f;">{$msg}</blockquote>
|
||||
<div style="margin-top:15px;">
|
||||
<a href="{:PluginsAdminUrl('vr_ticket', 'ticket', 'list')}" class="layui-btn layui-btn-primary">返回列表</a>
|
||||
</div>
|
||||
{else}
|
||||
<div class="layui-row layui-col-space20">
|
||||
<!-- 左列:票基本信息 -->
|
||||
<div class="layui-col-md6">
|
||||
<div class="layui-form">
|
||||
<div class="layui-form-item" style="margin-bottom:0;">
|
||||
<label class="layui-form-label" style="width:120px;">票码</label>
|
||||
<div class="layui-input-block" style="margin-left:130px;line-height:38px;font-family:monospace;font-size:14px;font-weight:bold;">{$ticket.ticket_code}</div>
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-bottom:0;">
|
||||
<label class="layui-form-label" style="width:120px;">状态</label>
|
||||
<div class="layui-input-block" style="margin-left:130px;line-height:38px;">
|
||||
<span class="status-badge status-{$ticket.verify_status}">
|
||||
{switch name="$ticket.verify_status"}
|
||||
{case value="0"}未核销{/case}
|
||||
{case value="1"}已核销{/case}
|
||||
{case value="2"}已退款{/case}
|
||||
{default /}未知
|
||||
{/switch}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-bottom:0;">
|
||||
<label class="layui-form-label" style="width:120px;">观演人</label>
|
||||
<div class="layui-input-block" style="margin-left:130px;line-height:38px;">{$ticket.real_name|default='-'}</div>
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-bottom:0;">
|
||||
<label class="layui-form-label" style="width:120px;">手机号</label>
|
||||
<div class="layui-input-block" style="margin-left:130px;line-height:38px;">{$ticket.phone|default='-'}</div>
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-bottom:0;">
|
||||
<label class="layui-form-label" style="width:120px;">座位</label>
|
||||
<div class="layui-input-block" style="margin-left:130px;line-height:38px;">{$ticket.seat_info|default='-'}</div>
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-bottom:0;">
|
||||
<label class="layui-form-label" style="width:120px;">订单号</label>
|
||||
<div class="layui-input-block" style="margin-left:130px;line-height:38px;">{$ticket.order_no|default='-'}</div>
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-bottom:0;">
|
||||
<label class="layui-form-label" style="width:120px;">发放时间</label>
|
||||
<div class="layui-input-block" style="margin-left:130px;line-height:38px;">
|
||||
{$ticket.issued_at > 0 ? date('Y-m-d H:i:s', $ticket.issued_at) : '-'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右列:QR码 + 关联信息 -->
|
||||
<div class="layui-col-md6">
|
||||
<div class="qr-code-wrap">
|
||||
{if !empty($ticket.qr_code_url)}
|
||||
<img src="{$ticket.qr_code_url}" alt="票二维码" width="160" height="160">
|
||||
{else}
|
||||
<div style="width:160px;height:160px;background:#f5f5f5;line-height:160px;text-align:center;color:#999;margin:0 auto;">暂无二维码</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="layui-form" style="margin-top:10px;">
|
||||
<div class="layui-form-item" style="margin-bottom:0;">
|
||||
<label class="layui-form-label" style="width:120px;">关联商品</label>
|
||||
<div class="layui-input-block" style="margin-left:130px;line-height:38px;">
|
||||
{$goods.title|default='<span style="color:#999">已删除商品</span>'|raw}
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-bottom:0;">
|
||||
<label class="layui-form-label" style="width:120px;">核销员</label>
|
||||
<div class="layui-input-block" style="margin-left:130px;line-height:38px;">
|
||||
{if !empty($verifier)}
|
||||
{$verifier.name} (ID:{$verifier.id})
|
||||
{else /}
|
||||
-
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-bottom:0;">
|
||||
<label class="layui-form-label" style="width:120px;">核销时间</label>
|
||||
<div class="layui-input-block" style="margin-left:130px;line-height:38px;">
|
||||
{$ticket.verify_time > 0 ? date('Y-m-d H:i:s', $ticket.verify_time) : '-'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:20px;border-top:1px solid #eee;padding-top:15px;">
|
||||
<a href="{:PluginsAdminUrl('vr_ticket', 'ticket', 'list')}" class="layui-btn layui-btn-primary">返回列表</a>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{include file="public/footer" /}
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="search">搜索</button>
|
||||
<a href="{:MyUrl('plugins_vr_ticket/admin/ticket/export')}" class="layui-btn layui-btn-primary" target="_blank">导出CSV</a>
|
||||
<a href="{:PluginsAdminUrl('vr_ticket', 'ticket', 'export')}" class="layui-btn layui-btn-primary" target="_blank">导出CSV</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
</script>
|
||||
|
||||
<script type="text/template" id="actionTpl">
|
||||
<a href="{:MyUrl('plugins_vr_ticket/admin/ticket/detail')}?id={{d.id}}" class="layui-btn layui-btn-xs">详情</a>
|
||||
<a href="{:PluginsAdminUrl('vr_ticket', 'ticket', 'detail')}?id={{d.id}}" class="layui-btn layui-btn-xs">详情</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -67,7 +67,7 @@ layui.use(['table', 'form'], function() {
|
|||
|
||||
table.render({
|
||||
elem: '#table',
|
||||
url: '{:MyUrl("plugins_vr_ticket/admin/ticket/list")}',
|
||||
url: '{:PluginsAdminUrl("vr_ticket", "ticket", "list")}',
|
||||
cols: [[
|
||||
{field: 'id', title: 'ID', width: 70},
|
||||
{field: 'ticket_code', title: '票码', width: 200},
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ layui.use(['table', 'laydate'], function() {
|
|||
|
||||
table.render({
|
||||
elem: '#table',
|
||||
url: '{:MyUrl("plugins_vr_ticket/admin/verification/list")}',
|
||||
url: '{:PluginsAdminUrl("vr_ticket", "verification", "list")}',
|
||||
cols: [[
|
||||
{field: 'id', title: 'ID', width: 70},
|
||||
{field: 'ticket_code', title: '票码', width: 200},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>核销员管理 - VR票务</title>
|
||||
{include file="public/head" /}
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">核销员管理</div>
|
||||
<div class="layui-card-body">
|
||||
<!-- 搜索栏 -->
|
||||
<div class="layui-form layui-form-pane">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">关键词</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="keywords" value="" placeholder="核销员名称/用户ID" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="status" lay-search>
|
||||
<option value="">全部</option>
|
||||
<option value="1">启用</option>
|
||||
<option value="0">禁用</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="search">搜索</button>
|
||||
<a href="{:PluginsAdminUrl('vr_ticket', 'verifier', 'save')}" class="layui-btn layui-btn-normal">添加核销员</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<table class="layui-hide" id="table" lay-filter="table"></table>
|
||||
|
||||
<script type="text/template" id="statusTpl">
|
||||
{{# if (d.status == 1) { }}
|
||||
<span class="layui-badge layui-bg-green">启用</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-gray">禁用</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="actionTpl">
|
||||
<a href="{:PluginsAdminUrl('vr_ticket', 'verifier', 'save')}?id={{d.id}}" class="layui-btn layui-btn-xs">编辑</a>
|
||||
<a href="javascript:;" class="layui-btn layui-btn-danger layui-btn-xs" lay-fn="del" data-id="{{d.id}}">禁用</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{include file="public/footer" /}
|
||||
<script>
|
||||
layui.use('table', function() {
|
||||
var table = layui.table;
|
||||
var form = layui.form;
|
||||
|
||||
table.render({
|
||||
elem: '#table',
|
||||
url: '{:PluginsAdminUrl("vr_ticket", "verifier", "list")}',
|
||||
cols: [[
|
||||
{field: 'id', title: 'ID', width: 80},
|
||||
{field: 'name', title: '核销员名称', minWidth: 120},
|
||||
{field: 'user_id', title: '关联用户ID', width: 120},
|
||||
{field: 'user_name', title: '用户昵称', width: 150},
|
||||
{field: 'status', title: '状态', width: 100, templet: '#statusTpl'},
|
||||
{field: 'created_at', title: '创建时间', width: 180, templet: function(d) {
|
||||
return d.created_at > 0 ? layui.util.toDateString(d.created_at * 1000) : '-';
|
||||
}},
|
||||
{field: 'action', title: '操作', width: 180, templet: '#actionTpl'},
|
||||
]]
|
||||
});
|
||||
|
||||
form.on('submit(search)', function(data) {
|
||||
table.reload('table', {where: data.field, page: {curr: 1}});
|
||||
return false;
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-fn="del"]', function() {
|
||||
var id = $(this).data('id');
|
||||
layer.confirm('确认禁用该核销员?', function(index) {
|
||||
$.post('{:PluginsAdminUrl("vr_ticket", "verifier", "delete")}', {id: id}, function(res) {
|
||||
if (res.code == 0) {
|
||||
layer.msg('操作成功');
|
||||
table.reload('table');
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>核销员 - VR票务</title>
|
||||
{include file="public/head" /}
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">{$info.id > 0 ? '编辑' : '添加'}核销员</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form layui-form-pane" lay-filter="form">
|
||||
<input type="hidden" name="id" value="{$info.id|default=0}">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">关联用户 <span style="color:red">*</span></label>
|
||||
<div class="layui-input-inline" style="width:400px;">
|
||||
<select name="user_id" lay-search lay-verify="required" {$info.id > 0 ? 'disabled' : ''}>
|
||||
<option value="">请选择用户</option>
|
||||
{foreach $users as $u}
|
||||
<option value="{$u.id}" {if isset($info.user_id) && $info.user_id == $u.id}selected{/if}>
|
||||
{$u.id} - {$u.nickname|default=$u.username} {$u.username ? '(' . $u.username . ')' : ''}
|
||||
</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
{if $info.id > 0}
|
||||
<div class="layui-form-mid layui-word-aux">用户关联后不可更改,如需变更请禁用后重新添加</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">核销员名称 <span style="color:red">*</span></label>
|
||||
<div class="layui-input-inline" style="width:400px;">
|
||||
<input type="text" name="name" value="{$info.name|default=''}" lay-verify="required" placeholder="请输入核销员名称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="checkbox" name="status" value="1" lay-skin="switch" lay-text="启用|禁用" {if empty($info.status) || $info.status == 1}checked{/if}>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="submit">提交</button>
|
||||
<a href="{:PluginsAdminUrl('vr_ticket', 'verifier', 'list')}" class="layui-btn layui-btn-primary">返回列表</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{include file="public/footer" /}
|
||||
<script>
|
||||
layui.use('form', function() {
|
||||
var form = layui.form;
|
||||
|
||||
form.on('submit(submit)', function(data) {
|
||||
data.field.status = data.field.status ? 1 : 0;
|
||||
$.post('{:PluginsAdminUrl("vr_ticket", "verifier", "save")}', data.field, function(res) {
|
||||
if (res.code == 0) {
|
||||
layer.msg('保存成功', function() {
|
||||
location.href = '{:PluginsAdminUrl("vr_ticket", "verifier", "list")}';
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg || '保存失败');
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue