feat: 建立全局店铺跨渠道管理 (#208 #209 #210 #211)

This commit is contained in:
chengma
2026-08-13 11:15:54 +08:00
parent 901b37a8cb
commit 8f707722ba
28 changed files with 1160 additions and 500 deletions
+1
View File
@@ -16,6 +16,7 @@
<a href="/tasks" data-module-root="/tasks" class="{{if eq .Active "tasks"}}active{{end}}">采集采购</a>
<a href="/clients" data-module-root="/clients" class="{{if eq .Active "clients"}}active{{end}}">客户端列表</a>
{{if and .CurrentUser .CurrentUser.IsAdmin}}
<a href="/shops" data-module-root="/shops" class="{{if eq .Active "shops"}}active{{end}}">店铺管理</a>
<a href="/users" data-module-root="/users" class="{{if eq .Active "users"}}active{{end}}">用户管理</a>
{{end}}
{{if .CurrentUser}}
+64
View File
@@ -0,0 +1,64 @@
{{define "shop/list"}}
{{template "header" .}}
<div class="toolbar">
<form class="inline grow" method="post" action="/shops/create">
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
<label for="display-name">业务店铺</label>
<input id="display-name" type="text" name="display_name" maxlength="500" required placeholder="页面统一显示名称">
<label for="syb-alias">SYB 名称</label>
<input id="syb-alias" type="text" name="syb_alias" maxlength="500" placeholder="与 SYB shopName 完全一致">
<label for="shopee-alias">蝦皮名称</label>
<input id="shopee-alias" type="text" name="shopee_alias" maxlength="500" placeholder="与导入店铺名完全一致">
<button type="submit" class="primary">新增并启用</button>
</form>
</div>
{{if .Message}}<p class="hint" role="status">{{.Message}}</p>{{end}}
{{if .Error}}<p class="missing" role="alert">{{.Error}}</p>{{end}}
<p class="hint">业务店铺是统一名称;SYB 和蝦皮名称是各渠道原始名称。系统只做忽略首尾空白后的精确匹配,不会模糊猜测。当前有 {{.UnlinkedShopeeCount}} 个蝦皮商品待关联。</p>
<div class="table-wrap">
<table>
<thead><tr><th>业务店铺</th><th>全局状态</th><th>SYB 名称</th><th>SYB 同步</th><th>蝦皮名称</th><th>蝦皮商品</th><th>更新时间</th><th>操作</th></tr></thead>
<tbody>
{{range .Rows}}
<tr>
<td><input name="display_name" value="{{.DisplayName}}" maxlength="500" required form="shop-edit-{{.ShopID}}"></td>
<td>{{if .Enabled}}启用{{else}}停用{{end}}</td>
<td><input name="syb_alias" value="{{.SybAlias}}" maxlength="500" placeholder="未配置" form="shop-edit-{{.ShopID}}"></td>
<td>{{if .SybAlias}}{{if and .Enabled .SybSyncEnabled}}同步{{else}}不进入同步{{end}}{{else}}—{{end}}</td>
<td><input name="shopee_alias" value="{{.ShopeeAlias}}" maxlength="500" placeholder="未配置" form="shop-edit-{{.ShopID}}"></td>
<td>{{.ShopeeProductCount}}</td>
<td>{{.UpdatedAt}}</td>
<td>
<form id="shop-edit-{{.ShopID}}" class="inline" method="post" action="/shops/update">
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}"><input type="hidden" name="shop_id" value="{{.ShopID}}">
<button type="submit">保存</button>
</form>
<form class="inline" method="post" action="/shops/status">
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}"><input type="hidden" name="shop_id" value="{{.ShopID}}"><input type="hidden" name="enabled" value="{{if .Enabled}}0{{else}}1{{end}}">
<button type="submit">{{if .Enabled}}停用店铺{{else}}启用店铺{{end}}</button>
</form>
{{if .SybAlias}}
<form class="inline" method="post" action="/shops/syb-status">
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}"><input type="hidden" name="shop_id" value="{{.ShopID}}"><input type="hidden" name="enabled" value="{{if .SybSyncEnabled}}0{{else}}1{{end}}">
<button type="submit">{{if .SybSyncEnabled}}停用 SYB{{else}}启用 SYB{{end}}</button>
</form>
{{end}}
{{if not .Enabled}}
<form class="inline" method="post" action="/shops/delete" data-confirm-submit="确定删除停用店铺“{{.DisplayName}}”吗?有关联商品或货运单时系统会拒绝删除。">
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}"><input type="hidden" name="shop_id" value="{{.ShopID}}"><button type="submit" class="danger">删除</button>
</form>
{{end}}
</td>
</tr>
{{else}}
<tr class="empty"><td colspan="8">还没有业务店铺。至少填写一个渠道名称后即可新增。</td></tr>
{{end}}
</tbody>
</table>
</div>
<div class="statusbar"><span class="grow"></span><span>共 {{len .Rows}} 个业务店铺</span></div>
{{template "footer" .}}
{{end}}
+12 -1
View File
@@ -11,6 +11,7 @@
<input type="hidden" name="status" value="{{.StatusFilter}}" form="shopee-bulk-form">
<input type="hidden" name="shop" value="{{.ShopFilter}}" form="shopee-bulk-form">
<input type="hidden" name="image" value="{{.ImageFilter}}" form="shopee-bulk-form">
<input type="hidden" name="store" value="{{.StoreFilter}}" form="shopee-bulk-form">
<input type="hidden" name="deleted" value="{{if .DeletedFilter}}1{{end}}" form="shopee-bulk-form">
<input type="hidden" name="page" value="{{.CurrentPage}}" form="shopee-bulk-form">
{{if not .DeletedFilter}}
@@ -39,6 +40,14 @@
<option value="{{.Value}}" {{if eq .Value $.ImageFilter}}selected{{end}}>{{.Text}}</option>
{{end}}
</select>
<label for="store">业务店铺</label>
<select id="store" name="store">
<option value="" {{if eq .StoreFilter ""}}selected{{end}}>全部业务店铺</option>
<option value="unlinked" {{if eq .StoreFilter "unlinked"}}selected{{end}}>待关联</option>
{{range .StoreOptions}}
<option value="{{.ShopID}}" {{if eq .ShopID $.StoreFilter}}selected{{end}}>{{.DisplayName}}{{if not .Enabled}}(已停用){{end}}</option>
{{end}}
</select>
{{if .CurrentUser.IsAdmin}}
<label for="deleted">数据范围</label>
<select id="deleted" name="deleted">
@@ -75,6 +84,7 @@
<th>图片</th>
<th>商品名称</th>
<th>蝦皮店铺</th>
<th>业务店铺</th>
<th>颜色</th>
<th>尺码</th>
{{/* SKU 数是这个商品报表里实际出现过的规格条数。
@@ -102,6 +112,7 @@
title 属性让悬停能看完整标题,收窄之后必须留着。 */}}
<td class="truncate col-title" title="{{.Title}}">{{.Title}}</td>
<td class="truncate col-shop" title="{{.ShopName}}">{{if .ShopName}}{{.ShopName}}{{else}}—{{end}}</td>
<td class="truncate col-shop" title="{{.BusinessShopName}}">{{if .ShopUnlinked}}<span class="missing">待关联</span>{{else}}{{.BusinessShopName}}{{end}}</td>
<td>{{.ColorCount}}</td>
<td>{{.SizeCount}}</td>
<td>{{.SKUCount}}</td>
@@ -113,7 +124,7 @@
</tr>
{{else}}
<tr class="empty">
<td colspan="13">
<td colspan="14">
{{if .IsFiltered}}
当前筛选条件下没有商品。请调整状态、店铺、图片或商品 ID。<br>
<small><a href="/shopee">清除筛选条件</a></small>
+2 -2
View File
@@ -21,7 +21,7 @@
</form>
<button type="button" data-modal-open="sync-history-modal">同步记录</button>
{{if .CurrentUser.IsAdmin}}<a class="button-link" href="/syb/shops">同步店铺({{.EnabledSyncShopCount}})</a>{{end}}
{{if .CurrentUser.IsAdmin}}<a class="button-link" href="/shops">店铺管理(同步 {{.EnabledSyncShopCount}})</a>{{end}}
<form id="syb-collect-form" method="post" action="/syb/collect-pdd-batch" hidden></form>
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}" form="syb-collect-form">
@@ -67,7 +67,7 @@
{{if .RangeError}}<p class="missing sync-range-message" role="alert">{{.RangeError}}</p>{{end}}
{{if .RangeWarning}}<p class="hint sync-range-message">{{.RangeWarning}}</p>{{end}}
<p class="hint sync-range-message">
按顺运宝货运单创建日期(UTC+8)同步,开始日和结束日都包含,每次最多 31 天;当前启用 {{.EnabledSyncShopCount}} 个同步店铺。
按顺运宝货运单创建日期(UTC+8)同步,开始日和结束日都包含,每次最多 31 天;当前在店铺管理中启用 {{.EnabledSyncShopCount}} 个 SYB 同步店铺。
</p>
<div class="modal-backdrop" id="sync-history-modal" {{if not .NeedSyncHistory}}hidden{{end}}>
-54
View File
@@ -1,54 +0,0 @@
{{define "syb/shops"}}
{{template "header" .}}
<div class="toolbar">
<form class="inline grow" method="post" action="/syb/shops/create">
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
<label for="shop-name">店铺名称</label>
<input id="shop-name" type="text" name="shop_name" maxlength="500" required
placeholder="与顺运宝 shopName 完全一致">
<button type="submit" class="primary">新增并启用</button>
</form>
<a class="button-link" href="/syb">返回顺运宝数据</a>
</div>
{{if .Message}}<p class="hint" role="status">{{.Message}}</p>{{end}}
{{if .Error}}<p class="missing" role="alert">{{.Error}}</p>{{end}}
<p class="hint">同步只接受启用店铺;匹配时忽略名称首尾空白,但不做模糊匹配。没有启用店铺时同步会安全停止。</p>
<div class="table-wrap">
<table>
<thead><tr><th>店铺名称</th><th>状态</th><th>更新时间</th><th>操作</th></tr></thead>
<tbody>
{{range .Rows}}
<tr>
<td title="{{.ShopName}}">{{.ShopName}}</td>
<td>{{if .Enabled}}启用{{else}}停用{{end}}</td>
<td>{{.UpdatedAt}}</td>
<td>
<form class="inline" method="post" action="/syb/shops/status">
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
<input type="hidden" name="shop_id" value="{{.ShopID}}">
<input type="hidden" name="enabled" value="{{if .Enabled}}0{{else}}1{{end}}">
<button type="submit">{{if .Enabled}}停用{{else}}重新启用{{end}}</button>
</form>
{{if not .Enabled}}
<form class="inline" method="post" action="/syb/shops/delete"
data-confirm-submit="确定永久删除已停用店铺“{{.ShopName}}”吗?历史货运单和同步记录不会删除;如需恢复,必须重新新增该店铺。">
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
<input type="hidden" name="shop_id" value="{{.ShopID}}">
<button type="submit" class="danger">删除</button>
</form>
{{end}}
</td>
</tr>
{{else}}
<tr class="empty"><td colspan="4">还没有同步店铺。请先新增并启用至少一个店铺,才能开始同步。</td></tr>
{{end}}
</tbody>
</table>
</div>
<div class="statusbar"><span class="grow"></span><span>共 {{len .Rows}} 个店铺,启用 {{.EnabledCount}} 个</span></div>
{{template "footer" .}}
{{end}}