自营售票管理端接口.md(仓库根,593 行,下文简称「管理端文档」)src/router/index.js 的 routerMap 声明,登录后 src/permission.js 守卫触发 GetInfo → GenerateRoutes(src/store/modules/permission.js)按后台 resourceList 的 code 过滤,addRoutes 注入。static/font/iconfont.css,index.html 引入),meta.icon → 类名 icon-{name};可用字形含 icon-ticket-manage(门票图标),直接复用,零图标改动。.form-wrap > .searchBox(el-form inline + .btn-wrap) + .tableBox(el-table stripe + 操作列 fixed right) + el-pagination;弹窗拆独立组件(参考 src/views/goodsCenter/priceList/EditDialog.vue、KSNewDialog.vue)。src/utils/request.js axios 实例,请求头 SaToken: localStorage.otaToken,code!==200 弹 Message,401/403 登出。管理端文档确认新接口走同一体系(/tenant 前缀 + 现有 satoken),直接复用,无需新实例。el-upload picture-card + window.config.uploadUrl || 'https://pres.cleartv.cn/upload'(见 src/views/goodsCenter/priceList/KSNewDialog.vue:699-702)。/tenant/otaTicketType 已有封装:src/api/ticketType.js 的 getTicketTypeList。src/store/modules/permission.js:19-25 子路由过滤逻辑:
route.children = route.children.filter(i => {
if (i.meta && i.meta.permissionName) {
return permissionCodes.find((code) => i.meta.permissionName.indexOf(`:${code}`) > -1)
} else {
return true
}
})
meta.permissionName 一旦有值,后台 code 必须以 :code 形式出现在其中才显示;写 'all' 也永远匹配不上 → 子菜单被隐藏。src/router/index.js:281-296 聚合后):meta.permissionName 数组含 'all' 则恒显示。结论:4 个新子路由均不写 permissionName → 聚合后父级 自营管理 的 permissionName 数组全为 'all' → 菜单全员可见。后续若要按角色控制,再补 permissionName + 后端配置 resourceList code。
做:
src/api/selfManage.js 新 API 封装。src/const.js 追加本模块常量。不做:
src/views/goodsCenter/priceList/EditDialog.vue、src/views/queryReport/orderList.vue)。routerMap 中「产品中心」块之后、「数据中心」块之前插入:
{
path: '/selfManage',
component: Layout,
name: '自营管理',
meta: { title: '自营管理', icon: 'ticket-manage' },
redirect: 'noredirect',
alwaysShow: true,
children: [
{ path: 'ticketType', name: 'selfTicketType', component: () => import('@/views/selfManage/ticketType'), meta: { title: '票种管理' } },
{ path: 'scenic', name: 'selfScenic', component: () => import('@/views/selfManage/scenic'), meta: { title: '景点管理' } },
{ path: 'thirdParty', name: 'selfThirdParty', component: () => import('@/views/selfManage/thirdParty'), meta: { title: '自营分销商管理' } },
{ path: 'saleCalendar', name: 'selfSaleCalendar', component: () => import('@/views/selfManage/saleCalendar'), meta: { title: '销售日历' } }
]
}
注意:name 用英文(现有中文 name 与英文混用,新模块统一英文,避免路由跳转歧义);子路由不写 permissionName(见第 1 节)。
统一 http.post(url, { data: params }) 风格。函数清单(URL 均出自管理端文档):
| 函数 | 方法+URL | 说明 |
|---|---|---|
| getSelfScenicList | POST /tenant/selfScenic | 筛选 name(模糊)/isOpen;分页 records/total |
| addSelfScenic | POST /tenant/selfScenic/add | |
| updateSelfScenic | POST /tenant/selfScenic/update | 多带 id |
| deleteSelfScenic | POST /tenant/selfScenic/delete | data.idList |
| getSelfTicketTypeList | POST /tenant/selfTicketType | 筛选 category/name/isSale;分页 |
| getSelfTicketTypeDetail | POST /tenant/selfTicketType/{id} | 路径拼 id,body data 空对象 |
| addSelfTicketType | POST /tenant/selfTicketType/add | |
| updateSelfTicketType | POST /tenant/selfTicketType/update | 必填 id;ticketTypeId/category 不可改 |
| deleteSelfTicketType | POST /tenant/selfTicketType/delete | data.idList |
| getSaleCalendarList | POST /tenant/selfTicketSaleCalendar/list | 入参 selfTicketTypeId;返回数组(非分页) |
| saveSaleCalendar | POST /tenant/selfTicketSaleCalendar/add | data 是数组,全量覆盖;空数组禁止调用 |
| deleteSaleCalendar | POST /tenant/selfTicketSaleCalendar/delete | data.idList = 规则 id |
| getUserThirdPartyList | POST /tenant/userThirdParty | 筛选 name(模糊)/contactName/phone/remark/status;分页 |
| addUserThirdParty | POST /tenant/userThirdParty/add | |
| updateUserThirdParty | POST /tenant/userThirdParty/update | id + 可选字段;name/loginName 不可改 |
| bindUserThirdParty | POST /tenant/userThirdParty/bind | userThirdPartyIdList + selfTicketTypeIdList([] = 清空) |
| rechargeUserThirdParty | POST /tenant/userThirdParty/recharge | userThirdPartyId + amount>0 |
| decreaseUserThirdParty | POST /tenant/userThirdParty/decrease | 同充值 |
| deleteUserThirdParty | POST /tenant/userThirdParty/delete | data.idList;余额>0/有未完结订单会失败 |
| getThirdPartyBalanceLog | POST /tenant/thirdPartyBalanceLog | 筛选 userThirdPartyId/type/tradeTimeStart/tradeTimeEnd;分页 |
线下票种下拉复用 src/api/ticketType.js 的 getTicketTypeList(POST /tenant/otaTicketType,传 {} 拉全量或按 name 筛),不重复封装。
SELF_TICKET_CATEGORY: ticket 景区门票 / batch 场次售票 / member 年卡次卡
SELF_REAL_NAME_TYPE: 0 不限 / 1 一证一人 / 2 一证多人
SELF_CHANNELS: wx 微信公众号 / wx-mini 微信小程序 / third-party 自营分销商
SELF_WEEKDAYS: 1 周日 … 7 周六(文档约定 1=周日)
SELF_BALANCE_LOG_TYPE: 1 充值 / 2 人工扣款 / 3 消费 / 4 退款
SELF_USE_DATE_TYPE: 1 日历票 / 2 期票
SELF_MEMBER_USE_DATE_TYPE: 1 按天 / 2 固定日期
SELF_MEMBER_ACTIVE_TYPE: 1 购买即激活 / 2 首次使用激活
src/views/selfManage/ticketType/index.vue + FormDialog.vue列表(POST /tenant/selfTicketType):
$router.push({path:'/selfManage/saleCalendar', query:{id}}))、删除表单弹窗 FormDialog(新增/编辑共用,show(row?) 模式):
ticket:useDays(数字)、useDateType(1 日历票 / 2 期票);期票时 show useDateStart/useDateEndmember:memberUseDateType(1 按天 / 2 固定日期);按天 show useDays;固定日期 show useDateStart/useDateEnd;memberActiveType(1/2)batch:展示所选线下票种的 batchConfigList(只读表格:场次名称/时段/最大数量),说明「场次来自线下票种,不在此维护」src/views/selfManage/scenic/index.vue + FormDialog.vue列表(POST /tenant/selfScenic):
表单弹窗:
:limit="6",action = window.config.uploadUrl || 'https://pres.cleartv.cn/upload',上传成功取返回 URL(与 KSNewDialog 同款 on-change/on-remove 处理,失败提示重试),保存为英文逗号串;编辑时按逗号拆成 fileList 回填src/views/selfManage/thirdParty/index.vue + 4 个子弹窗列表(POST /tenant/userThirdParty):
balance > 0(提示先扣款);未完结订单前端不可见,靠后端报错弹 Message子弹窗:
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/)、contactName、phone、remark;文案提示「新建余额为 0,创建后需单独授权票种」src/views/selfManage/saleCalendar/index.vue(独立菜单)this.$route.query.id 预选并自动加载)+ 提示文案「规则覆盖该票种某天价格/是否可售;C 端列表显示底价,详情/下单走日历」specificDate 逗号串1 周日…7 周六,至少勾 1 个),提交拼逗号串data 以数组提交 saveSaleCalendar(每条含 selfTicketTypeId/price/isSale/priority + specificDate 或 startDate/endDate/weekdays;已有规则保留原 id)src/utils/request.js 统一 Message 提示与 401/403 登出,页面内不重复弹错this.$confirm{ pageNum: 1, pageSize: 10 },res.data.records / res.data.total,el-pagination :current-page.sync + @current-change 重载(与现有页一致)parseTime(src/utils/index.js)新增:
修改:
不改:permission.js、request.js、login、layout、既有业务页。
npm run dev 启动后侧边栏出现「自营管理」(产品中心之后),展开有 4 个二级菜单;任意已登录账号可见/tenant/selfScenic 等,页面表现为 Message 报错(开发期需先与后端确认环境已联调,见管理端文档联调顺序)el-upload 返回结构沿用 KSNewDialog 的处理方式实现,联调时以实际 upload 响应字段为准