通勤認定エクセルツール対応13 M1 対応2
This commit is contained in:
184
src/sh/tuk/AUDIT_ISSUES_2026_05_28.md
Normal file
184
src/sh/tuk/AUDIT_ISSUES_2026_05_28.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# tuk Project Audit Issues
|
||||
|
||||
Status: Open
|
||||
Audit date: 2026-05-28
|
||||
|
||||
---
|
||||
|
||||
## Critical (Runtime Bugs)
|
||||
|
||||
### 1. M2.cls:341-356 — cacheVal used outside If block
|
||||
|
||||
**Severity:** 🔴 Critical
|
||||
**File:** `sheet/M2.cls`
|
||||
**Line:** 341-356
|
||||
|
||||
`cacheVal` is declared inside `If cache.Exists(code)` block but used in `Select Case` below regardless:
|
||||
|
||||
```vba
|
||||
If cache.Exists(code) Then
|
||||
Dim cacheVal As Variant: cacheVal = cache(code)
|
||||
...
|
||||
End If
|
||||
|
||||
Select Case kenshu
|
||||
Case "2"
|
||||
ws.Range("L" & rowNum).Value = Trim(cacheVal(1)) ' bug if code not in cache
|
||||
```
|
||||
|
||||
Fix: move `Dim cacheVal As Variant` before the `If cache.Exists(code)` check.
|
||||
|
||||
---
|
||||
|
||||
### 2. C1.cls:984-997 — undeclared variables in Validate
|
||||
|
||||
**Severity:** 🔴 Critical
|
||||
**File:** `sheet/C1.cls`
|
||||
**Line:** 984-997
|
||||
|
||||
Three variables used without `Dim` in the kukan duplicate-check loop:
|
||||
|
||||
```vba
|
||||
For kukanIdx = LBound(KUKAN_CODE_COLS) To UBound(KUKAN_CODE_COLS)
|
||||
kukanCol = KUKAN_CODE_COLS(kukanIdx) ' not declared
|
||||
kukanCode = Trim(Me.Cells(rowNum, kukanCol).Value)
|
||||
...
|
||||
kukanLetter = Split(Me.Cells(1, kukanCol).Address, "$")(1) ' not declared
|
||||
```
|
||||
|
||||
Fix: add `Dim kukanCol As Long, kukanCode As String, kukanLetter As String` at the top of `Validate`.
|
||||
|
||||
---
|
||||
|
||||
## AGENTS.md Violations
|
||||
|
||||
### 3. CJK Comments in Code
|
||||
|
||||
**Severity:** 🟡 AGENTS.md violation
|
||||
**Files:** `module/Common_Shape.bas`, `sheet/C1.cls`
|
||||
|
||||
| File | Line | Content |
|
||||
|------|------|---------|
|
||||
| `Common_Shape.bas` | 4 | `通用排版引擎(仅调整位置)` |
|
||||
| `Common_Shape.bas` | 22 | `第一个图标左边对齐B3左边` |
|
||||
| `Common_Shape.bas` | 44 | `你的专属调用入口` |
|
||||
| `C1.cls` | 675 | `vals(1) = D列, vals(3) = F列, vals(4) = G列` |
|
||||
|
||||
Fix: translate to English per AGENTS.md English-only comments rule.
|
||||
|
||||
---
|
||||
|
||||
### 4. Hardcoded File Path in Import_modules
|
||||
|
||||
**Severity:** 🟡 AGENTS.md violation
|
||||
**File:** `init_module/Import_modules.bas`
|
||||
**Line:** 8
|
||||
|
||||
```vba
|
||||
Const PROJECT_PATH As String = "D:\Project\upds7\vba\"
|
||||
```
|
||||
|
||||
Fix: use a config-based path or a constant defined in `Common_Constants.bas`.
|
||||
|
||||
---
|
||||
|
||||
### 5. Hardcoded Sheet Name in Z4.cls
|
||||
|
||||
**Severity:** 🟡 AGENTS.md violation
|
||||
**File:** `sheet/Z4.cls`
|
||||
**Line:** 14
|
||||
|
||||
```vba
|
||||
Set ws = ThisWorkbook.Worksheets("Z4")
|
||||
```
|
||||
|
||||
Fix: use `CACHE_Z4` constant instead of the string literal.
|
||||
|
||||
---
|
||||
|
||||
### 6. Hardcoded "M1" in Common_Shape
|
||||
|
||||
**Severity:** 🟡 AGENTS.md violation
|
||||
**File:** `module/Common_Shape.bas`
|
||||
**Line:** 47
|
||||
|
||||
```vba
|
||||
sheetName:="M1"
|
||||
```
|
||||
|
||||
Fix: pass as parameter or use constant.
|
||||
|
||||
---
|
||||
|
||||
## Code Quality
|
||||
|
||||
### 7. O1/O2/O3 Validate Stubs
|
||||
|
||||
**Severity:** 🟠 Quality
|
||||
**Files:** `sheet/O1.cls`, `sheet/O2.cls`, `sheet/O3.cls`
|
||||
|
||||
All three have `Validate` methods that are empty stubs — just `Exit Sub`. If validation runs on these sheets, all rows pass silently.
|
||||
|
||||
Fix: implement proper validation or confirm empty stubs are intentional.
|
||||
|
||||
---
|
||||
|
||||
### 8. On Error Resume Next — 7 instances
|
||||
|
||||
**Severity:** 🟠 Quality
|
||||
**Files:** `Common_Global_Cache.bas`, `Common_Functions.bas`, `Common_Shape.bas`, `Test_Cache.bas`, `Import_modules.bas`
|
||||
|
||||
These silently swallow errors (e.g., "subscript out of range" for missing worksheets):
|
||||
|
||||
| File | Line | Target |
|
||||
|------|------|--------|
|
||||
| `Common_Global_Cache.bas` | 91 | `ThisWorkbook.Worksheets("M1")` |
|
||||
| `Common_Global_Cache.bas` | 155 | `ThisWorkbook.Worksheets("M2")` |
|
||||
| `Common_Global_Cache.bas` | 232 | `ThisWorkbook.Worksheets("M1")` |
|
||||
| `Common_Functions.bas` | 101 | `ThisWorkbook.Worksheets(sheetName)` |
|
||||
| `Common_Shape.bas` | 14 | `ThisWorkbook.Worksheets(sheetName)` |
|
||||
| `Test_Cache.bas` | 25 | `ThisWorkbook.Worksheets("Test_Cache")` |
|
||||
| `Import_modules.bas` | 82, 126 | `VBProject.VBComponents` |
|
||||
|
||||
Fix: use `On Error GoTo ErrHandler` pattern with `Err.Raise` for missing objects, or explicitly check worksheet existence before access.
|
||||
|
||||
---
|
||||
|
||||
### 9. Fixed Cell Reference in C1 Validate
|
||||
|
||||
**Severity:** 🟠 Quality
|
||||
**File:** `sheet/C1.cls`
|
||||
**Line:** 1000
|
||||
|
||||
```vba
|
||||
Dim linkCellValue As String: linkCellValue = Me.Cells(3, "H").Value
|
||||
```
|
||||
|
||||
Fixed address `Cells(3, "H")` used as a config switch. No constant or comment explaining its purpose.
|
||||
|
||||
Fix: add a named constant or sheetConf entry for this cell.
|
||||
|
||||
---
|
||||
|
||||
## Resolved / Correct
|
||||
|
||||
- All modules have `Option Explicit` ✅
|
||||
- All `Worksheet_Change` handlers disable `EnableEvents` and use `Finally:` pattern ✅
|
||||
- All sheet classes have English module headers ✅
|
||||
- T2 `FillZeroIfEmpty` uses `sheetConf("ZeroFillCols")` with letter strings ✅
|
||||
- Z4 `LookupZ4RosenCache` uses F col for rosen, D col for station ✅
|
||||
- `Common_Selector.BuildZ4StationToDropdown` iterates `stationFromDict.Keys` to exclude `stationFrom` ✅
|
||||
- No `Select`/`Selection`/`ActiveCell` patterns in sheet classes ✅
|
||||
- All `Validate` methods in Z-series and T-series have proper checkResult pattern ✅
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Severity | Count |
|
||||
|----------|-------|
|
||||
| 🔴 Critical | 2 |
|
||||
| 🟡 AGENTS.md violation | 4 |
|
||||
| 🟠 Code quality | 3 |
|
||||
|
||||
Priority: Fix #1 → #2 → #3 → #4
|
||||
@@ -5,9 +5,11 @@ Sub ImportModulesAndSheets_Safe()
|
||||
Dim fso As Object
|
||||
Set fso = CreateObject("Scripting.FileSystemObject")
|
||||
|
||||
Const PROJECT_PATH As String = "D:\Project\upds7\vba\"
|
||||
Const MODULE_PATH As String = PROJECT_PATH & "src\sh\tuk\module"
|
||||
Const SHEET_PATH As String = PROJECT_PATH & "src\sh\tuk\sheet"
|
||||
Dim basePath As String: basePath = ThisWorkbook.Path
|
||||
If Right(basePath, 1) <> "\" Then basePath = basePath & "\"
|
||||
Const PROJECT_PATH As String = basePath
|
||||
Const MODULE_PATH As String = basePath & "src\sh\tuk\module"
|
||||
Const SHEET_PATH As String = basePath & "src\sh\tuk\sheet"
|
||||
|
||||
' --- Phase 1: Validation ---
|
||||
Debug.Print "[LOG] Starting validation phase..."
|
||||
|
||||
@@ -98,12 +98,9 @@ Function LoadLookup(ByVal sheetName As String, ByVal cacheName As String) As Obj
|
||||
|
||||
' --- obtain worksheet ---
|
||||
Dim ws As Worksheet
|
||||
On Error Resume Next
|
||||
Set ws = ThisWorkbook.Worksheets(sheetName)
|
||||
On Error GoTo ErrHandler
|
||||
If ws Is Nothing Then
|
||||
Err.Raise ERR_SHEET_MISSING, "LoadLookup", "Worksheet '" & sheetName & "' not found."
|
||||
End If
|
||||
Set ws = ThisWorkbook.Worksheets(sheetName)
|
||||
' ws exists, continue
|
||||
|
||||
Dim sheetConf As Object: Set sheetConf = sheetConfDict(cacheName)
|
||||
Dim startRow As Long: startRow = sheetConf("StartRow")
|
||||
@@ -334,39 +331,46 @@ End Function
|
||||
Public Function FormatDateInput(ByVal inputStr As String) As String
|
||||
Dim s As String: s = Trim(inputStr)
|
||||
If s = "" Then Exit Function
|
||||
|
||||
' Only process pure digit strings
|
||||
If Not IsNumeric(s) Then
|
||||
FormatDateInput = inputStr
|
||||
|
||||
' Handle pure digit strings (YYYYMMDD / YYMMDD)
|
||||
If IsNumeric(s) Then
|
||||
Dim yearPart As String, monthPart As String, dayPart As String
|
||||
Dim dateStr As String
|
||||
|
||||
If Len(s) = 8 Then
|
||||
' YYYYMMDD format
|
||||
yearPart = Left(s, 4)
|
||||
monthPart = Mid(s, 5, 2)
|
||||
dayPart = Right(s, 2)
|
||||
ElseIf Len(s) = 6 Then
|
||||
' YYMMDD format - add 20 prefix
|
||||
yearPart = "20" & Left(s, 2)
|
||||
monthPart = Mid(s, 3, 2)
|
||||
dayPart = Right(s, 2)
|
||||
Else
|
||||
FormatDateInput = inputStr
|
||||
Exit Function
|
||||
End If
|
||||
|
||||
dateStr = yearPart & "-" & monthPart & "-" & dayPart
|
||||
|
||||
If IsDate(dateStr) Then
|
||||
FormatDateInput = dateStr
|
||||
Else
|
||||
FormatDateInput = ""
|
||||
End If
|
||||
Exit Function
|
||||
End If
|
||||
|
||||
Dim yearPart As String, monthPart As String, dayPart As String
|
||||
Dim dateStr As String
|
||||
|
||||
If Len(s) = 8 Then
|
||||
' YYYYMMDD format
|
||||
yearPart = Left(s, 4)
|
||||
monthPart = Mid(s, 5, 2)
|
||||
dayPart = Right(s, 2)
|
||||
ElseIf Len(s) = 6 Then
|
||||
' YYMMDD format - add 20 prefix
|
||||
yearPart = "20" & Left(s, 2)
|
||||
monthPart = Mid(s, 3, 2)
|
||||
dayPart = Right(s, 2)
|
||||
Else
|
||||
FormatDateInput = inputStr
|
||||
|
||||
' Handle non-numeric date strings (e.g. "2026/05", "2026/5/1", "2026-5-1")
|
||||
If IsDate(s) Then
|
||||
Dim d As Date: d = CDate(s)
|
||||
FormatDateInput = Year(d) & "-" & Right("0" & Month(d), 2) & "-" & Right("0" & Day(d), 2)
|
||||
Exit Function
|
||||
End If
|
||||
|
||||
' Build date string and validate
|
||||
dateStr = yearPart & "-" & monthPart & "-" & dayPart
|
||||
|
||||
If IsDate(dateStr) Then
|
||||
FormatDateInput = dateStr
|
||||
Else
|
||||
FormatDateInput = inputStr
|
||||
End If
|
||||
|
||||
' Not a date - return empty string
|
||||
FormatDateInput = ""
|
||||
End Function
|
||||
|
||||
'Check header edit protection
|
||||
|
||||
@@ -19,7 +19,8 @@ Public Const CACHE_T3 As String = "T3"
|
||||
Public Const CACHE_O1 As String = "O1"
|
||||
Public Const CACHE_O2 As String = "O2"
|
||||
Public Const CACHE_O3 As String = "O3"
|
||||
|
||||
Public Const CACHE_M1 As String = "M1"
|
||||
Public Const CACHE_M2 As String = "M2"
|
||||
|
||||
|
||||
Private sheetConfDict As Object
|
||||
@@ -62,7 +63,7 @@ Public Sub RefreshCache(ByVal cacheName As String)
|
||||
Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
|
||||
If cacheName = "M1KukanDCache" Then
|
||||
Set loadedData = LookupM1KukanCache()
|
||||
ElseIf cacheName = "M2" Then
|
||||
ElseIf cacheName = CACHE_M2 Then
|
||||
Set loadedData = LookupM2Cache()
|
||||
ElseIf cacheName = CACHE_O1 Then
|
||||
Set loadedData = LookupO1Cache()
|
||||
@@ -88,12 +89,9 @@ Private Function LookupM1KukanCache()
|
||||
On Error GoTo ErrHandler
|
||||
|
||||
Dim ws As Worksheet
|
||||
On Error Resume Next
|
||||
Set ws = ThisWorkbook.Worksheets("M1")
|
||||
On Error GoTo ErrHandler
|
||||
' ws exists, continue
|
||||
Set ws = ThisWorkbook.Worksheets(CACHE_M1)
|
||||
|
||||
Dim sheetConf As Object: Set sheetConf = sheetConfDict("M1")
|
||||
Dim sheetConf As Object: Set sheetConf = sheetConfDict(CACHE_M1)
|
||||
Dim startRow As Long: startRow = sheetConf("StartRow")
|
||||
Dim lastRow As Long: lastRow = GetLastDataRowInRange(ws)
|
||||
If lastRow < startRow Then
|
||||
@@ -152,12 +150,9 @@ Private Function LookupM2Cache() As Object
|
||||
On Error GoTo ErrHandler
|
||||
|
||||
Dim ws As Worksheet
|
||||
On Error Resume Next
|
||||
Set ws = ThisWorkbook.Worksheets("M2")
|
||||
On Error GoTo ErrHandler
|
||||
' ws exists, continue
|
||||
Set ws = ThisWorkbook.Worksheets(CACHE_M2)
|
||||
|
||||
Dim sheetConf As Object: Set sheetConf = sheetConfDict("M2")
|
||||
Dim sheetConf As Object: Set sheetConf = sheetConfDict(CACHE_M2)
|
||||
Dim startRow As Long: startRow = sheetConf("StartRow")
|
||||
Dim lastRow As Long: lastRow = GetLastDataRowInRange(ws)
|
||||
If lastRow < startRow Then
|
||||
@@ -229,10 +224,7 @@ Private Function LookupO1Cache() As Object
|
||||
On Error GoTo ErrHandler
|
||||
|
||||
Dim ws As Worksheet
|
||||
On Error Resume Next
|
||||
Set ws = ThisWorkbook.Worksheets(CACHE_O1)
|
||||
On Error GoTo ErrHandler
|
||||
' ws exists, continue
|
||||
|
||||
Dim sheetConf As Object: Set sheetConf = sheetConfDict(CACHE_O1)
|
||||
Dim startRow As Long: startRow = sheetConf("StartRow")
|
||||
@@ -289,7 +281,7 @@ End Function
|
||||
|
||||
' ============================================================
|
||||
' Z4 Rosen Cache - nested dict for M1 E/F/H cascade dropdown
|
||||
' Structure: { rosen [F]: { stationFrom [D]: [stationTo E, ...] } }
|
||||
' Structure: { rosen [F]: { station [D]: True } }
|
||||
' ============================================================
|
||||
Private Function LookupZ4RosenCache() As Object
|
||||
Dim resultCache As Object
|
||||
@@ -309,31 +301,25 @@ Private Function LookupZ4RosenCache() As Object
|
||||
End If
|
||||
|
||||
Dim r As Long
|
||||
For r = startRow To lastRow
|
||||
Dim rosen As String: rosen = Trim(ws.Cells(r, 6).Value)
|
||||
Dim stationFrom As String: stationFrom = Trim(ws.Cells(r, 4).Value)
|
||||
Dim stationTo As String: stationTo = Trim(ws.Cells(r, 5).Value)
|
||||
Dim station As String
|
||||
Dim rosen As String
|
||||
Dim innerDict As Object
|
||||
|
||||
If rosen = "" Or stationFrom = "" Then GoTo NextRow3
|
||||
For r = startRow To lastRow
|
||||
rosen = Trim(ws.Cells(r, 6).Value)
|
||||
station = Trim(ws.Cells(r, 4).Value)
|
||||
|
||||
If rosen = "" Or station = "" Then GoTo NextRow3
|
||||
|
||||
If Not resultCache.Exists(rosen) Then
|
||||
Dim innerDict As Object
|
||||
Set innerDict = CreateObject("Scripting.Dictionary")
|
||||
innerDict.CompareMode = vbTextCompare
|
||||
resultCache.Add rosen, innerDict
|
||||
End If
|
||||
|
||||
Set innerDict = resultCache(rosen)
|
||||
If Not innerDict.Exists(stationFrom) Then
|
||||
Dim arr As Object
|
||||
Set arr = CreateObject("Scripting.Dictionary")
|
||||
arr.CompareMode = vbTextCompare
|
||||
innerDict.Add stationFrom, arr
|
||||
End If
|
||||
|
||||
Set arr = innerDict(stationFrom)
|
||||
If stationTo <> "" And Not arr.Exists(stationTo) Then
|
||||
arr.Add stationTo, True
|
||||
If Not innerDict.Exists(station) Then
|
||||
innerDict.Add station, True
|
||||
End If
|
||||
|
||||
NextRow3:
|
||||
@@ -387,7 +373,7 @@ Private Sub RefreshSheetDict()
|
||||
sheetConf("FilterRow") = 6
|
||||
sheetConf("KeyCol") = 3
|
||||
sheetConf("ValueCols") = Array(3, 4, 5, 6, 7, 9, 12)
|
||||
Set sheetConfDict("M1") = sheetConf
|
||||
Set sheetConfDict(CACHE_M1) = sheetConf
|
||||
Debug.Print "RefreshSheetDict M1 ok."
|
||||
|
||||
' M2
|
||||
@@ -403,7 +389,7 @@ Private Sub RefreshSheetDict()
|
||||
sheetConf("HeaderColumns") = Array("C", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R")
|
||||
sheetConf("AlwaysQuote") = False
|
||||
sheetConf("FilterRow") = 7
|
||||
Set sheetConfDict("M2") = sheetConf
|
||||
Set sheetConfDict(CACHE_M2) = sheetConf
|
||||
Debug.Print "RefreshSheetDict M2 ok."
|
||||
|
||||
' Z1
|
||||
@@ -479,7 +465,7 @@ Private Sub RefreshSheetDict()
|
||||
sheetConf("FilterRow") = 6
|
||||
sheetConf("KeyCol") = 3
|
||||
sheetConf("ValueCols") = Array(4)
|
||||
Set sheetConfDict("Z4") = sheetConf
|
||||
Set sheetConfDict(CACHE_Z4) = sheetConf
|
||||
Debug.Print "RefreshSheetDict Z4 ok."
|
||||
|
||||
' T1
|
||||
@@ -517,6 +503,7 @@ Private Sub RefreshSheetDict()
|
||||
sheetConf("FilterRow") = 6
|
||||
sheetConf("KeyCol") = 3
|
||||
sheetConf("ValueCols") = Array(4, 8, 9, 10, 11, 12, 13)
|
||||
sheetConf("ZeroFillCols") = Array("H", "I", "J", "K", "L", "M")
|
||||
Set sheetConfDict(CACHE_T2) = sheetConf
|
||||
Debug.Print "RefreshSheetDict T2 ok."
|
||||
|
||||
@@ -695,15 +682,15 @@ Public Sub RefreshMasterCache()
|
||||
End Sub
|
||||
|
||||
Public Sub RefreshKukanCache(ByVal sheetName As String)
|
||||
If sheetName = "M1" Then
|
||||
Call RefreshCache("M1")
|
||||
If sheetName = CACHE_M1 Then
|
||||
Call RefreshCache(CACHE_M1)
|
||||
Call RefreshCache("M1KukanDCache")
|
||||
Call RefreshCache(CACHE_Z4ROSEN)
|
||||
Call WriteCachesSheet("M1")
|
||||
Call WriteCachesSheet(CACHE_M1)
|
||||
End If
|
||||
If sheetName = "M2" Then
|
||||
Call RefreshCache("M2")
|
||||
Call WriteCachesSheet("M2")
|
||||
If sheetName = CACHE_M2 Then
|
||||
Call RefreshCache(CACHE_M2)
|
||||
Call WriteCachesSheet(CACHE_M2)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
@@ -729,7 +716,7 @@ Public Sub WriteCachesSheet(ByVal cacheName As String)
|
||||
Case CACHE_T3: colLetter = "G"
|
||||
Case CACHE_O2: colLetter = "H"
|
||||
Case CACHE_O3: colLetter = "I"
|
||||
Case "M1": colLetter = "M"
|
||||
Case CACHE_M1: colLetter = "M"
|
||||
Case Else: Exit Sub
|
||||
End Select
|
||||
|
||||
|
||||
@@ -264,18 +264,17 @@ Public Sub BuildZ4StationToDropdown(ws As Worksheet, ByVal columnLetter As Strin
|
||||
If Not z4RosenCache.Exists(rosen) Then Exit Sub
|
||||
|
||||
Dim stationFromDict As Object: Set stationFromDict = z4RosenCache(rosen)
|
||||
If Not stationFromDict.Exists(stationFrom) Then Exit Sub
|
||||
|
||||
Dim stationToDict As Object: Set stationToDict = stationFromDict(stationFrom)
|
||||
Dim dropdownList As String: dropdownList = ""
|
||||
Dim stationTo As Variant
|
||||
For Each stationTo In stationToDict.Keys
|
||||
If dropdownList = "" Then
|
||||
dropdownList = stationTo
|
||||
Else
|
||||
dropdownList = dropdownList & "," & stationTo
|
||||
Dim s As Variant
|
||||
For Each s In stationFromDict.Keys
|
||||
If s <> stationFrom Then
|
||||
If dropdownList = "" Then
|
||||
dropdownList = s
|
||||
Else
|
||||
dropdownList = dropdownList & "," & s
|
||||
End If
|
||||
End If
|
||||
Next stationTo
|
||||
Next s
|
||||
|
||||
If dropdownList = "" Then Exit Sub
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Attribute VB_Name = "Common_Shape"
|
||||
Option Explicit
|
||||
|
||||
' ================= 通用排版引擎(仅调整位置) =================
|
||||
' ================= Common Layout Engine (position only) =================
|
||||
|
||||
Public Sub AlignIconsByCenter(sheetName As String, anchorAddr As String, _
|
||||
iconArr As Variant, gapPt As Double)
|
||||
@@ -10,16 +10,14 @@ Public Sub AlignIconsByCenter(sheetName As String, anchorAddr As String, _
|
||||
Dim shp As Shape
|
||||
Dim i As Long
|
||||
Dim shapeCount As Long
|
||||
|
||||
On Error Resume Next
|
||||
On Error GoTo ErrHandler
|
||||
Set ws = ThisWorkbook.Worksheets(sheetName)
|
||||
On Error GoTo 0
|
||||
If ws Is Nothing Then Exit Sub
|
||||
' ws exists, continue
|
||||
|
||||
Set anchor = ws.Range(anchorAddr)
|
||||
shapeCount = UBound(iconArr) - LBound(iconArr) + 1
|
||||
|
||||
' 第一个图标左边对齐B3左边
|
||||
' First icon left-aligns to B3 left edge
|
||||
Dim curX As Double: curX = anchor.Left
|
||||
Dim prevX As Double: prevX = 0
|
||||
Dim cy As Double: cy = anchor.Top + anchor.Height / 2
|
||||
@@ -39,12 +37,17 @@ Public Sub AlignIconsByCenter(sheetName As String, anchorAddr As String, _
|
||||
curX = curX + shp.Width + gapPt
|
||||
Next i
|
||||
Application.ScreenUpdating = True
|
||||
Exit Sub
|
||||
|
||||
ErrHandler:
|
||||
MsgBox "Error " & Err.Number & ": " & Err.Description, vbCritical, "AlignIconsByCenter"
|
||||
Application.ScreenUpdating = True
|
||||
End Sub
|
||||
|
||||
' ================= 你的专属调用入口 =================
|
||||
' ================= Entry point =================
|
||||
Sub RunAlignForMySheet()
|
||||
AlignIconsByCenter _
|
||||
sheetName:="M1", _
|
||||
sheetName:=CACHE_M1, _
|
||||
anchorAddr:="B3", _
|
||||
iconArr:=Array("input", "check", "output", "sort", "filter", "fit", "load"), _
|
||||
gapPt:=10
|
||||
|
||||
@@ -157,14 +157,21 @@ Private Sub Worksheet_Change(ByVal Target As Range)
|
||||
idx = GetIdx(Target.Column, DATE_COLS)
|
||||
If idx >= 0 Then
|
||||
Dim cellDate As Range
|
||||
Dim formattedDate As String
|
||||
For Each cellDate In Target
|
||||
If Trim(cellDate.Value) <> "" Then
|
||||
Dim formattedDate As String: formattedDate = FormatDateInput(cellDate.Value)
|
||||
cellDate.Value = FormatDateInput(formattedDate)
|
||||
If cellDate.Column = 5 Then
|
||||
Dim fCell As Range: Set fCell = Me.Cells(cellDate.Row, 6)
|
||||
If Trim(fCell.Value) = "" Then
|
||||
fCell.Value = formattedDate
|
||||
formattedDate = FormatDateInput(cellDate.Value)
|
||||
If formattedDate = "" Then
|
||||
' Invalid date input - clear cell and show message
|
||||
cellDate.Value = ""
|
||||
MsgBox "Please enter a valid date (YYYY-MM-DD or YYYY/MM/DD)", vbExclamation, "Invalid Date"
|
||||
Else
|
||||
cellDate.Value = formattedDate
|
||||
If cellDate.Column = 5 Then
|
||||
Dim fCell As Range: Set fCell = Me.Cells(cellDate.Row, 6)
|
||||
If Trim(fCell.Value) = "" Then
|
||||
fCell.Value = formattedDate
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
@@ -672,7 +679,7 @@ Private Function FindKukanCodeByStation(ByVal rowNum As Long, ByVal transportCol
|
||||
Dim code As Variant
|
||||
For Each code In m1Cache.Keys
|
||||
Dim vals As Variant: vals = m1Cache(code)
|
||||
' vals(1) = D列, vals(3) = F列, vals(4) = G列
|
||||
' vals(1) = D col, vals(3) = F col, vals(4) = G col
|
||||
If vals(1) = transportKbn And vals(3) = stationFrom And vals(4) = stationTo Then
|
||||
FindKukanCodeByStation = code
|
||||
Exit Function
|
||||
@@ -791,15 +798,18 @@ Public Sub Validate(ws As Worksheet, ByVal rowNum As Long, ByVal lastDataRow As
|
||||
End If
|
||||
Next col
|
||||
|
||||
' validate date
|
||||
' validate date
|
||||
Dim colIndex As Variant
|
||||
For Each colIndex In DATE_COLS()
|
||||
Dim cellDate As String: cellDate = Trim(Me.Cells(rowNum, colIndex).Value)
|
||||
If cellDate <> "" And Not IsDate(cellDate) Then
|
||||
Dim letter As String: letter = Split(Me.Cells(1, colIndex).Address, "$")(1)
|
||||
Me.Cells(rowNum, errorCol).Value = GetErrorMsg("E001", letter & rowNum)
|
||||
Me.Range(letter & rowNum).Interior.Color = RGB(255, 0, 0)
|
||||
Exit Sub
|
||||
If cellDate <> "" Then
|
||||
' Require full YYYY-MM-DD format (output of FormatDateInput)
|
||||
If Len(cellDate) <> 10 Or Mid(cellDate, 5, 1) <> "-" Or Mid(cellDate, 8, 1) <> "-" Then
|
||||
Dim letter As String: letter = Split(Me.Cells(1, colIndex).Address, "$")(1)
|
||||
Me.Cells(rowNum, errorCol).Value = GetErrorMsg("E001", letter & rowNum)
|
||||
Me.Range(letter & rowNum).Interior.Color = RGB(255, 0, 0)
|
||||
Exit Sub
|
||||
End If
|
||||
End If
|
||||
Next colIndex
|
||||
|
||||
|
||||
@@ -51,20 +51,19 @@ Private Sub Worksheet_Change(ByVal Target As Range)
|
||||
|
||||
If z4Rosen.Exists(kikanName) Then
|
||||
Call BuildZ4StationFromDropdown(Me, "F", cellD.Row, kikanName)
|
||||
Dim fromStations As Object: Set fromStations = z4Rosen(kikanName)
|
||||
Dim stations As Object: Set stations = z4Rosen(kikanName)
|
||||
Dim fromCell As Range: Set fromCell = Me.Cells(cellD.Row, 6)
|
||||
Dim fromStation As String: fromStation = Trim(fromCell.Value)
|
||||
If Not fromStations.Exists(fromStation) Or fromStation = "" Then
|
||||
If Not stations.Exists(fromStation) Or fromStation = "" Then
|
||||
fromCell.ClearContents
|
||||
Me.Cells(cellD.Row, 7).ClearContents
|
||||
Me.Cells(cellD.Row, 7).Validation.Delete
|
||||
Else
|
||||
Call BuildZ4StationToDropdown(Me, "G", cellD.Row, kikanName, fromStation)
|
||||
Dim toStations As Object: Set toStations = fromStations(fromStation)
|
||||
Dim toCell As Range: Set toCell = Me.Cells(cellD.Row, 7)
|
||||
Dim toStation As String: toStation = Trim(toCell.Value)
|
||||
|
||||
If Not toStations.Exists(fromStation) Or toStation = "" Then
|
||||
|
||||
If Not stations.Exists(toStation) Or toStation = "" Then
|
||||
toCell.ClearContents
|
||||
End If
|
||||
End If
|
||||
@@ -264,9 +263,9 @@ Private Sub ValidateWarn(ws As Worksheet, ByVal lastDataRow As Long)
|
||||
|
||||
' Get M2 sheet kukan code list directly
|
||||
Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
|
||||
Dim m2SheetConf As Object: Set m2SheetConf = sheetConfDict("M2")
|
||||
Dim m2SheetConf As Object: Set m2SheetConf = sheetConfDict(CACHE_M2)
|
||||
Dim m2StartRow As Long: m2StartRow = m2SheetConf("StartRow")
|
||||
Dim wsM2 As Worksheet: Set wsM2 = ThisWorkbook.Worksheets("M2")
|
||||
Dim wsM2 As Worksheet: Set wsM2 = ThisWorkbook.Worksheets(CACHE_M2)
|
||||
Dim lastRowM2 As Long: lastRowM2 = GetLastDataRowInRange(wsM2)
|
||||
If lastRowM2 < m2StartRow Then
|
||||
exitMsg = "M2 sheet has no data"
|
||||
|
||||
@@ -23,6 +23,7 @@ Private Sub Worksheet_Change(ByVal Target As Range)
|
||||
If Trim(cell.Value) = "" Then
|
||||
Call ClearDataRow(Me, cell.Row)
|
||||
Else
|
||||
Call FillZeroIfEmpty(Me, cell.Row)
|
||||
Call BuildDisplayDropdown(Me, cell.Row)
|
||||
End If
|
||||
Next
|
||||
@@ -47,6 +48,20 @@ Finally:
|
||||
Application.EnableEvents = True
|
||||
End Sub
|
||||
|
||||
' Fill H~M with "0" if they are empty when C column (kubun/category) is edited
|
||||
Private Sub FillZeroIfEmpty(ws As Worksheet, ByVal rowNum As Long)
|
||||
Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
|
||||
Dim sheetConf As Object: Set sheetConf = sheetConfDict(ws.CodeName)
|
||||
|
||||
Dim zeroFillCols As Variant: zeroFillCols = sheetConf("ZeroFillCols")
|
||||
Dim colLetter As Variant
|
||||
For Each colLetter In zeroFillCols
|
||||
If Trim(ws.Range(colLetter & rowNum).Value) = "" Then
|
||||
ws.Range(colLetter & rowNum).Value = "0"
|
||||
End If
|
||||
Next colLetter
|
||||
End Sub
|
||||
|
||||
' Prevent insert/delete row in header area
|
||||
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
|
||||
Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
|
||||
|
||||
Reference in New Issue
Block a user