Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
S
skills
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
allen.wang
skills
Commits
141c5999
Commit
141c5999
authored
Apr 19, 2026
by
allen.wang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix:优化报表效果-效率
parent
efff934e
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
215 additions
and
109 deletions
+215
-109
sync_inventory_monthly_assets.py
vip-report/scripts/sync_inventory_monthly_assets.py
+64
-35
sync_monthly_sales_assets.py
vip-report/scripts/sync_monthly_sales_assets.py
+50
-26
sync_top_products_assets.py
vip-report/scripts/sync_top_products_assets.py
+51
-21
sync_warehouse_100060_assets.py
vip-report/scripts/sync_warehouse_100060_assets.py
+50
-27
No files found.
vip-report/scripts/sync_inventory_monthly_assets.py
View file @
141c5999
...
...
@@ -464,12 +464,12 @@ def build_shoes_filters(
return
filters
def
build_
overall
_ui_filter_actions
(
def
build_
time
_ui_filter_actions
(
report_month
:
str
,
report_year
:
int
,
compare_year
:
int
|
None
=
None
,
)
->
list
[
dict
[
str
,
Any
]]:
"""
Force S04 Overall to re-apply the visible time
quick filters through the UI."""
"""
Apply the visible Month and billdate 年
quick filters through the UI."""
month_values
=
[
normalize_month_label
(
index
)
for
index
in
range
(
1
,
resolve_month_index
(
report_month
)
+
1
)
...
...
@@ -491,6 +491,15 @@ def build_overall_ui_filter_actions(
},
]
def
build_overall_ui_filter_actions
(
report_month
:
str
,
report_year
:
int
,
compare_year
:
int
|
None
=
None
,
)
->
list
[
dict
[
str
,
Any
]]:
"""Force S04 Overall to re-apply the visible time quick filters through the UI."""
return
build_time_ui_filter_actions
(
report_month
,
report_year
,
compare_year
)
def
build_specs
(
report_month
:
str
,
report_year
:
int
,
compare_year
:
int
)
->
dict
[
str
,
Any
]:
"""Helper."""
filters
=
[
...
...
@@ -505,13 +514,26 @@ def build_specs(report_month: str, report_year: int, compare_year: int) -> dict[
report_year
,
compare_year
,
)
s05_filters
=
normalize_dashboard_download_filters
(
build_bags_filters
(
report_month
,
report_year
,
compare_year
)
bags_shoes_ui_filter_actions
=
build_time_ui_filter_actions
(
report_month
,
report_year
,
compare_year
,
)
s05_filters
=
[
filter_spec
for
filter_spec
in
normalize_dashboard_download_filters
(
build_bags_filters
(
report_month
,
report_year
,
compare_year
)
)
if
filter_spec
.
get
(
"label"
)
==
"storename"
]
# S06 intentionally mirrors the S05 Bags flow; only the Tableau page differs.
s06_filters
=
normalize_dashboard_download_filters
(
build_bags_filters
(
report_month
,
report_year
,
compare_year
)
)
s06_filters
=
[
filter_spec
for
filter_spec
in
normalize_dashboard_download_filters
(
build_bags_filters
(
report_month
,
report_year
,
compare_year
)
)
if
filter_spec
.
get
(
"label"
)
==
"storename"
]
s07_filters
=
normalize_dashboard_download_filters
(
build_s07_filters
(
report_month
,
report_year
,
compare_year
)
)
...
...
@@ -526,7 +548,7 @@ def build_specs(report_month: str, report_year: int, compare_year: int) -> dict[
"filters"
:
filters
,
"capture_mode"
:
"download_image"
,
"post_filter_wait_ms"
:
INVENTORY_MONTHLY_OVERALL_POST_FILTER_WAIT_MS
,
"ui_filter_mode"
:
"s
napsho
t"
,
"ui_filter_mode"
:
"s
crip
t"
,
"ui_filter_actions"
:
s04_ui_filter_actions
,
"ui_filter_post_wait_ms"
:
8000
,
"ui_filter_forbidden_text_patterns"
:
[
"当前筛选器没有要可视化的数据"
],
...
...
@@ -546,6 +568,10 @@ def build_specs(report_month: str, report_year: int, compare_year: int) -> dict[
"viewport"
:
{
"width"
:
1280
,
"height"
:
960
},
"capture_mode"
:
"download_image"
,
"post_filter_wait_ms"
:
INVENTORY_MONTHLY_DOWNLOAD_POST_FILTER_WAIT_MS
,
"ui_filter_mode"
:
"script"
,
"ui_filter_actions"
:
bags_shoes_ui_filter_actions
,
"ui_filter_post_wait_ms"
:
8000
,
"ui_filter_forbidden_text_patterns"
:
[
"当前筛选器没有要可视化的数据"
],
"params"
:
{},
"raw_screenshot_name"
:
"inventory-s05-bags-download.png"
,
"note"
:
"S05 bags dashboard export after applying active-sheet filters."
,
...
...
@@ -559,6 +585,10 @@ def build_specs(report_month: str, report_year: int, compare_year: int) -> dict[
"capture_mode"
:
"download_image"
,
"viewport"
:
{
"width"
:
1280
,
"height"
:
960
},
"post_filter_wait_ms"
:
INVENTORY_MONTHLY_DOWNLOAD_POST_FILTER_WAIT_MS
,
"ui_filter_mode"
:
"script"
,
"ui_filter_actions"
:
bags_shoes_ui_filter_actions
,
"ui_filter_post_wait_ms"
:
8000
,
"ui_filter_forbidden_text_patterns"
:
[
"当前筛选器没有要可视化的数据"
],
"params"
:
{},
"raw_screenshot_name"
:
"inventory-s06-shoes-download.png"
,
"note"
:
"S06 shoes dashboard export after applying active-sheet filters."
,
...
...
@@ -814,6 +844,11 @@ def resolve_playwright_download_path(filename: str, download_dir: Path | None =
return
path
def
resolve_session_capture_path
(
root
:
Path
,
session
:
str
,
filename
:
str
)
->
Path
:
"""Helper."""
return
root
/
"output"
/
"playwright"
/
session
/
filename
def
build_login_js
(
username
:
str
,
password
:
str
)
->
str
:
"""Helper."""
payload
=
{
"username"
:
username
,
"password"
:
password
}
...
...
@@ -2283,11 +2318,25 @@ def build_apply_quick_filters_js(spec: dict[str, Any]) -> str:
}});
}}
const checkedAfter = await listCheckedRows(listbox);
const checkedAfterLabels = [...new Set(
checkedAfter
.map((entry) => String(entry?.text || '').trim())
.filter((value) => value && value !== allFilterValue)
)];
const desiredCheckedLabels = [...new Set(
desiredValues
.map((value) => String(value || '').trim())
.filter((value) => value && value !== allFilterValue)
)];
const exactSelection =
checkedAfterLabels.length === desiredCheckedLabels.length &&
desiredCheckedLabels.every((value) => checkedAfterLabels.includes(value));
const closeMethod = await closeQuickFilter(button);
const finalButtonText = await waitForButtonText(button, expectedButtonText, Number(spec.close_wait_ms || 15000));
const ok =
missingValues.length === 0 &&
desiredStates.every((entry) => entry.checked) &&
exactSelection &&
(!expectedButtonText || finalButtonText.includes(expectedButtonText));
return {{
ok,
...
...
@@ -2299,6 +2348,9 @@ def build_apply_quick_filters_js(spec: dict[str, Any]) -> str:
desiredValues,
checkedBefore,
checkedAfter,
checkedAfterLabels,
desiredCheckedLabels,
exactSelection,
desiredStates,
actionsTaken,
missingValues,
...
...
@@ -2744,29 +2796,9 @@ def load_state_if_present(
def
locate_session_file
(
root
:
Path
,
session
:
str
,
filename
:
str
)
->
Path
:
"""Helper."""
direct
=
r
oot
/
"output"
/
"playwright"
/
session
/
filename
direct
=
r
esolve_session_capture_path
(
root
,
session
,
filename
)
if
direct
.
exists
():
return
direct
search_roots
=
[
root
/
"output"
/
"playwright"
,
root
/
"output"
/
"vip-report"
,
root
,
]
matches
:
list
[
Path
]
=
[]
for
search_root
in
search_roots
:
if
search_root
.
exists
():
matches
.
extend
(
search_root
.
rglob
(
filename
))
if
len
(
matches
)
==
1
:
return
matches
[
0
]
if
matches
:
latest
=
sorted
(
{
item
.
resolve
()
for
item
in
matches
},
key
=
lambda
item
:
item
.
stat
()
.
st_mtime
,
reverse
=
True
,
)[
0
]
return
latest
raise
FileNotFoundError
(
f
"Unable to locate {filename} under {root}."
)
...
...
@@ -2812,17 +2844,14 @@ def wait_for_capture_file(
)
wait_deadline
=
time
.
monotonic
()
+
effective_timeout
local_output
=
workdir
/
filename
session_output
=
resolve_session_capture_path
(
workspace_root
,
session
,
filename
)
while
time
.
monotonic
()
<
wait_deadline
:
if
preferred_path
is
not
None
and
preferred_path
.
exists
():
return
preferred_path
if
local_output
.
exists
():
return
local_output
try
:
located
=
locate_session_file
(
workspace_root
,
session
,
filename
)
if
located
.
exists
():
return
located
except
FileNotFoundError
:
pass
if
session_output
.
exists
():
return
session_output
time
.
sleep
(
1
)
raise
FileNotFoundError
(
f
"Unable to locate {filename} under {workspace_root}."
)
...
...
vip-report/scripts/sync_monthly_sales_assets.py
View file @
141c5999
...
...
@@ -338,6 +338,18 @@ def write_js(workdir: Path, name: str, content: str) -> Path:
return
path
def
resolve_playwright_download_path
(
filename
:
str
,
workdir
:
Path
)
->
Path
:
"""Helper."""
path
=
workdir
/
".playwright-downloads"
/
filename
path
.
parent
.
mkdir
(
parents
=
True
,
exist_ok
=
True
)
return
path
def
resolve_session_capture_path
(
root
:
Path
,
session
:
str
,
filename
:
str
)
->
Path
:
"""Helper."""
return
root
/
"output"
/
"playwright"
/
session
/
filename
def
build_login_js
(
username
:
str
,
password
:
str
)
->
str
:
"""Helper."""
payload
=
{
...
...
@@ -762,27 +774,26 @@ def load_state_if_present(session: str, state_path: Path, *, cwd: Path) -> None:
)
def
locate_session_file
(
root
:
Path
,
session
:
str
,
filename
:
str
)
->
Path
:
def
locate_session_file
(
root
:
Path
,
session
:
str
,
filename
:
str
,
*
,
workdir
:
Path
|
None
=
None
,
)
->
Path
:
"""Helper."""
direct
=
root
/
"output"
/
"playwright"
/
session
/
filename
if
direct
.
exists
():
return
direct
search_roots
=
[
root
/
"output"
/
"playwright"
,
root
/
"output"
/
"vip-report"
,
root
,
]
matches
:
list
[
Path
]
=
[]
for
search_root
in
search_roots
:
if
search_root
.
exists
():
matches
.
extend
(
search_root
.
rglob
(
filename
))
if
len
(
matches
)
==
1
:
return
matches
[
0
]
if
matches
:
latest
=
sorted
({
item
.
resolve
()
for
item
in
matches
},
key
=
lambda
item
:
item
.
stat
()
.
st_mtime
,
reverse
=
True
)[
0
]
return
latest
candidates
:
list
[
Path
]
=
[]
if
workdir
is
not
None
:
candidates
.
extend
(
[
resolve_playwright_download_path
(
filename
,
workdir
),
workdir
/
filename
,
]
)
candidates
.
append
(
resolve_session_capture_path
(
root
,
session
,
filename
))
for
candidate
in
candidates
:
if
candidate
.
exists
():
return
candidate
raise
FileNotFoundError
(
f
"Unable to locate {filename} under {root}."
)
...
...
@@ -939,6 +950,18 @@ def capture_tableau_view(
)
->
Path
:
"""Helper."""
target_url
=
build_tableau_target_url
(
base_url
,
capture_spec
[
"hash_url"
])
preferred_capture_path
=
resolve_playwright_download_path
(
capture_spec
[
"raw_screenshot_name"
],
workdir
)
legacy_session_output
=
resolve_session_capture_path
(
workspace_root
,
session
,
capture_spec
[
"raw_screenshot_name"
],
)
for
stale_path
in
(
preferred_capture_path
,
workdir
/
capture_spec
[
"raw_screenshot_name"
],
legacy_session_output
,
):
stale_path
.
unlink
(
missing_ok
=
True
)
goto_with_retry
(
session
,
target_url
,
cwd
=
workdir
)
run_playwright
(
[
"--session"
,
session
,
"resize"
,
str
(
VIEWPORT
[
"width"
]),
str
(
VIEWPORT
[
"height"
])],
...
...
@@ -963,7 +986,7 @@ def capture_tableau_view(
f
"tmp-{capture_spec['capture_id']}-capture.js"
,
build_export_image_js
(
capture_spec
[
"inner_frame_fragment"
],
str
(
(
workdir
/
capture_spec
[
"raw_screenshot_name"
])
.
resolve
()),
str
(
preferred_capture_path
.
resolve
()),
viewport
=
VIEWPORT
,
),
)
...
...
@@ -994,11 +1017,12 @@ def capture_tableau_view(
configure_script
.
unlink
(
missing_ok
=
True
)
capture_script
.
unlink
(
missing_ok
=
True
)
local_output
=
workdir
/
capture_spec
[
"raw_screenshot_name"
]
if
local_output
.
exists
():
normalize_image_size
(
local_output
,
{
"width"
:
1400
,
"height"
:
3360
})
return
local_output
captured_path
=
locate_session_file
(
workspace_root
,
session
,
capture_spec
[
"raw_screenshot_name"
])
captured_path
=
locate_session_file
(
workspace_root
,
session
,
capture_spec
[
"raw_screenshot_name"
],
workdir
=
workdir
,
)
normalize_image_size
(
captured_path
,
{
"width"
:
1400
,
"height"
:
3360
})
return
captured_path
...
...
vip-report/scripts/sync_top_products_assets.py
View file @
141c5999
...
...
@@ -488,6 +488,18 @@ def write_js(workdir: Path, name: str, content: str) -> Path:
return
path
def
resolve_playwright_download_path
(
filename
:
str
,
workdir
:
Path
)
->
Path
:
"""Helper."""
path
=
workdir
/
".playwright-downloads"
/
filename
path
.
parent
.
mkdir
(
parents
=
True
,
exist_ok
=
True
)
return
path
def
resolve_session_capture_path
(
root
:
Path
,
session
:
str
,
filename
:
str
)
->
Path
:
"""Helper."""
return
root
/
"output"
/
"playwright"
/
session
/
filename
def
build_login_js
(
username
:
str
,
password
:
str
)
->
str
:
"""Helper."""
payload
=
{
"username"
:
username
,
"password"
:
password
}
...
...
@@ -1629,22 +1641,27 @@ def load_state_if_present(session: str, state_path: Path, *, cwd: Path) -> None:
run_playwright
([
"--session"
,
session
,
"state-load"
,
str
(
state_path
)],
cwd
=
cwd
,
timeout
=
60
)
def
locate_session_file
(
root
:
Path
,
session
:
str
,
filename
:
str
)
->
Path
:
def
locate_session_file
(
root
:
Path
,
session
:
str
,
filename
:
str
,
*
,
workdir
:
Path
|
None
=
None
,
)
->
Path
:
"""Helper."""
direct
=
root
/
"output"
/
"playwright"
/
session
/
filename
if
direct
.
exists
():
return
direct
search_roots
=
[
root
/
"output"
/
"playwright"
,
root
/
"output"
/
"vip-report"
,
root
]
matches
:
list
[
Path
]
=
[]
for
search_root
in
search_roots
:
if
search_root
.
exists
():
matches
.
extend
(
search_root
.
rglob
(
filename
))
if
not
matches
:
raise
FileNotFoundError
(
f
"Unable to locate {filename} under {root}."
)
return
sorted
({
item
.
resolve
()
for
item
in
matches
},
key
=
lambda
item
:
item
.
stat
()
.
st_mtime
,
reverse
=
True
)[
0
]
candidates
:
list
[
Path
]
=
[]
if
workdir
is
not
None
:
candidates
.
extend
(
[
resolve_playwright_download_path
(
filename
,
workdir
),
workdir
/
filename
,
]
)
candidates
.
append
(
resolve_session_capture_path
(
root
,
session
,
filename
))
for
candidate
in
candidates
:
if
candidate
.
exists
():
return
candidate
raise
FileNotFoundError
(
f
"Unable to locate {filename} under {root}."
)
def
crop_image
(
source
:
Path
,
target
:
Path
,
crop
:
dict
[
str
,
int
],
*
,
resize_to
:
dict
[
str
,
int
]
|
None
=
None
)
->
None
:
...
...
@@ -1673,6 +1690,18 @@ def capture_tableau_view(
)
->
Path
:
"""Helper."""
target_url
=
f
"{base_url}{capture_spec['hash_url']}"
preferred_capture_path
=
resolve_playwright_download_path
(
capture_spec
[
"raw_screenshot_name"
],
workdir
)
legacy_session_output
=
resolve_session_capture_path
(
workspace_root
,
session
,
capture_spec
[
"raw_screenshot_name"
],
)
for
stale_path
in
(
preferred_capture_path
,
workdir
/
capture_spec
[
"raw_screenshot_name"
],
legacy_session_output
,
):
stale_path
.
unlink
(
missing_ok
=
True
)
def
reset_target_page
()
->
None
:
run_playwright
([
"--session"
,
session
,
"goto"
,
target_url
],
cwd
=
workdir
,
timeout
=
120
)
run_playwright
(
...
...
@@ -1737,7 +1766,7 @@ def capture_tableau_view(
f
"tmp-{capture_spec['capture_id']}-capture.js"
,
build_export_image_js
(
capture_spec
[
"inner_frame_fragment"
],
str
(
(
workdir
/
capture_spec
[
"raw_screenshot_name"
])
.
resolve
()),
str
(
preferred_capture_path
.
resolve
()),
viewport
=
VIEWPORT
,
),
)
...
...
@@ -1871,11 +1900,12 @@ def capture_tableau_view(
wait_script
.
unlink
(
missing_ok
=
True
)
capture_script
.
unlink
(
missing_ok
=
True
)
local_output
=
workdir
/
capture_spec
[
"raw_screenshot_name"
]
if
local_output
.
exists
():
normalize_image_size
(
local_output
,
{
"width"
:
1400
,
"height"
:
3760
})
return
local_output
captured_path
=
locate_session_file
(
workspace_root
,
session
,
capture_spec
[
"raw_screenshot_name"
])
captured_path
=
locate_session_file
(
workspace_root
,
session
,
capture_spec
[
"raw_screenshot_name"
],
workdir
=
workdir
,
)
normalize_image_size
(
captured_path
,
{
"width"
:
1400
,
"height"
:
3760
})
return
captured_path
...
...
vip-report/scripts/sync_warehouse_100060_assets.py
View file @
141c5999
...
...
@@ -341,6 +341,18 @@ def write_js(workdir: Path, name: str, content: str) -> Path:
return
path
def
resolve_playwright_download_path
(
filename
:
str
,
workdir
:
Path
)
->
Path
:
"""Helper."""
path
=
workdir
/
".playwright-downloads"
/
filename
path
.
parent
.
mkdir
(
parents
=
True
,
exist_ok
=
True
)
return
path
def
resolve_session_capture_path
(
root
:
Path
,
session
:
str
,
filename
:
str
)
->
Path
:
"""Helper."""
return
root
/
"output"
/
"playwright"
/
session
/
filename
def
build_login_js
(
username
:
str
,
password
:
str
)
->
str
:
"""Helper."""
payload
=
{
"username"
:
username
,
"password"
:
password
}
...
...
@@ -591,26 +603,26 @@ def load_state_if_present(session: str, state_path: Path, *, cwd: Path) -> None:
pass
def
locate_session_file
(
root
:
Path
,
session
:
str
,
filename
:
str
)
->
Path
:
def
locate_session_file
(
root
:
Path
,
session
:
str
,
filename
:
str
,
*
,
workdir
:
Path
|
None
=
None
,
)
->
Path
:
"""Helper."""
search_roots
=
[
root
/
"output"
/
"playwright"
,
root
/
"output"
/
"vip-report"
,
root
,
]
matches
:
list
[
Path
]
=
[]
for
search_root
in
search_roots
:
if
search_root
.
exists
():
matches
.
extend
(
search_root
.
rglob
(
filename
))
if
len
(
matches
)
==
1
:
return
matches
[
0
]
if
matches
:
return
sorted
(
{
item
.
resolve
()
for
item
in
matches
},
key
=
lambda
item
:
item
.
stat
()
.
st_mtime
,
reverse
=
True
,
)[
0
]
candidates
:
list
[
Path
]
=
[]
if
workdir
is
not
None
:
candidates
.
extend
(
[
resolve_playwright_download_path
(
filename
,
workdir
),
workdir
/
filename
,
]
)
candidates
.
append
(
resolve_session_capture_path
(
root
,
session
,
filename
))
for
candidate
in
candidates
:
if
candidate
.
exists
():
return
candidate
raise
FileNotFoundError
(
f
"Unable to locate {filename} under {root}."
)
...
...
@@ -707,8 +719,18 @@ def capture_tableau_view(
)
->
Path
:
"""Helper."""
target_url
=
f
"{base_url}{capture_spec['hash_url']}"
local_output
=
workdir
/
capture_spec
[
"raw_screenshot_name"
]
local_output
.
unlink
(
missing_ok
=
True
)
preferred_capture_path
=
resolve_playwright_download_path
(
capture_spec
[
"raw_screenshot_name"
],
workdir
)
legacy_session_output
=
resolve_session_capture_path
(
workspace_root
,
session
,
capture_spec
[
"raw_screenshot_name"
],
)
for
stale_path
in
(
preferred_capture_path
,
workdir
/
capture_spec
[
"raw_screenshot_name"
],
legacy_session_output
,
):
stale_path
.
unlink
(
missing_ok
=
True
)
run_playwright
([
"--session"
,
session
,
"goto"
,
target_url
],
cwd
=
workdir
,
timeout
=
120
)
run_playwright
(
[
"--session"
,
session
,
"resize"
,
str
(
VIEWPORT
[
"width"
]),
str
(
VIEWPORT
[
"height"
])],
...
...
@@ -726,7 +748,7 @@ def capture_tableau_view(
f
"tmp-{capture_spec['capture_id']}-{time.time_ns()}-capture.js"
,
build_export_image_js
(
capture_spec
[
"inner_frame_fragment"
],
str
(
(
workdir
/
capture_spec
[
"raw_screenshot_name"
])
.
resolve
()),
str
(
preferred_capture_path
.
resolve
()),
viewport
=
VIEWPORT
,
),
)
...
...
@@ -770,11 +792,12 @@ def capture_tableau_view(
configure_script
.
unlink
(
missing_ok
=
True
)
capture_script
.
unlink
(
missing_ok
=
True
)
if
local_output
.
exists
():
wait_for_image_ready
(
local_output
)
normalize_image_size
(
local_output
,
{
"width"
:
1400
,
"height"
:
3360
})
return
local_output
captured_path
=
locate_session_file
(
workspace_root
,
session
,
capture_spec
[
"raw_screenshot_name"
])
captured_path
=
locate_session_file
(
workspace_root
,
session
,
capture_spec
[
"raw_screenshot_name"
],
workdir
=
workdir
,
)
wait_for_image_ready
(
captured_path
)
normalize_image_size
(
captured_path
,
{
"width"
:
1400
,
"height"
:
3360
})
return
captured_path
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment