Reuse the live price stream for the product catalog and physical delivery list.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,8 +3,10 @@
|
||||
"1": "ref_utils",
|
||||
"2": "index.vue",
|
||||
"3": "productPrice.ts",
|
||||
"4": "useNewPhysicalRequestPage.ts",
|
||||
"5": "api/products.ts",
|
||||
"6": "priceSocket.ts",
|
||||
"7": "priceSocketState.ts",
|
||||
"8": "useProductsPageData.ts",
|
||||
"9": "AuthPriceStream"
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"0": "ffa7d5a5ae1f1cb0", "1": "67d1701e4c6cea74", "2": "517e2bd803b5bf98", "3": "18bc618fd6f328bb", "5": "8d51306eb7d0daf2", "6": "cd6583f8b1bf3877", "8": "004ed482633014da", "9": "08b88f1fc8c91c56"}
|
||||
{"0": "d7734412cf0800ce", "1": "67d1701e4c6cea74", "2": "a1988eda2ebb6afe", "3": "18bc618fd6f328bb", "4": "b16e1aea09ac331f", "5": "8d51306eb7d0daf2", "6": "fe2bcdb916bbc9f9", "7": "ac69b3434e72782c", "8": "004ed482633014da", "9": "08b88f1fc8c91c56"}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"0": "useTvMonitorPage",
|
||||
"1": "ref_utils",
|
||||
"2": "index.vue",
|
||||
"3": "productPrice.ts",
|
||||
"5": "api/products.ts",
|
||||
"6": "priceSocket.ts",
|
||||
"8": "useProductsPageData.ts",
|
||||
"9": "AuthPriceStream"
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
# Graph Report - ghatreh_user (2026-09-28)
|
||||
|
||||
## Corpus Check
|
||||
- 598 files · ~506,836 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
- Unclassified: 51 file(s) not represented in the graph (top: .less 25, .eot 6, .ttf 6)
|
||||
|
||||
## Summary
|
||||
- 198 nodes · 409 edges · 8 communities (7 shown, 1 thin omitted)
|
||||
- Extraction: 93% EXTRACTED · 7% INFERRED · 0% AMBIGUOUS · INFERRED: 28 edges (avg confidence: 0.85)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Graph Freshness
|
||||
- Built from commit: `9cb09796`
|
||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||
- Run `graphify update .` after code changes (no API cost).
|
||||
|
||||
## Community Hubs (Navigation)
|
||||
- useTvMonitorPage
|
||||
- ref_utils
|
||||
- index.vue
|
||||
- productPrice.ts
|
||||
- api/products.ts
|
||||
- priceSocket.ts
|
||||
- useProductsPageData.ts
|
||||
- AuthPriceStream
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `useTvMonitorPage()` - 25 edges
|
||||
2. `connect()` - 15 edges
|
||||
3. `getProductBaseBuyPrice()` - 10 edges
|
||||
4. `touchStreamActivity()` - 9 edges
|
||||
5. `bindStreamEvents()` - 9 edges
|
||||
6. `forceReconnect()` - 9 edges
|
||||
7. `runFallbackPoll()` - 8 edges
|
||||
8. `maybeShowNetworkAlert()` - 8 edges
|
||||
9. `disconnect()` - 8 edges
|
||||
10. `applyProductsList()` - 8 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `connect()` --calls--> `AuthPriceStream` [EXTRACTED]
|
||||
src/utils/priceSocket.ts → src/utils/priceSocket.ts _Bridges community 9 → community 6_
|
||||
- `connect()` --calls--> `touchStreamActivity()` [EXTRACTED]
|
||||
src/utils/priceSocket.ts → src/utils/priceSocket.ts _Bridges community 1 → community 6_
|
||||
|
||||
## Import Cycles
|
||||
- None detected.
|
||||
|
||||
## Communities (8 total, 1 thin omitted)
|
||||
|
||||
### Community 0 - "useTvMonitorPage"
|
||||
Cohesion: 0.10
|
||||
Nodes (30): ref_api, ref_assets, ref_moment, ref_moment_jalaali, ref_vueuse_core, bankCoinRank(), floorTvToman(), formatTvPrice() (+22 more)
|
||||
|
||||
### Community 1 - "ref_utils"
|
||||
Cohesion: 0.23
|
||||
Nodes (15): ref_composables, ref_store, ref_utils, applyAppNotificationFromStream(), applyLastFromStream(), applySettingsFromStream(), applyUnreadCountFromStreamPayload(), bindStreamEvents() (+7 more)
|
||||
|
||||
### Community 2 - "index.vue"
|
||||
Cohesion: 0.10
|
||||
Nodes (23): ref_components, ref_views, ref_vue, priceSocketConnected, priceStreamConnectingSince, priceStreamLifecycle, priceStreamList, priceStreamProducts (+15 more)
|
||||
|
||||
### Community 3 - "productPrice.ts"
|
||||
Cohesion: 0.20
|
||||
Nodes (24): applyPriceOffsetPercent(), buyCashFee(), cashFeeOptions(), getColleagueSourcedUnitPrice(), getProductBaseBuyPrice(), getProductBaseSellPrice(), getProductBuyPrice(), getProductSellPrice() (+16 more)
|
||||
|
||||
### Community 5 - "api/products.ts"
|
||||
Cohesion: 0.15
|
||||
Nodes (5): ref_models, TvServerTime, CountPInventory, PInventory, Product
|
||||
|
||||
### Community 6 - "priceSocket.ts"
|
||||
Cohesion: 0.11
|
||||
Nodes (41): ref_ant_design_vue, bindBrowserNetworkListeners(), clearConnectingLifecycle(), clearFallbackPollTimer(), clearPriceNetworkAlert(), clearReconnectTimer(), connect(), disconnect() (+33 more)
|
||||
|
||||
### Community 8 - "useProductsPageData.ts"
|
||||
Cohesion: 0.12
|
||||
Nodes (31): applyProductsList(), applyProductsListFromSocket(), applySocketProductList(), changeProductsTab(), flagOff(), flagOn(), initialized, initProductsPageData() (+23 more)
|
||||
|
||||
## Knowledge Gaps
|
||||
- **20 isolated node(s):** `Product`, `PInventory`, `CountPInventory`, `priceSocketConnected`, `priceWssEnabled` (+15 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components. (Counts symbols only; 43 node(s) total have ≤1 connection when file, concept and rationale nodes are included.)
|
||||
- **1 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `AuthPriceStream` connect `AuthPriceStream` to `priceSocket.ts`?**
|
||||
_High betweenness centrality (0.035) - this node is a cross-community bridge._
|
||||
- **Why does `runFallbackPoll()` connect `priceSocket.ts` to `ref_utils`, `index.vue`?**
|
||||
_High betweenness centrality (0.016) - this node is a cross-community bridge._
|
||||
- **Are the 14 inferred relationships involving `useTvMonitorPage()` (e.g. with `isBankCoin()` and `isGoldBar()`) actually correct?**
|
||||
_`useTvMonitorPage()` has 14 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **What connects `Product`, `PInventory`, `CountPInventory` to the rest of the system?**
|
||||
_20 weakly-connected nodes found - possible documentation gaps or missing edges._
|
||||
- **Should `useTvMonitorPage` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.09982174688057041 - nodes in this community are weakly interconnected._
|
||||
- **Should `index.vue` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.10153846153846154 - nodes in this community are weakly interconnected._
|
||||
- **Should `priceSocket.ts` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.10638297872340426 - nodes in this community are weakly interconnected._
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,17 @@
|
||||
# Graph Report - ghatreh_user (2026-09-28)
|
||||
# Graph Report - ghatreh_user (2026-09-29)
|
||||
|
||||
## Corpus Check
|
||||
- 598 files · ~506,836 words
|
||||
- 598 files · ~506,875 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
- Unclassified: 51 file(s) not represented in the graph (top: .less 25, .eot 6, .ttf 6)
|
||||
|
||||
## Summary
|
||||
- 198 nodes · 409 edges · 8 communities (7 shown, 1 thin omitted)
|
||||
- Extraction: 93% EXTRACTED · 7% INFERRED · 0% AMBIGUOUS · INFERRED: 28 edges (avg confidence: 0.85)
|
||||
- 208 nodes · 426 edges · 10 communities (9 shown, 1 thin omitted)
|
||||
- Extraction: 92% EXTRACTED · 8% INFERRED · 0% AMBIGUOUS · INFERRED: 33 edges (avg confidence: 0.85)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Graph Freshness
|
||||
- Built from commit: `9cb09796`
|
||||
- Built from commit: `da68f0a5`
|
||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||
- Run `graphify update .` after code changes (no API cost).
|
||||
|
||||
@@ -20,8 +20,10 @@
|
||||
- ref_utils
|
||||
- index.vue
|
||||
- productPrice.ts
|
||||
- useNewPhysicalRequestPage.ts
|
||||
- api/products.ts
|
||||
- priceSocket.ts
|
||||
- priceSocketState.ts
|
||||
- useProductsPageData.ts
|
||||
- AuthPriceStream
|
||||
|
||||
@@ -29,72 +31,80 @@
|
||||
1. `useTvMonitorPage()` - 25 edges
|
||||
2. `connect()` - 15 edges
|
||||
3. `getProductBaseBuyPrice()` - 10 edges
|
||||
4. `touchStreamActivity()` - 9 edges
|
||||
5. `bindStreamEvents()` - 9 edges
|
||||
4. `bindStreamEvents()` - 9 edges
|
||||
5. `touchStreamActivity()` - 9 edges
|
||||
6. `forceReconnect()` - 9 edges
|
||||
7. `runFallbackPoll()` - 8 edges
|
||||
8. `maybeShowNetworkAlert()` - 8 edges
|
||||
9. `disconnect()` - 8 edges
|
||||
10. `applyProductsList()` - 8 edges
|
||||
7. `useNewPhysicalRequestPage()` - 8 edges
|
||||
8. `applyProductsList()` - 8 edges
|
||||
9. `applySocketProductList()` - 8 edges
|
||||
10. `disconnect()` - 8 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `connect()` --calls--> `AuthPriceStream` [EXTRACTED]
|
||||
src/utils/priceSocket.ts → src/utils/priceSocket.ts _Bridges community 9 → community 6_
|
||||
- `connect()` --calls--> `touchStreamActivity()` [EXTRACTED]
|
||||
- `connect()` --calls--> `bindStreamEvents()` [EXTRACTED]
|
||||
src/utils/priceSocket.ts → src/utils/priceSocket.ts _Bridges community 1 → community 6_
|
||||
|
||||
## Import Cycles
|
||||
- None detected.
|
||||
|
||||
## Communities (8 total, 1 thin omitted)
|
||||
## Communities (10 total, 1 thin omitted)
|
||||
|
||||
### Community 0 - "useTvMonitorPage"
|
||||
Cohesion: 0.10
|
||||
Nodes (30): ref_api, ref_assets, ref_moment, ref_moment_jalaali, ref_vueuse_core, bankCoinRank(), floorTvToman(), formatTvPrice() (+22 more)
|
||||
Nodes (29): ref_assets, ref_moment, ref_moment_jalaali, ref_vueuse_core, bankCoinRank(), floorTvToman(), formatTvPrice(), isBankCoin() (+21 more)
|
||||
|
||||
### Community 1 - "ref_utils"
|
||||
Cohesion: 0.23
|
||||
Nodes (15): ref_composables, ref_store, ref_utils, applyAppNotificationFromStream(), applyLastFromStream(), applySettingsFromStream(), applyUnreadCountFromStreamPayload(), bindStreamEvents() (+7 more)
|
||||
|
||||
### Community 2 - "index.vue"
|
||||
Cohesion: 0.10
|
||||
Nodes (23): ref_components, ref_views, ref_vue, priceSocketConnected, priceStreamConnectingSince, priceStreamLifecycle, priceStreamList, priceStreamProducts (+15 more)
|
||||
Cohesion: 0.19
|
||||
Nodes (15): ref_components, ref_views, coinColumns, extraTickerLoop, loopNews(), loopTicker(), marqueeCopies(), newsDuration() (+7 more)
|
||||
|
||||
### Community 3 - "productPrice.ts"
|
||||
Cohesion: 0.20
|
||||
Nodes (24): applyPriceOffsetPercent(), buyCashFee(), cashFeeOptions(), getColleagueSourcedUnitPrice(), getProductBaseBuyPrice(), getProductBaseSellPrice(), getProductBuyPrice(), getProductSellPrice() (+16 more)
|
||||
|
||||
### Community 4 - "useNewPhysicalRequestPage.ts"
|
||||
Cohesion: 0.12
|
||||
Nodes (13): ref_ant_design_vue, ref_api, ref_lodash, ref_router, NEW_PHYSICAL_REQUEST_KEY, NewPhysicalRequestContext, useNewPhysicalRequestPage(), getAddress() (+5 more)
|
||||
|
||||
### Community 5 - "api/products.ts"
|
||||
Cohesion: 0.15
|
||||
Nodes (5): ref_models, TvServerTime, CountPInventory, PInventory, Product
|
||||
|
||||
### Community 6 - "priceSocket.ts"
|
||||
Cohesion: 0.11
|
||||
Nodes (41): ref_ant_design_vue, bindBrowserNetworkListeners(), clearConnectingLifecycle(), clearFallbackPollTimer(), clearPriceNetworkAlert(), clearReconnectTimer(), connect(), disconnect() (+33 more)
|
||||
Cohesion: 0.14
|
||||
Nodes (40): bindBrowserNetworkListeners(), clearConnectingLifecycle(), clearFallbackPollTimer(), clearPriceNetworkAlert(), clearReconnectTimer(), connect(), disconnect(), disconnectSourceOnly() (+32 more)
|
||||
|
||||
### Community 7 - "priceSocketState.ts"
|
||||
Cohesion: 0.20
|
||||
Nodes (8): ref_vue, priceSocketConnected, priceStreamConnectingSince, priceStreamLifecycle, priceStreamList, priceStreamProducts, priceStreamServerUnix, priceWssEnabled
|
||||
|
||||
### Community 8 - "useProductsPageData.ts"
|
||||
Cohesion: 0.12
|
||||
Nodes (31): applyProductsList(), applyProductsListFromSocket(), applySocketProductList(), changeProductsTab(), flagOff(), flagOn(), initialized, initProductsPageData() (+23 more)
|
||||
|
||||
## Knowledge Gaps
|
||||
- **20 isolated node(s):** `Product`, `PInventory`, `CountPInventory`, `priceSocketConnected`, `priceWssEnabled` (+15 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components. (Counts symbols only; 43 node(s) total have ≤1 connection when file, concept and rationale nodes are included.)
|
||||
- **22 isolated node(s):** `NewPhysicalRequestContext`, `NEW_PHYSICAL_REQUEST_KEY`, `initialized`, `productsActiveKey`, `productsTypeItems` (+17 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components. (Counts symbols only; 45 node(s) total have ≤1 connection when file, concept and rationale nodes are included.)
|
||||
- **1 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `AuthPriceStream` connect `AuthPriceStream` to `priceSocket.ts`?**
|
||||
_High betweenness centrality (0.035) - this node is a cross-community bridge._
|
||||
- **Why does `runFallbackPoll()` connect `priceSocket.ts` to `ref_utils`, `index.vue`?**
|
||||
_High betweenness centrality (0.016) - this node is a cross-community bridge._
|
||||
_High betweenness centrality (0.033) - this node is a cross-community bridge._
|
||||
- **Are the 14 inferred relationships involving `useTvMonitorPage()` (e.g. with `isBankCoin()` and `isGoldBar()`) actually correct?**
|
||||
_`useTvMonitorPage()` has 14 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **What connects `Product`, `PInventory`, `CountPInventory` to the rest of the system?**
|
||||
_20 weakly-connected nodes found - possible documentation gaps or missing edges._
|
||||
- **What connects `NewPhysicalRequestContext`, `NEW_PHYSICAL_REQUEST_KEY`, `initialized` to the rest of the system?**
|
||||
_22 weakly-connected nodes found - possible documentation gaps or missing edges._
|
||||
- **Should `useTvMonitorPage` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.09982174688057041 - nodes in this community are weakly interconnected._
|
||||
- **Should `index.vue` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.10153846153846154 - nodes in this community are weakly interconnected._
|
||||
_Cohesion score 0.10416666666666667 - nodes in this community are weakly interconnected._
|
||||
- **Should `useNewPhysicalRequestPage.ts` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.12418300653594772 - nodes in this community are weakly interconnected._
|
||||
- **Should `priceSocket.ts` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.10638297872340426 - nodes in this community are weakly interconnected._
|
||||
_Cohesion score 0.1378048780487805 - nodes in this community are weakly interconnected._
|
||||
- **Should `useProductsPageData.ts` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.125 - nodes in this community are weakly interconnected._
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+627
-287
File diff suppressed because it is too large
Load Diff
+158
-158
@@ -18,8 +18,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"components.d.ts": {
|
||||
"mtime": 1789408875.7319229,
|
||||
"seen": 1790532739.4895563,
|
||||
"mtime": 1790615126.894407,
|
||||
"seen": 1790700630.5518231,
|
||||
"ast_hash": "f35eed197a26e44719ef4593b949eb58",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -180,8 +180,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/api/products.ts": {
|
||||
"mtime": 1790601117.1185765,
|
||||
"seen": 1790606091.2974627,
|
||||
"mtime": 1790675167.3287976,
|
||||
"seen": 1790700630.5518472,
|
||||
"ast_hash": "0330dcba5733f10629df4f8f24abd73d",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -204,14 +204,14 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/api/wallet.ts": {
|
||||
"mtime": 1790581289.7798402,
|
||||
"seen": 1790592151.6513388,
|
||||
"mtime": 1790675167.356649,
|
||||
"seen": 1790700630.5518503,
|
||||
"ast_hash": "78c93a3a9055ceefc7b0a2c6883d4341",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/app/authBoot.ts": {
|
||||
"mtime": 1790581289.7716439,
|
||||
"seen": 1790592151.6513402,
|
||||
"mtime": 1790675167.3544807,
|
||||
"seen": 1790700630.551851,
|
||||
"ast_hash": "5143360a44d1a3675e352bd13580133b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -222,8 +222,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/app/createApp.ts": {
|
||||
"mtime": 1790581289.7476532,
|
||||
"seen": 1790592151.6513422,
|
||||
"mtime": 1790675167.3417244,
|
||||
"seen": 1790700630.5518525,
|
||||
"ast_hash": "2170b02775f908ea986af21e3ead814e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -1578,8 +1578,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/components/BasicPacks/BasicButton.vue": {
|
||||
"mtime": 1790581289.7722647,
|
||||
"seen": 1790592151.6515193,
|
||||
"mtime": 1790675167.3545702,
|
||||
"seen": 1790700630.5520358,
|
||||
"ast_hash": "c46f62acd13fb0ca2e4d055910fa4969",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -1728,8 +1728,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/components/SupportMessengerBrandIcon.vue": {
|
||||
"mtime": 1790581289.7035408,
|
||||
"seen": 1790592151.65154,
|
||||
"mtime": 1790675167.3270626,
|
||||
"seen": 1790700630.5520556,
|
||||
"ast_hash": "6b0d86e46c3df17689b545171b89b784",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -1818,8 +1818,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/composables/useWalletAssets.ts": {
|
||||
"mtime": 1790581289.7169514,
|
||||
"seen": 1790592151.651552,
|
||||
"mtime": 1790675167.3320017,
|
||||
"seen": 1790700630.5520675,
|
||||
"ast_hash": "80ec09208dfe3ded4e7e34c15db05882",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -1872,20 +1872,20 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/layouts/AppLayoutShell.vue": {
|
||||
"mtime": 1790581289.775759,
|
||||
"seen": 1790592151.6515596,
|
||||
"mtime": 1790675167.3555534,
|
||||
"seen": 1790700630.5520747,
|
||||
"ast_hash": "7edd95777060c51491d915efbe82ee0a",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/layouts/components/DesktopPageFrame.vue": {
|
||||
"mtime": 1790581289.772935,
|
||||
"seen": 1790592151.6515605,
|
||||
"mtime": 1790675167.354983,
|
||||
"seen": 1790700630.5520756,
|
||||
"ast_hash": "9435d3eb35c7590f51e7c7460770212c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/layouts/components/DesktopPageTopbar.vue": {
|
||||
"mtime": 1790581289.7320335,
|
||||
"seen": 1790592151.6515613,
|
||||
"mtime": 1790675167.3363695,
|
||||
"seen": 1790700630.5520763,
|
||||
"ast_hash": "e104470a0d3cbfa151f83223550e406d",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -1896,14 +1896,14 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/layouts/components/ResponsiveViewPair.vue": {
|
||||
"mtime": 1790581289.780348,
|
||||
"seen": 1790592151.6515627,
|
||||
"mtime": 1790675167.3562129,
|
||||
"seen": 1790700630.5520775,
|
||||
"ast_hash": "c92fdcfe9260844a5ee46c58ef08b644",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/layouts/composables/useAppLayout.ts": {
|
||||
"mtime": 1790581289.7644093,
|
||||
"seen": 1790592151.6515634,
|
||||
"mtime": 1790675167.3511508,
|
||||
"seen": 1790700630.5520782,
|
||||
"ast_hash": "16578294b760d8b7230c7db348bb8678",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -1920,32 +1920,32 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/layouts/composables/useResponsiveLayout.ts": {
|
||||
"mtime": 1790581289.7767413,
|
||||
"seen": 1790592151.651566,
|
||||
"mtime": 1790675167.3557105,
|
||||
"seen": 1790700630.5520809,
|
||||
"ast_hash": "a2d706cfc025a4ad30d17b1a1b9753cc",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/layouts/config/navigation.ts": {
|
||||
"mtime": 1790581289.7630057,
|
||||
"seen": 1790592151.6515667,
|
||||
"mtime": 1790675167.3507586,
|
||||
"seen": 1790700630.5520813,
|
||||
"ast_hash": "545dee96d9a4b8a43cb8c5275ea6b715",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/layouts/constants.ts": {
|
||||
"mtime": 1790581289.7804513,
|
||||
"seen": 1790592151.6515675,
|
||||
"mtime": 1790675167.3561485,
|
||||
"seen": 1790700630.552082,
|
||||
"ast_hash": "fc26385df5a8777e06af9c045c0d1bb3",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/layouts/desktop/DesktopAppLayout.vue": {
|
||||
"mtime": 1790581289.7193491,
|
||||
"seen": 1790592151.6515682,
|
||||
"mtime": 1790675167.3331728,
|
||||
"seen": 1790700630.5520828,
|
||||
"ast_hash": "0761a7b05d06ed2eeee10ac8589ac7e7",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/layouts/desktop/DesktopNavItem.vue": {
|
||||
"mtime": 1790581289.7648094,
|
||||
"seen": 1790592151.6515691,
|
||||
"mtime": 1790675167.3521643,
|
||||
"seen": 1790700630.5520835,
|
||||
"ast_hash": "7081bfee87412acc4e72064ec84ad573",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -1962,8 +1962,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/layouts/mobile/MobileBottomNav.vue": {
|
||||
"mtime": 1790581289.7444942,
|
||||
"seen": 1790592151.6515715,
|
||||
"mtime": 1790675167.3397605,
|
||||
"seen": 1790700630.552086,
|
||||
"ast_hash": "5d5f76f8189548a41cdb3208ad5bb513",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -1974,8 +1974,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/layouts/types.ts": {
|
||||
"mtime": 1790581289.756836,
|
||||
"seen": 1790592151.651573,
|
||||
"mtime": 1790675167.3492832,
|
||||
"seen": 1790700630.5520875,
|
||||
"ast_hash": "517dba1e664ab5b9ee856e77c4325b3b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2106,8 +2106,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/models/walletAssets.ts": {
|
||||
"mtime": 1790581289.7039738,
|
||||
"seen": 1790592151.6515915,
|
||||
"mtime": 1790675167.327241,
|
||||
"seen": 1790700630.5521047,
|
||||
"ast_hash": "49c824cc0b624dc38f934edb019f712f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2142,8 +2142,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/modules/version/VersionUpdateModal.vue": {
|
||||
"mtime": 1790581289.7192545,
|
||||
"seen": 1790592151.651596,
|
||||
"mtime": 1790675167.3326786,
|
||||
"seen": 1790700630.5521092,
|
||||
"ast_hash": "1530423bd93ce29354df7c5732a4d9ee",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2154,8 +2154,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/store/cartStore.ts": {
|
||||
"mtime": 1790581289.765109,
|
||||
"seen": 1790592151.6515977,
|
||||
"mtime": 1790675167.3524942,
|
||||
"seen": 1790700630.552111,
|
||||
"ast_hash": "92732c083a228a7245f248418c256ea4",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2340,8 +2340,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/utils/productStreamBridge.ts": {
|
||||
"mtime": 1790581289.7799215,
|
||||
"seen": 1790592151.6516228,
|
||||
"mtime": 1790675167.356957,
|
||||
"seen": 1790700630.5521352,
|
||||
"ast_hash": "689a3db557fa4677e227087f229f1ee6",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2418,8 +2418,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/utils/useDraggableFloatingButton.ts": {
|
||||
"mtime": 1790581289.757719,
|
||||
"seen": 1790592151.6516328,
|
||||
"mtime": 1790675167.3506365,
|
||||
"seen": 1790700630.5521457,
|
||||
"ast_hash": "e568fb90a5b30b8697d8483f57427c0e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2478,14 +2478,14 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/about/components/AboutSectionsContent.vue": {
|
||||
"mtime": 1790581289.7652397,
|
||||
"seen": 1790592151.6516407,
|
||||
"mtime": 1790675167.3510337,
|
||||
"seen": 1790700630.5521533,
|
||||
"ast_hash": "fd892a2bfd6d3b1c4a6acf7234422689",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/about/components/AboutSupportActions.vue": {
|
||||
"mtime": 1790581289.755555,
|
||||
"seen": 1790592151.6516414,
|
||||
"mtime": 1790675167.3440611,
|
||||
"seen": 1790700630.552154,
|
||||
"ast_hash": "373d0a9c5d87ad62946879b759426020",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2502,8 +2502,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/about/index.vue": {
|
||||
"mtime": 1790581289.735072,
|
||||
"seen": 1790592151.6516438,
|
||||
"mtime": 1790675167.3388388,
|
||||
"seen": 1790700630.5521562,
|
||||
"ast_hash": "a3e23a3cf00336d85280ee32af176780",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2568,26 +2568,26 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/cart/composables/useCartPage.ts": {
|
||||
"mtime": 1790581289.7767942,
|
||||
"seen": 1790592151.651652,
|
||||
"mtime": 1790675167.3558276,
|
||||
"seen": 1790700630.5521646,
|
||||
"ast_hash": "c88965e44509d5a2465a78072a9120fe",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/cart/desktop/DesktopCartView.vue": {
|
||||
"mtime": 1790581289.7597075,
|
||||
"seen": 1790592151.6516528,
|
||||
"mtime": 1790675167.3499484,
|
||||
"seen": 1790700630.5521653,
|
||||
"ast_hash": "8bb39140d9da0493c1d5e4bfa8dfad32",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/cart/index.vue": {
|
||||
"mtime": 1790581289.7191577,
|
||||
"seen": 1790592151.6516535,
|
||||
"mtime": 1790675167.3332436,
|
||||
"seen": 1790700630.5521662,
|
||||
"ast_hash": "2af9e4fb3c242abfed4812bc22a1bf34",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/cart/mobile/MobileCartView.vue": {
|
||||
"mtime": 1790581289.7343495,
|
||||
"seen": 1790592151.6516542,
|
||||
"mtime": 1790675167.3370388,
|
||||
"seen": 1790700630.5521667,
|
||||
"ast_hash": "3cbfb0474bfdf2847cc4ad51bc4cfa8e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2604,50 +2604,50 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/earnMoney/composables/useEarnMoneyPage.ts": {
|
||||
"mtime": 1790581289.7502456,
|
||||
"seen": 1790592151.6516564,
|
||||
"mtime": 1790675167.3422387,
|
||||
"seen": 1790700630.5521688,
|
||||
"ast_hash": "43e942d8725ae3d6fc773670a26db39c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/earnMoney/desktop/DesktopEarnMoneyView.vue": {
|
||||
"mtime": 1790581289.7792299,
|
||||
"seen": 1790592151.651657,
|
||||
"mtime": 1790675167.3560903,
|
||||
"seen": 1790700630.5521698,
|
||||
"ast_hash": "3bf36eaa1a0038845436558b2c230ea4",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/earnMoney/index.vue": {
|
||||
"mtime": 1790581289.7743354,
|
||||
"seen": 1790592151.6516583,
|
||||
"mtime": 1790675167.3551111,
|
||||
"seen": 1790700630.5521705,
|
||||
"ast_hash": "da19bfb8ad6f304d11af40f9252e4fcf",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/earnMoney/mobile/MobileEarnMoneyView.vue": {
|
||||
"mtime": 1790581289.7039165,
|
||||
"seen": 1790592151.651659,
|
||||
"mtime": 1790675167.327144,
|
||||
"seen": 1790700630.5521712,
|
||||
"ast_hash": "31d5d12a394aad5de1d66f88b6392313",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/fund/components/Item.vue": {
|
||||
"mtime": 1790581289.7175026,
|
||||
"seen": 1790592151.6516597,
|
||||
"mtime": 1790675167.3306296,
|
||||
"seen": 1790700630.552172,
|
||||
"ast_hash": "7b771e46def53e5a67625f1e72ee6e84",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/fund/composables/useFundPage.ts": {
|
||||
"mtime": 1790581289.7640991,
|
||||
"seen": 1790592151.6516604,
|
||||
"mtime": 1790675167.3507905,
|
||||
"seen": 1790700630.552173,
|
||||
"ast_hash": "f5b09c131de6f2b38f79a4075bd4fd30",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/fund/desktop/DesktopFundView.vue": {
|
||||
"mtime": 1790581289.7320585,
|
||||
"seen": 1790592151.6516614,
|
||||
"mtime": 1790675167.338016,
|
||||
"seen": 1790700630.5521736,
|
||||
"ast_hash": "ef7497d1e0fe0f4edc23f652cf7bf982",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/fund/index.vue": {
|
||||
"mtime": 1790581289.7203767,
|
||||
"seen": 1790592151.651662,
|
||||
"mtime": 1790675167.3332903,
|
||||
"seen": 1790700630.5521743,
|
||||
"ast_hash": "dbe505f7de335697d520a5cb2b90e5e7",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2664,32 +2664,32 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/fund/info/composables/useFundInfoPage.ts": {
|
||||
"mtime": 1790581289.7566793,
|
||||
"seen": 1790592151.6516645,
|
||||
"mtime": 1790675167.3483257,
|
||||
"seen": 1790700630.552177,
|
||||
"ast_hash": "aeb2ce91efedaa7b02b24eac5a3e6246",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/fund/info/desktop/DesktopFundInfoView.vue": {
|
||||
"mtime": 1790581289.7581055,
|
||||
"seen": 1790592151.6516652,
|
||||
"mtime": 1790675167.350571,
|
||||
"seen": 1790700630.5521774,
|
||||
"ast_hash": "7043b3599bc2954f5e1f1dfe465835ef",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/fund/info/index.vue": {
|
||||
"mtime": 1790581289.7498908,
|
||||
"seen": 1790592151.651666,
|
||||
"mtime": 1790675167.3420742,
|
||||
"seen": 1790700630.5521781,
|
||||
"ast_hash": "cd54caa6e61b16493547e7cb031ac2dd",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/fund/info/mobile/MobileFundInfoView.vue": {
|
||||
"mtime": 1790581289.7658176,
|
||||
"seen": 1790592151.6516666,
|
||||
"mtime": 1790675167.353358,
|
||||
"seen": 1790700630.5521789,
|
||||
"ast_hash": "63333279f3765972b66789ee439ddfca",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/fund/mobile/MobileFundView.vue": {
|
||||
"mtime": 1790581289.718552,
|
||||
"seen": 1790592151.6516676,
|
||||
"mtime": 1790675167.3324924,
|
||||
"seen": 1790700630.55218,
|
||||
"ast_hash": "1fb480e32178b7cba27e275ab34221ec",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2700,32 +2700,32 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/giftCard/components/GiftCardForm.vue": {
|
||||
"mtime": 1790581289.772232,
|
||||
"seen": 1790592151.6516695,
|
||||
"mtime": 1790675167.3549411,
|
||||
"seen": 1790700630.5521817,
|
||||
"ast_hash": "8f9f270377a5e40094934b0a5283d9ca",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/giftCard/composables/useGiftCardPage.ts": {
|
||||
"mtime": 1790581289.7498488,
|
||||
"seen": 1790592151.65167,
|
||||
"mtime": 1790675167.3421705,
|
||||
"seen": 1790700630.5521824,
|
||||
"ast_hash": "acf910b3e2381af7887662b40fb5f2f2",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/giftCard/desktop/DesktopGiftCardView.vue": {
|
||||
"mtime": 1790581289.7043967,
|
||||
"seen": 1790592151.6516707,
|
||||
"mtime": 1790675167.3282175,
|
||||
"seen": 1790700630.5521832,
|
||||
"ast_hash": "8e7aef94f550b31ab83f57257d33ca64",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/giftCard/index.vue": {
|
||||
"mtime": 1790581289.7638223,
|
||||
"seen": 1790592151.6516716,
|
||||
"mtime": 1790675167.3508492,
|
||||
"seen": 1790700630.5521839,
|
||||
"ast_hash": "c31c5825812c7f8bd641d3fcf3fec4f7",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/giftCard/mobile/MobileGiftCardView.vue": {
|
||||
"mtime": 1790581289.753045,
|
||||
"seen": 1790592151.6516724,
|
||||
"mtime": 1790675167.3449354,
|
||||
"seen": 1790700630.5521846,
|
||||
"ast_hash": "c598fb854b50d209346259c6e1eace01",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2754,8 +2754,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/home/components/HomeSkeleton.vue": {
|
||||
"mtime": 1790581289.7506878,
|
||||
"seen": 1790592151.6516764,
|
||||
"mtime": 1790675167.3434727,
|
||||
"seen": 1790700630.5521884,
|
||||
"ast_hash": "e7e81d45943658b86dfcab3d948f0b36",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2946,8 +2946,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/home/indexgolak.vue": {
|
||||
"mtime": 1790581289.7769225,
|
||||
"seen": 1790592151.651702,
|
||||
"mtime": 1790675167.356107,
|
||||
"seen": 1790700630.5522146,
|
||||
"ast_hash": "e7c91c9c4496b64f4b5cd37d2e424be0",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2970,8 +2970,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/index.vue": {
|
||||
"mtime": 1790581289.7656732,
|
||||
"seen": 1790592151.6517053,
|
||||
"mtime": 1790675167.3529696,
|
||||
"seen": 1790700630.552218,
|
||||
"ast_hash": "5dbef116be09aef0adb7c2cdea432ea8",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -3012,9 +3012,9 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/physicalReceive/composables/useNewPhysicalRequestPage.ts": {
|
||||
"mtime": 1782972802.463694,
|
||||
"seen": 1790532739.4899328,
|
||||
"ast_hash": "a5c087dada0538afb2d25e0f75ad390b",
|
||||
"mtime": 1790700307.7608473,
|
||||
"seen": 1790700630.5522234,
|
||||
"ast_hash": "0289ae710d61986ed62dd0487e6cbe06",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/physicalReceive/composables/usePhysicalReceiveList.ts": {
|
||||
@@ -3036,8 +3036,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/physicalReceive/desktop/DesktopPhysicalReceiveListView.vue": {
|
||||
"mtime": 1790581289.7742436,
|
||||
"seen": 1790592151.6517146,
|
||||
"mtime": 1790675167.3555284,
|
||||
"seen": 1790700630.552227,
|
||||
"ast_hash": "c5d5ced9f804bd57dc0535a4d4de8914",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -3150,9 +3150,9 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/products/composables/useProductsPageData.ts": {
|
||||
"mtime": 1790602630.1972547,
|
||||
"seen": 1790606091.2978623,
|
||||
"ast_hash": "9b1fdb2ab4bf09a8971604cb1b77104b",
|
||||
"mtime": 1790675167.3357227,
|
||||
"seen": 1790700630.5522432,
|
||||
"ast_hash": "cf93e70b85a647a84adb9628f2b0d654",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/products/index.vue": {
|
||||
@@ -3168,8 +3168,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/products/product/[id].vue": {
|
||||
"mtime": 1790581289.7178955,
|
||||
"seen": 1790592151.6517322,
|
||||
"mtime": 1790675167.3322432,
|
||||
"seen": 1790700630.5522456,
|
||||
"ast_hash": "4d5dbffa7f108e296ff6872f6d97f888",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -3222,38 +3222,38 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/rules/components/RulesContentPanel.vue": {
|
||||
"mtime": 1790581289.756601,
|
||||
"seen": 1790592151.6517394,
|
||||
"mtime": 1790675167.348994,
|
||||
"seen": 1790700630.5522585,
|
||||
"ast_hash": "0397b2d938550301e1a371b02399accc",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/rules/components/RulesSupportActions.vue": {
|
||||
"mtime": 1790581289.7043483,
|
||||
"seen": 1790592151.65174,
|
||||
"mtime": 1790675167.3274155,
|
||||
"seen": 1790700630.55226,
|
||||
"ast_hash": "dfcb04410887030a4100a500a22d4f5e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/rules/composables/useRulesPage.ts": {
|
||||
"mtime": 1790581289.7178285,
|
||||
"seen": 1790592151.651741,
|
||||
"mtime": 1790675167.332384,
|
||||
"seen": 1790700630.552261,
|
||||
"ast_hash": "67e9a8ea5f5c75382d82d90d71e41b81",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/rules/desktop/DesktopRulesView.vue": {
|
||||
"mtime": 1790581289.753291,
|
||||
"seen": 1790592151.6517417,
|
||||
"mtime": 1790675167.343888,
|
||||
"seen": 1790700630.5522623,
|
||||
"ast_hash": "eac93a3ad3870f9cb71f538a60912f95",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/rules/index.vue": {
|
||||
"mtime": 1790581289.7107584,
|
||||
"seen": 1790592151.6517422,
|
||||
"mtime": 1790675167.329072,
|
||||
"seen": 1790700630.552264,
|
||||
"ast_hash": "6c03a46bb3bff411c5098f55d34d94e5",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/rules/mobile/MobileRulesView.vue": {
|
||||
"mtime": 1790581289.7456188,
|
||||
"seen": 1790592151.651743,
|
||||
"mtime": 1790675167.3389237,
|
||||
"seen": 1790700630.5522654,
|
||||
"ast_hash": "8379fb3f36a470b2692a8ef5be8f70a8",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -3264,14 +3264,14 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/rules/rulesContent.ts": {
|
||||
"mtime": 1790581289.7184877,
|
||||
"seen": 1790592151.6517446,
|
||||
"mtime": 1790675167.332593,
|
||||
"seen": 1790700630.5522676,
|
||||
"ast_hash": "e4eedce0363cf670da9865d26e9a96ab",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/transactions/components/Item.vue": {
|
||||
"mtime": 1790581289.7771592,
|
||||
"seen": 1790592151.6517453,
|
||||
"mtime": 1790675167.3559308,
|
||||
"seen": 1790700630.5522683,
|
||||
"ast_hash": "54ac7d17ec562d7dbe43497131ddddb0",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -3282,26 +3282,26 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/transactions/composables/useTransactionsPage.ts": {
|
||||
"mtime": 1790581289.7564578,
|
||||
"seen": 1790592151.6517467,
|
||||
"mtime": 1790675167.347898,
|
||||
"seen": 1790700630.5522702,
|
||||
"ast_hash": "c3f311baff2920528772a3fc72c5492c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/transactions/desktop/DesktopDefaultTransactionsView.vue": {
|
||||
"mtime": 1790581289.7458122,
|
||||
"seen": 1790592151.6517475,
|
||||
"mtime": 1790675167.3390832,
|
||||
"seen": 1790700630.552271,
|
||||
"ast_hash": "95aefd29cc97851ac06bb09652127202",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/transactions/index.vue": {
|
||||
"mtime": 1790581289.7642682,
|
||||
"seen": 1790592151.6517484,
|
||||
"mtime": 1790675167.3507755,
|
||||
"seen": 1790700630.5522718,
|
||||
"ast_hash": "90e227da4097bbcb4b352bb531cac43b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/transactions/mobile/MobileTransactionsView.vue": {
|
||||
"mtime": 1790581289.7041333,
|
||||
"seen": 1790592151.651749,
|
||||
"mtime": 1790675167.327207,
|
||||
"seen": 1790700630.5522726,
|
||||
"ast_hash": "c930d0557e4ca8962a2d43aef10a8f0f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -3324,14 +3324,14 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/user/components/UserPasswordForm.vue": {
|
||||
"mtime": 1790581289.7750266,
|
||||
"seen": 1790592151.6517522,
|
||||
"mtime": 1790675167.3555717,
|
||||
"seen": 1790700630.5522764,
|
||||
"ast_hash": "9686bcb583ad891f11b2cec9d910721c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/user/components/UserProfileForm.vue": {
|
||||
"mtime": 1790581289.7041698,
|
||||
"seen": 1790592151.6517527,
|
||||
"mtime": 1790675167.3274717,
|
||||
"seen": 1790700630.5522773,
|
||||
"ast_hash": "7f3c664c7154ecc4cfca4daed9063310",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -3342,8 +3342,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/user/desktop/DesktopUserView.vue": {
|
||||
"mtime": 1790581289.7662172,
|
||||
"seen": 1790592151.6517541,
|
||||
"mtime": 1790675167.3539462,
|
||||
"seen": 1790700630.552279,
|
||||
"ast_hash": "e862a78b1710d68c88a5f25ac28cce2f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -3420,14 +3420,14 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/wallet/desktop/DesktopWalletView.vue": {
|
||||
"mtime": 1790581289.7505662,
|
||||
"seen": 1790592151.651765,
|
||||
"mtime": 1790675167.343406,
|
||||
"seen": 1790700630.55229,
|
||||
"ast_hash": "d4de65f275cfde91982dfb20fc8eea2f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/base/wallet/index.vue": {
|
||||
"mtime": 1790581289.7778225,
|
||||
"seen": 1790592151.6517658,
|
||||
"mtime": 1790675167.3557346,
|
||||
"seen": 1790700630.5522912,
|
||||
"ast_hash": "4d09ded1dca5233463275270edaf2781",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -3486,8 +3486,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/support/components/SupportChatHeader.vue": {
|
||||
"mtime": 1790581289.7797737,
|
||||
"seen": 1790592151.6517744,
|
||||
"mtime": 1790675167.3561814,
|
||||
"seen": 1790700630.5523007,
|
||||
"ast_hash": "ed62c182838b1a9acb9e4ad4715db061",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -3498,8 +3498,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/support/index.vue": {
|
||||
"mtime": 1790581289.7042654,
|
||||
"seen": 1790592151.651776,
|
||||
"mtime": 1790675167.3272913,
|
||||
"seen": 1790700630.5523026,
|
||||
"ast_hash": "38596d0cb6e4b74c300bbc32d2caee73",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -3510,8 +3510,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/views/tv/composables/useTvMonitorPage.ts": {
|
||||
"mtime": 1790604052.0040936,
|
||||
"seen": 1790606091.2979152,
|
||||
"mtime": 1790675167.3505325,
|
||||
"seen": 1790700630.5523043,
|
||||
"ast_hash": "d85990e113d0ad330a1ae0dbbc5fcad0",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -3534,8 +3534,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/vite-env.d.ts": {
|
||||
"mtime": 1790581289.7662013,
|
||||
"seen": 1790592151.6517808,
|
||||
"mtime": 1790675167.3539531,
|
||||
"seen": 1790700630.5523074,
|
||||
"ast_hash": "870ea76d31cfb7145c73307deca819a3",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
|
||||
+7
-3
@@ -1,10 +1,14 @@
|
||||
import useAxios from "@/utils/useAxios";
|
||||
import type {PInventory, Product} from "@/models/products";
|
||||
import type { PWallet, Wallet } from '@/models/wallet'
|
||||
import { priceStreamList } from "@/utils/priceSocketState";
|
||||
|
||||
|
||||
export const getProducts = async (): Promise<any> => {
|
||||
return await useAxios.get<Product[]>(`/customer/product/list`, { timeout: 15000 })
|
||||
export const getProducts = async (force = false): Promise<Product[]> => {
|
||||
if (!force && Array.isArray(priceStreamList.value) && priceStreamList.value.length > 0) {
|
||||
return priceStreamList.value as unknown as Product[]
|
||||
}
|
||||
const response = await useAxios.get<Product[]>(`/customer/product/list`, { timeout: 15000 })
|
||||
return Array.isArray(response) ? response : []
|
||||
}
|
||||
export const getTvProducts = async (): Promise<Product[]> => {
|
||||
const response = await useAxios.get<unknown>(`/customer/tv/products`, { timeout: 15000 })
|
||||
|
||||
@@ -0,0 +1,861 @@
|
||||
<template>
|
||||
<div
|
||||
ref="containerRef"
|
||||
class="product-picker-root"
|
||||
:class="{
|
||||
'product-picker-root--compact': compact,
|
||||
'product-picker-root--open': isOpen,
|
||||
}"
|
||||
>
|
||||
<label v-if="label" class="product-picker__label">{{ label }}</label>
|
||||
|
||||
<!-- سلکتور جمعوجور -->
|
||||
<div
|
||||
class="product-picker__control"
|
||||
:class="{
|
||||
'product-picker__control--clickable': !disabled && !isEdit,
|
||||
'product-picker__control--disabled': disabled,
|
||||
'product-picker__control--locked': isEdit,
|
||||
'product-picker__control--active': isOpen,
|
||||
}"
|
||||
role="button"
|
||||
:tabindex="disabled ? -1 : 0"
|
||||
:aria-label="label || placeholder"
|
||||
@click="toggleOpen"
|
||||
@keydown.enter.prevent="toggleOpen"
|
||||
>
|
||||
<div class="product-picker__value">
|
||||
<span class="product-picker__icon" aria-hidden="true">
|
||||
<BasicIcon
|
||||
:icon="isEdit ? 'vuesax-linear:lock' : 'vuesax-linear:box-1'"
|
||||
:size="compact ? 16 : 18"
|
||||
:color="selectedItem ? 'var(--App-secondary-color, #e0be7f)' : 'var(--app-text-soft, #9ca3af)'"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="product-picker__text"
|
||||
:class="{ 'product-picker__text--placeholder': !selectedItem && !lockedTitle }"
|
||||
>
|
||||
{{ displayTitle }}
|
||||
</span>
|
||||
<span v-if="displayUnit" class="product-picker__unit">({{ displayUnit }})</span>
|
||||
<span v-if="displaySubtitle" class="product-picker__subtitle">{{ displaySubtitle }}</span>
|
||||
</div>
|
||||
|
||||
<div class="product-picker__trailing">
|
||||
<button
|
||||
v-if="allowClear && selectedItem && !disabled && !isEdit"
|
||||
type="button"
|
||||
class="product-picker__clear-btn"
|
||||
aria-label="پاک کردن"
|
||||
@click.stop="handleClear"
|
||||
>
|
||||
<BasicIcon icon="vuesax-linear:close-circle" size="16" color="var(--app-text-soft, #9ca3af)" />
|
||||
</button>
|
||||
<span class="product-picker__arrow" aria-hidden="true">
|
||||
<BasicIcon
|
||||
v-if="!isEdit"
|
||||
:icon="isOpen ? 'vuesax-linear:arrow-up-1' : 'vuesax-linear:arrow-down-1'"
|
||||
size="16"
|
||||
color="var(--app-text-soft, #9ca3af)"
|
||||
/>
|
||||
<BasicIcon v-else icon="vuesax-linear:lock" size="14" color="var(--app-text-soft, #9ca3af)" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- دراپداون دسکتاپ -->
|
||||
<div
|
||||
v-if="isDesktop && isOpen && !disabled && !isEdit"
|
||||
class="product-picker__dropdown"
|
||||
:style="dropdownStyle"
|
||||
>
|
||||
<div class="product-picker__search">
|
||||
<span class="product-picker__search-icon" aria-hidden="true">
|
||||
<BasicIcon icon="vuesax-linear:search-normal" size="16" color="var(--app-text-soft, #9ca3af)" />
|
||||
</span>
|
||||
<input
|
||||
ref="desktopSearchInputRef"
|
||||
v-model="searchQuery"
|
||||
type="text"
|
||||
class="product-picker__search-input"
|
||||
placeholder="جستجوی محصول..."
|
||||
autocomplete="off"
|
||||
/>
|
||||
<button
|
||||
v-if="searchQuery"
|
||||
type="button"
|
||||
class="product-picker__clear-query-btn"
|
||||
aria-label="پاک کردن جستجو"
|
||||
@click="searchQuery = ''"
|
||||
>
|
||||
<BasicIcon icon="vuesax-linear:close-circle" size="15" color="var(--app-text-soft, #9ca3af)" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="product-picker__list" role="listbox">
|
||||
<button
|
||||
v-for="p in filteredList"
|
||||
:key="getItemKey(p)"
|
||||
type="button"
|
||||
role="option"
|
||||
class="product-picker__item"
|
||||
:class="{ 'product-picker__item--selected': isSelected(p) }"
|
||||
:aria-selected="isSelected(p)"
|
||||
@click="selectItem(p)"
|
||||
>
|
||||
<div class="product-picker__item-info">
|
||||
<span class="product-picker__item-icon">
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:box-1"
|
||||
size="16"
|
||||
:color="isSelected(p) ? 'var(--App-secondary-color, #e0be7f)' : 'inherit'"
|
||||
/>
|
||||
</span>
|
||||
<span class="product-picker__item-title">{{ getItemTitle(p) }}</span>
|
||||
<span v-if="getItemUnit(p)" class="product-picker__item-unit">({{ getItemUnit(p) }})</span>
|
||||
<span v-if="getItemSubtitle(p)" class="product-picker__item-subtitle">{{ getItemSubtitle(p) }}</span>
|
||||
</div>
|
||||
|
||||
<span v-if="isSelected(p)" class="product-picker__item-check">
|
||||
<BasicIcon icon="vuesax-linear:tick-circle" size="18" color="var(--App-secondary-color, #e0be7f)" />
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div v-if="loading" class="product-picker__loading">
|
||||
<BasicIcon icon="vuesax-linear:box-time" size="20" class="animate-spin" color="var(--App-secondary-color, #e0be7f)" />
|
||||
<span>در حال دریافت محصولات...</span>
|
||||
</div>
|
||||
<div v-else-if="filteredList.length === 0" class="product-picker__empty">
|
||||
<BasicIcon icon="vuesax-linear:info-circle" size="20" color="var(--app-text-soft, #9ca3af)" />
|
||||
<span>{{ emptyText }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- اکشنشیت موبایل -->
|
||||
<BasicActionSheet
|
||||
v-if="!isDesktop"
|
||||
v-model:show="isSheetOpen"
|
||||
:title="sheetTitle"
|
||||
:closable="true"
|
||||
@closed="onSheetClosed"
|
||||
>
|
||||
<div class="product-picker-sheet">
|
||||
<div class="product-picker-sheet__search">
|
||||
<span class="product-picker-sheet__search-icon" aria-hidden="true">
|
||||
<BasicIcon icon="vuesax-linear:search-normal" size="18" color="var(--app-text-soft, #9ca3af)" />
|
||||
</span>
|
||||
<input
|
||||
ref="mobileSearchInputRef"
|
||||
v-model="searchQuery"
|
||||
type="text"
|
||||
class="product-picker-sheet__search-input"
|
||||
placeholder="جستجوی نام یا کد محصول..."
|
||||
autocomplete="off"
|
||||
/>
|
||||
<button
|
||||
v-if="searchQuery"
|
||||
type="button"
|
||||
class="product-picker-sheet__clear-btn"
|
||||
aria-label="پاک کردن جستجو"
|
||||
@click="searchQuery = ''"
|
||||
>
|
||||
<BasicIcon icon="vuesax-linear:close-circle" size="18" color="var(--app-text-soft, #9ca3af)" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="product-picker-sheet__list" role="listbox">
|
||||
<button
|
||||
v-for="p in filteredList"
|
||||
:key="getItemKey(p)"
|
||||
type="button"
|
||||
role="option"
|
||||
class="product-picker-sheet__item"
|
||||
:class="{ 'product-picker-sheet__item--selected': isSelected(p) }"
|
||||
:aria-selected="isSelected(p)"
|
||||
@click="selectItem(p)"
|
||||
>
|
||||
<div class="product-picker-sheet__item-info">
|
||||
<span class="product-picker-sheet__item-icon">
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:box-1"
|
||||
size="18"
|
||||
:color="isSelected(p) ? 'var(--App-secondary-color, #e0be7f)' : 'inherit'"
|
||||
/>
|
||||
</span>
|
||||
<div class="product-picker-sheet__item-texts">
|
||||
<span class="product-picker-sheet__item-title">{{ getItemTitle(p) }}</span>
|
||||
<span
|
||||
v-if="getItemSubtitle(p) || getItemUnit(p)"
|
||||
class="product-picker-sheet__item-meta"
|
||||
>
|
||||
{{ getItemSubtitle(p) || `واحد: ${getItemUnit(p)}` }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span v-if="isSelected(p)" class="product-picker-sheet__item-check">
|
||||
<BasicIcon icon="vuesax-linear:tick-circle" size="20" color="var(--App-secondary-color, #e0be7f)" />
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div v-if="loading" class="product-picker-sheet__loading">
|
||||
<BasicIcon icon="vuesax-linear:box-time" size="26" class="animate-spin" color="var(--App-secondary-color, #e0be7f)" />
|
||||
<span class="mt-2 text-sm text-gray-400">در حال دریافت محصولات...</span>
|
||||
</div>
|
||||
<div v-else-if="filteredList.length === 0" class="product-picker-sheet__empty">
|
||||
<BasicIcon icon="vuesax-linear:info-circle" size="24" color="var(--app-text-soft, #9ca3af)" />
|
||||
<span>{{ emptyText }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BasicActionSheet>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
|
||||
import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout'
|
||||
|
||||
interface Props {
|
||||
modelValue?: number | string | null
|
||||
value?: number | string | null
|
||||
items?: any[]
|
||||
products?: any[]
|
||||
keyName?: string
|
||||
valueName?: string
|
||||
unitName?: string
|
||||
subtitleName?: string
|
||||
placeholder?: string
|
||||
sheetTitle?: string
|
||||
label?: string
|
||||
disabled?: boolean
|
||||
loading?: boolean
|
||||
isEdit?: boolean
|
||||
lockedTitle?: string
|
||||
allowClear?: boolean
|
||||
compact?: boolean
|
||||
emptyText?: string
|
||||
dropdownStyle?: Record<string, any>
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
modelValue: undefined,
|
||||
value: undefined,
|
||||
items: undefined,
|
||||
products: undefined,
|
||||
keyName: 'id',
|
||||
valueName: 'title',
|
||||
unitName: 'unit',
|
||||
subtitleName: 'subtitle',
|
||||
placeholder: 'انتخاب محصول...',
|
||||
sheetTitle: 'انتخاب محصول',
|
||||
label: '',
|
||||
disabled: false,
|
||||
loading: false,
|
||||
isEdit: false,
|
||||
lockedTitle: '',
|
||||
allowClear: false,
|
||||
compact: false,
|
||||
emptyText: 'محصولی یافت نشد',
|
||||
dropdownStyle: undefined,
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [val: any]
|
||||
'update:value': [val: any]
|
||||
'change': [item: any]
|
||||
'clear': []
|
||||
}>()
|
||||
|
||||
const isDesktop = useDesktopBreakpoint()
|
||||
const containerRef = ref<HTMLElement>()
|
||||
const desktopSearchInputRef = ref<HTMLInputElement>()
|
||||
const mobileSearchInputRef = ref<HTMLInputElement>()
|
||||
|
||||
const isOpen = ref(false)
|
||||
const isSheetOpen = ref(false)
|
||||
const searchQuery = ref('')
|
||||
|
||||
const effectiveList = computed(() => {
|
||||
if (Array.isArray(props.items)) return props.items
|
||||
if (Array.isArray(props.products)) return props.products
|
||||
return []
|
||||
})
|
||||
|
||||
const currentValue = computed(() => {
|
||||
if (props.modelValue !== undefined) return props.modelValue
|
||||
return props.value
|
||||
})
|
||||
|
||||
function getItemKey(item: any): any {
|
||||
if (!item) return ''
|
||||
return item[props.keyName] !== undefined ? item[props.keyName] : item.id
|
||||
}
|
||||
|
||||
function getItemTitle(item: any): string {
|
||||
if (!item) return ''
|
||||
return String(item[props.valueName] || item.title || item.name || `محصول ${getItemKey(item)}`)
|
||||
}
|
||||
|
||||
function getItemUnit(item: any): string {
|
||||
if (!item) return ''
|
||||
return item[props.unitName] || item.unit || ''
|
||||
}
|
||||
|
||||
function getItemSubtitle(item: any): string {
|
||||
if (!item) return ''
|
||||
return item[props.subtitleName] || item.subtitle || ''
|
||||
}
|
||||
|
||||
const selectedItem = computed(() => {
|
||||
const val = currentValue.value
|
||||
if (val === undefined || val === null || val === '') return null
|
||||
return effectiveList.value.find((p) => String(getItemKey(p)) === String(val)) ?? null
|
||||
})
|
||||
|
||||
const displayTitle = computed(() => {
|
||||
if (props.isEdit && props.lockedTitle) return props.lockedTitle
|
||||
if (selectedItem.value) return getItemTitle(selectedItem.value)
|
||||
const val = currentValue.value
|
||||
if (val !== undefined && val !== null && val !== '') return `محصول ${val}`
|
||||
return props.placeholder
|
||||
})
|
||||
|
||||
const displayUnit = computed(() => {
|
||||
if (props.isEdit) return ''
|
||||
return selectedItem.value ? getItemUnit(selectedItem.value) : ''
|
||||
})
|
||||
|
||||
const displaySubtitle = computed(() => {
|
||||
if (props.isEdit) return ''
|
||||
return selectedItem.value ? getItemSubtitle(selectedItem.value) : ''
|
||||
})
|
||||
|
||||
function isSelected(item: any): boolean {
|
||||
const val = currentValue.value
|
||||
if (val === undefined || val === null || val === '') return false
|
||||
return String(getItemKey(item)) === String(val)
|
||||
}
|
||||
|
||||
function normalizeText(text: string): string {
|
||||
return (text || '')
|
||||
.toLowerCase()
|
||||
.replace(/ي/g, 'ی')
|
||||
.replace(/ك/g, 'ک')
|
||||
.replace(/[\u200B-\u200D\uFEFF]/g, '')
|
||||
.trim()
|
||||
}
|
||||
|
||||
const filteredList = computed(() => {
|
||||
const q = normalizeText(searchQuery.value)
|
||||
if (!q) return effectiveList.value
|
||||
return effectiveList.value.filter((p) => {
|
||||
const title = normalizeText(getItemTitle(p))
|
||||
const unit = normalizeText(getItemUnit(p))
|
||||
const subtitle = normalizeText(getItemSubtitle(p))
|
||||
const key = String(getItemKey(p))
|
||||
return title.includes(q) || unit.includes(q) || subtitle.includes(q) || key.includes(q)
|
||||
})
|
||||
})
|
||||
|
||||
function toggleOpen() {
|
||||
if (props.disabled || props.isEdit) return
|
||||
if (isDesktop.value) {
|
||||
isOpen.value = !isOpen.value
|
||||
if (isOpen.value) {
|
||||
nextTick(() => {
|
||||
desktopSearchInputRef.value?.focus()
|
||||
})
|
||||
} else {
|
||||
searchQuery.value = ''
|
||||
}
|
||||
} else {
|
||||
isSheetOpen.value = true
|
||||
nextTick(() => {
|
||||
mobileSearchInputRef.value?.focus()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function selectItem(item: any) {
|
||||
const key = getItemKey(item)
|
||||
emit('update:modelValue', key)
|
||||
emit('update:value', key)
|
||||
emit('change', item)
|
||||
isOpen.value = false
|
||||
isSheetOpen.value = false
|
||||
searchQuery.value = ''
|
||||
}
|
||||
|
||||
function handleClear() {
|
||||
emit('update:modelValue', undefined)
|
||||
emit('update:value', undefined)
|
||||
emit('change', undefined)
|
||||
emit('clear')
|
||||
}
|
||||
|
||||
function onSheetClosed() {
|
||||
searchQuery.value = ''
|
||||
}
|
||||
|
||||
function handleClickOutside(e: MouseEvent) {
|
||||
if (containerRef.value && !containerRef.value.contains(e.target as Node)) {
|
||||
isOpen.value = false
|
||||
searchQuery.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('click', handleClickOutside)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('click', handleClickOutside)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.product-picker-root {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.375rem;
|
||||
width: 100%;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
z-index: 1;
|
||||
|
||||
&--open {
|
||||
z-index: 50;
|
||||
}
|
||||
--picker-bg: var(--app-surface, var(--admin-bg-surface, #ffffff));
|
||||
--picker-border: var(--app-border, var(--admin-border, #e2e8f0));
|
||||
--picker-border-focus: var(--app-border-strong, var(--App-secondary-color, #e0be7f));
|
||||
--picker-text: var(--app-text-primary, var(--admin-text, #0f172a));
|
||||
--picker-text-soft: var(--app-text-muted, var(--admin-text-secondary, #64748b));
|
||||
--picker-inset: var(--app-surface-inset, rgba(15, 23, 42, 0.03));
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .product-picker-root,
|
||||
:global(html.dark) .product-picker-root {
|
||||
--picker-bg: var(--app-surface, #1e2026);
|
||||
--picker-border: var(--app-border, rgba(255, 255, 255, 0.12));
|
||||
--picker-border-focus: var(--app-border-strong, rgba(255, 255, 255, 0.28));
|
||||
--picker-text: var(--app-text-primary, #ffffff);
|
||||
--picker-text-soft: var(--app-text-muted, rgba(255, 255, 255, 0.55));
|
||||
--picker-inset: var(--app-surface-inset, rgba(255, 255, 255, 0.04));
|
||||
}
|
||||
|
||||
.product-picker__label {
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 700;
|
||||
color: var(--picker-text);
|
||||
}
|
||||
|
||||
.product-picker__control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-height: 2.65rem;
|
||||
padding: 0 0.75rem;
|
||||
border-radius: 0.65rem;
|
||||
border: 1px solid var(--picker-border);
|
||||
background: var(--picker-bg);
|
||||
color: var(--picker-text);
|
||||
direction: rtl;
|
||||
transition: all 0.18s ease;
|
||||
user-select: none;
|
||||
|
||||
.product-picker-root--compact & {
|
||||
min-height: 2.35rem;
|
||||
padding: 0 0.6rem;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
&--clickable {
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
border-color: var(--picker-border-focus);
|
||||
}
|
||||
}
|
||||
|
||||
&--active {
|
||||
border-color: var(--picker-border-focus);
|
||||
box-shadow: 0 0 0 2px rgba(227, 176, 86, 0.15);
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
background: var(--picker-inset);
|
||||
}
|
||||
|
||||
&--locked {
|
||||
background: var(--picker-inset);
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
.product-picker__value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.product-picker__icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.product-picker__text {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: var(--picker-text);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
.product-picker-root--compact & {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
&--placeholder {
|
||||
color: var(--picker-text-soft);
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.product-picker__unit {
|
||||
font-size: 0.75rem;
|
||||
color: var(--picker-text-soft);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.product-picker__subtitle {
|
||||
font-size: 0.72rem;
|
||||
color: var(--App-secondary-color, #e0be7f);
|
||||
font-weight: 600;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.product-picker__trailing {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.product-picker__clear-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
background: transparent;
|
||||
padding: 2px;
|
||||
cursor: pointer;
|
||||
border-radius: 9999px;
|
||||
transition: opacity 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.product-picker__arrow {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* دراپداون دسکتاپ */
|
||||
.product-picker__dropdown {
|
||||
position: absolute;
|
||||
top: calc(100% + 4px);
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 1050;
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.75rem;
|
||||
border: 1px solid var(--picker-border);
|
||||
background: var(--picker-bg);
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.12);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.375rem;
|
||||
}
|
||||
|
||||
.product-picker__search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
height: 2.25rem;
|
||||
padding: 0 0.6rem;
|
||||
border-radius: 0.5rem;
|
||||
background: var(--picker-inset);
|
||||
border: 1px solid var(--picker-border);
|
||||
}
|
||||
|
||||
.product-picker__search-icon {
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.product-picker__search-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
color: var(--picker-text);
|
||||
font-size: 0.8125rem;
|
||||
text-align: right;
|
||||
direction: rtl;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--picker-text-soft);
|
||||
}
|
||||
}
|
||||
|
||||
.product-picker__clear-query-btn {
|
||||
border: none;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.product-picker__list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
max-height: 14rem;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.product-picker__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 0.5rem 0.65rem;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid transparent;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
outline: none;
|
||||
text-align: right;
|
||||
|
||||
&:hover {
|
||||
background: var(--picker-inset);
|
||||
border-color: var(--picker-border);
|
||||
}
|
||||
|
||||
&--selected {
|
||||
background: rgba(224, 190, 127, 0.12);
|
||||
border-color: var(--App-secondary-color, #e0be7f);
|
||||
}
|
||||
}
|
||||
|
||||
.product-picker__item-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.product-picker__item-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.product-picker__item-title {
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
color: var(--picker-text);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.product-picker__item-unit {
|
||||
font-size: 0.72rem;
|
||||
color: var(--picker-text-soft);
|
||||
}
|
||||
|
||||
.product-picker__item-subtitle {
|
||||
font-size: 0.72rem;
|
||||
color: var(--App-secondary-color, #e0be7f);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.product-picker__item-check {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.product-picker__empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.35rem;
|
||||
padding: 1.25rem 0.5rem;
|
||||
color: var(--picker-text-soft);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
/* شیت موبایل */
|
||||
.product-picker-sheet {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
padding-bottom: 1.5rem;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.product-picker-sheet__search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
height: 2.75rem;
|
||||
padding: 0 0.85rem;
|
||||
border-radius: 0.75rem;
|
||||
background: var(--picker-inset);
|
||||
border: 1px solid var(--picker-border);
|
||||
}
|
||||
|
||||
.product-picker-sheet__search-icon {
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.product-picker-sheet__search-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
color: var(--picker-text);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
text-align: right;
|
||||
direction: rtl;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--picker-text-soft);
|
||||
}
|
||||
}
|
||||
|
||||
.product-picker-sheet__clear-btn {
|
||||
border: none;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.product-picker-sheet__list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
max-height: 55vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.product-picker-sheet__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 0.65rem 0.75rem;
|
||||
border-radius: 0.65rem;
|
||||
border: 1px solid var(--picker-border);
|
||||
background: var(--picker-bg);
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
outline: none;
|
||||
text-align: right;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--App-secondary-color, #e0be7f);
|
||||
}
|
||||
|
||||
&--selected {
|
||||
border-color: var(--App-secondary-color, #e0be7f);
|
||||
background: rgba(224, 190, 127, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.product-picker-sheet__item-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.65rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.product-picker-sheet__item-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2.1rem;
|
||||
height: 2.1rem;
|
||||
border-radius: 0.5rem;
|
||||
background: var(--picker-inset);
|
||||
flex-shrink: 0;
|
||||
|
||||
.product-picker-sheet__item--selected & {
|
||||
background: var(--App-secondary-color, #e0be7f);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.product-picker-sheet__item-texts {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.product-picker-sheet__item-title {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 700;
|
||||
color: var(--picker-text);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.product-picker-sheet__item-meta {
|
||||
font-size: 0.7rem;
|
||||
color: var(--picker-text-soft);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.product-picker-sheet__item-check {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.product-picker-sheet__empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.4rem;
|
||||
padding: 2rem 1rem;
|
||||
color: var(--picker-text-soft);
|
||||
font-size: 0.8125rem;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,15 +1,38 @@
|
||||
import { ref } from 'vue'
|
||||
import { getProducts } from '@/api/products'
|
||||
import type { Product } from '@/models/products'
|
||||
import { priceStreamList } from '@/utils/priceSocketState'
|
||||
|
||||
/** کش مشترک لیست محصولات — dedupe درخواستهای polling */
|
||||
const catalogProducts = ref<Product[]>([])
|
||||
let catalogPromise: Promise<Product[]> | null = null
|
||||
|
||||
export function getProductsCatalogRef() {
|
||||
if (catalogProducts.value.length === 0 && Array.isArray(priceStreamList.value) && priceStreamList.value.length > 0) {
|
||||
catalogProducts.value = priceStreamList.value as unknown as Product[]
|
||||
}
|
||||
return catalogProducts
|
||||
}
|
||||
|
||||
export function syncCatalogFromStream(streamProducts: Product[]) {
|
||||
if (!Array.isArray(streamProducts) || streamProducts.length === 0) return
|
||||
if (catalogProducts.value.length === 0) {
|
||||
catalogProducts.value = streamProducts
|
||||
} else {
|
||||
const map = new Map(streamProducts.map((p) => [p.id, p]))
|
||||
catalogProducts.value.forEach((p) => {
|
||||
const incoming = map.get(p.id)
|
||||
if (incoming) {
|
||||
if (incoming.price !== undefined) p.price = incoming.price
|
||||
if (incoming.price_buy !== undefined) p.price_buy = incoming.price_buy
|
||||
if (incoming.price_sell !== undefined) p.price_sell = incoming.price_sell
|
||||
if (incoming.trade_open !== undefined) p.trade_open = incoming.trade_open
|
||||
if (incoming.show !== undefined) p.show = incoming.show
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function findProductInCatalog(id: number): Product | undefined {
|
||||
return catalogProducts.value.find((p) => p.id === id)
|
||||
}
|
||||
@@ -19,17 +42,34 @@ export function getProductsCatalog(force = false): Promise<Product[]> {
|
||||
if (catalogProducts.value.length > 0) {
|
||||
return Promise.resolve(catalogProducts.value)
|
||||
}
|
||||
if (Array.isArray(priceStreamList.value) && priceStreamList.value.length > 0) {
|
||||
catalogProducts.value = priceStreamList.value as unknown as Product[]
|
||||
return Promise.resolve(catalogProducts.value)
|
||||
}
|
||||
}
|
||||
|
||||
if (!force && catalogPromise) {
|
||||
return catalogPromise
|
||||
}
|
||||
|
||||
catalogPromise = getProducts()
|
||||
catalogPromise = getProducts(force)
|
||||
.then((products) => {
|
||||
catalogProducts.value = products ?? []
|
||||
const list = Array.isArray(products) ? products : []
|
||||
if (list.length > 0) {
|
||||
catalogProducts.value = list
|
||||
}
|
||||
return catalogProducts.value
|
||||
})
|
||||
.catch((err) => {
|
||||
if (catalogProducts.value.length > 0) {
|
||||
return catalogProducts.value
|
||||
}
|
||||
if (Array.isArray(priceStreamList.value) && priceStreamList.value.length > 0) {
|
||||
catalogProducts.value = priceStreamList.value as unknown as Product[]
|
||||
return catalogProducts.value
|
||||
}
|
||||
throw err
|
||||
})
|
||||
.finally(() => {
|
||||
catalogPromise = null
|
||||
})
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { Product } from '@/models/products'
|
||||
import { Modal } from 'ant-design-vue'
|
||||
import { getConfigApp } from '@/utils/config'
|
||||
import { applyProductsListFromStream } from '@/utils/productStreamBridge'
|
||||
import { syncCatalogFromStream } from '@/composables/useProductsCatalog'
|
||||
import {
|
||||
priceSocketConnected,
|
||||
priceStreamConnectingSince,
|
||||
@@ -505,6 +506,7 @@ function handleListPayload(payload: unknown) {
|
||||
|
||||
touchStreamActivity()
|
||||
priceStreamList.value = products as Array<Record<string, unknown>>
|
||||
syncCatalogFromStream(products)
|
||||
applyProductsListFromStream(products)
|
||||
}
|
||||
|
||||
|
||||
@@ -307,43 +307,28 @@ function tvBuyUnitPrice(product: Product): number {
|
||||
}
|
||||
|
||||
function tvSellUnitPrice(product: Product): number {
|
||||
const sell = Number(product.tv_sell_price ?? 0)
|
||||
if (sell > 0) {
|
||||
return sell
|
||||
}
|
||||
return tvBuyUnitPrice(product)
|
||||
return Number(product.tv_sell_price ?? 0)
|
||||
}
|
||||
|
||||
export function getTvProductBuyPrice(product?: Product | null): number {
|
||||
if (!product) {
|
||||
return 0
|
||||
}
|
||||
const unit = tvBuyUnitPrice(product)
|
||||
if (unit > 0) {
|
||||
return unit
|
||||
}
|
||||
return getProductBuyPrice(product)
|
||||
return tvBuyUnitPrice(product)
|
||||
}
|
||||
|
||||
export function getTvProductSellPrice(product?: Product | null): number {
|
||||
if (!product) {
|
||||
return 0
|
||||
}
|
||||
const unit = tvSellUnitPrice(product)
|
||||
if (unit > 0) {
|
||||
return unit
|
||||
}
|
||||
return getProductSellPrice(product)
|
||||
return tvSellUnitPrice(product)
|
||||
}
|
||||
|
||||
export function isTvProductPriceInactive(product?: Product | null): boolean {
|
||||
if (!product) {
|
||||
return true
|
||||
}
|
||||
if (tvBuyUnitPrice(product) > 0 || tvSellUnitPrice(product) > 0) {
|
||||
return false
|
||||
}
|
||||
return isProductPriceInactive(product)
|
||||
return tvBuyUnitPrice(product) <= 0 && tvSellUnitPrice(product) <= 0
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { inject, nextTick, onMounted, provide, ref, type InjectionKey, type Ref } from 'vue'
|
||||
import { inject, nextTick, onMounted, provide, ref, watch, type InjectionKey, type Ref } from 'vue'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { message } from 'ant-design-vue'
|
||||
import router from '@/router'
|
||||
import { getProductInventory } from '@/api/products'
|
||||
import { physicalReceiveApi } from '@/api/physicalreceive'
|
||||
import { tableAddress } from '@/api/address'
|
||||
import type { CountPInventory, PInventory } from '@/models/products'
|
||||
import type { CountPInventory, PInventory, Product } from '@/models/products'
|
||||
import type { Address } from '@/models/address'
|
||||
import { loading } from '@/utils'
|
||||
import { priceStreamList } from '@/utils/priceSocketState'
|
||||
import { useWalletAssets } from '@/composables/useWalletAssets'
|
||||
import { usePhysicalReceiveShellContext } from './usePhysicalReceiveShell'
|
||||
|
||||
@@ -73,18 +74,63 @@ export function useNewPhysicalRequestPage() {
|
||||
)
|
||||
}
|
||||
|
||||
let cachedInventoryRows: PInventory[] = []
|
||||
|
||||
function buildPhysicalDeliveryItems(inventoryRows: PInventory[] = []): PInventory[] {
|
||||
const streamList = Array.isArray(priceStreamList.value)
|
||||
? (priceStreamList.value as unknown as Product[])
|
||||
: []
|
||||
const inventoryMap = new Map((inventoryRows || []).map((r) => [r.id, r]))
|
||||
|
||||
const physicalStream = streamList.filter(
|
||||
(p) => Boolean(p.has_physical_delivery) && p.title !== 'آبشده نقدی'
|
||||
)
|
||||
|
||||
const list: PInventory[] = physicalStream.map((p) => {
|
||||
const inv = inventoryMap.get(p.id)
|
||||
return {
|
||||
...p,
|
||||
...(inv || {}),
|
||||
id: p.id,
|
||||
title: p.title,
|
||||
unit: p.unit || inv?.unit || 'عدد',
|
||||
has_physical_delivery: true,
|
||||
min_physical_delivery_quantity: Number(
|
||||
p.min_physical_delivery_quantity ?? inv?.min_physical_delivery_quantity ?? 0
|
||||
),
|
||||
wallet: inv?.wallet ?? {
|
||||
id: p.id,
|
||||
gold: 0,
|
||||
},
|
||||
} as PInventory
|
||||
})
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
function syncItemsFromStream() {
|
||||
const selectedIds = new Set(selectedProducts.value.map((sp) => sp.product.id))
|
||||
const fresh = buildPhysicalDeliveryItems(cachedInventoryRows)
|
||||
baseItems.value = cloneDeep(fresh)
|
||||
items.value = fresh.filter((item) => !selectedIds.has(item.id))
|
||||
}
|
||||
|
||||
watch(
|
||||
() => priceStreamList.value,
|
||||
() => {
|
||||
syncItemsFromStream()
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
async function initProductWallet() {
|
||||
syncItemsFromStream()
|
||||
try {
|
||||
loading.value = true
|
||||
const inventory = (await getProductInventory()).rows.filter(
|
||||
(x) => x.title !== 'آبشده نقدی' && x.wallet?.gold && x.wallet.gold > 0,
|
||||
)
|
||||
items.value = inventory
|
||||
baseItems.value = cloneDeep(inventory)
|
||||
const invRes = await getProductInventory()
|
||||
cachedInventoryRows = invRes?.rows || []
|
||||
syncItemsFromStream()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +186,8 @@ export function useNewPhysicalRequestPage() {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await initProductWallet()
|
||||
syncItemsFromStream()
|
||||
void initProductWallet()
|
||||
await getAddress()
|
||||
})
|
||||
|
||||
|
||||
@@ -6,15 +6,12 @@
|
||||
<div class="dinner-surface p-5 space-y-4">
|
||||
<div class="physical-new-request__picker-row">
|
||||
<div class="physical-new-request__select">
|
||||
<BasicSelect
|
||||
<ProductPicker
|
||||
v-model:value="selectedProduct"
|
||||
:items="items"
|
||||
key-name="id"
|
||||
:show-search="false"
|
||||
value-name="title"
|
||||
size="large"
|
||||
placeholder="لطفا محصول را انتخاب کنید"
|
||||
:has-tooltip="false"
|
||||
placeholder="لطفاً محصول را انتخاب کنید"
|
||||
sheet-title="انتخاب محصول تحویل فیزیکی"
|
||||
allow-clear
|
||||
/>
|
||||
</div>
|
||||
<BasicButton
|
||||
@@ -85,7 +82,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import BasicSelect from '@/components/BasicPacks/BasicSelect.vue'
|
||||
import ProductPicker from '@/components/BasicPacks/ProductPicker.vue'
|
||||
import BasicModal from '@/components/BasicPacks/BasicModal.vue'
|
||||
import DesktopPageTopbar from '@/layouts/components/DesktopPageTopbar.vue'
|
||||
import New_EditAddress from '@/views/base/address/components/New_EditAddress.vue'
|
||||
|
||||
@@ -3,15 +3,12 @@
|
||||
<div class="physical-new-request__toolbar mpage-content">
|
||||
<div class="physical-new-request__picker-row px-3">
|
||||
<div class="physical-new-request__select">
|
||||
<BasicSelect
|
||||
<ProductPicker
|
||||
v-model:value="selectedProduct"
|
||||
:items="items"
|
||||
key-name="id"
|
||||
:show-search="false"
|
||||
value-name="title"
|
||||
size="large"
|
||||
placeholder="لطفا محصول را انتخاب کنید"
|
||||
:has-tooltip="false"
|
||||
placeholder="لطفاً محصول را انتخاب کنید"
|
||||
sheet-title="انتخاب محصول تحویل فیزیکی"
|
||||
allow-clear
|
||||
/>
|
||||
</div>
|
||||
<BasicButton
|
||||
@@ -64,7 +61,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import BasicSelect from '@/components/BasicPacks/BasicSelect.vue'
|
||||
import ProductPicker from '@/components/BasicPacks/ProductPicker.vue'
|
||||
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
|
||||
import New_EditAddress from '@/views/base/address/components/New_EditAddress.vue'
|
||||
import PhysicalReceiveCartRow from '../components/PhysicalReceiveCartRow.vue'
|
||||
|
||||
@@ -24,18 +24,13 @@
|
||||
<BasicIcon icon="vuesax-linear:box-1" size="18" />
|
||||
<span class="truncate">{{ lockedProductTitle || 'محصول ثابت' }}</span>
|
||||
</div>
|
||||
<div v-else class="piggy-create__products">
|
||||
<button
|
||||
v-for="p in products"
|
||||
:key="p.id"
|
||||
type="button"
|
||||
class="piggy-create__product"
|
||||
:class="{ 'piggy-create__product--on': productId === p.id }"
|
||||
@click="productId = p.id"
|
||||
>
|
||||
<BasicIcon icon="vuesax-linear:box-1" size="18" />
|
||||
<span class="min-w-0 truncate">{{ p.title || `محصول ${p.id}` }}</span>
|
||||
</button>
|
||||
<div v-else>
|
||||
<ProductPicker
|
||||
v-model:value="productId"
|
||||
:items="products"
|
||||
placeholder="انتخاب محصول قلک..."
|
||||
sheet-title="انتخاب محصول قلک"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -82,7 +77,8 @@
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import router from '@/router'
|
||||
import { createFund, editFund, getFundById } from '@/api/fund'
|
||||
import { getProducts } from '@/api/products'
|
||||
import { getProductsCatalog, getProductsCatalogRef } from '@/composables/useProductsCatalog'
|
||||
import ProductPicker from '@/components/BasicPacks/ProductPicker.vue'
|
||||
import { useFundUserStore } from '@/store/fundStore'
|
||||
import { useSettingsStore } from '@/store/settingsStore'
|
||||
import { message } from 'ant-design-vue'
|
||||
@@ -94,7 +90,7 @@ const settingsStore = useSettingsStore()
|
||||
const busy = ref(false)
|
||||
const title = ref('پس انداز')
|
||||
const productId = ref<number | undefined>()
|
||||
const products = ref<Product[]>([])
|
||||
const products = ref<Product[]>(getProductsCatalogRef().value || [])
|
||||
const lockedProductTitle = ref('')
|
||||
const presets = [...PIGGY_PRESETS]
|
||||
|
||||
@@ -142,15 +138,17 @@ onMounted(async () => {
|
||||
return
|
||||
}
|
||||
try {
|
||||
busy.value = true
|
||||
const list = await getProducts()
|
||||
if (!products.value.length || editId.value) {
|
||||
busy.value = true
|
||||
}
|
||||
const list = await getProductsCatalog()
|
||||
products.value = Array.isArray(list) ? list : ((list as any)?.rows ?? (list as any)?.data ?? [])
|
||||
if (editId.value) {
|
||||
const fund = await getFundById(editId.value)
|
||||
title.value = fund?.title ?? ''
|
||||
productId.value = fund?.product_id
|
||||
lockedProductTitle.value = fund?.product?.title || ''
|
||||
} else if (products.value.length === 1) {
|
||||
} else if (!productId.value && products.value.length > 0) {
|
||||
productId.value = products.value[0]?.id
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -8,13 +8,12 @@
|
||||
>
|
||||
<div class="flex flex-col gap-4 w-full">
|
||||
<a-form-item :rules="[required()]" label="محصول" name="product_id">
|
||||
<BasicSelect
|
||||
<ProductPicker
|
||||
v-model:value="form.product_id"
|
||||
:items="products"
|
||||
key-name="id"
|
||||
placeholder="آبشده، سکه، نقره و ..."
|
||||
size="large"
|
||||
value-name="title"
|
||||
sheet-title="انتخاب محصول هشدار"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item :rules="[required()]" label="جهت قیمت" name="price_condition">
|
||||
@@ -53,6 +52,7 @@
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
|
||||
import BasicSelect from '@/components/BasicPacks/BasicSelect.vue'
|
||||
import ProductPicker from '@/components/BasicPacks/ProductPicker.vue'
|
||||
import { required } from '@/utils/inputRules'
|
||||
import { usePriceTriggerPageContext } from '../composables/usePriceTriggerPage'
|
||||
|
||||
|
||||
@@ -341,13 +341,23 @@ export function useTvMonitorPage() {
|
||||
return isTvProductPriceInactive(product)
|
||||
}
|
||||
|
||||
function isProductTvBuyInactive(product: Product) {
|
||||
return Number(product.tv_price ?? 0) <= 0
|
||||
}
|
||||
|
||||
function isProductTvSellInactive(product: Product) {
|
||||
return Number(product.tv_sell_price ?? 0) <= 0
|
||||
}
|
||||
|
||||
function productBuyLabel(product: Product) {
|
||||
if (isProductTvInactive(product)) return NO_QUOTE_MESSAGE
|
||||
if (isProductTvBuyInactive(product)) return '—'
|
||||
return formatTvPrice(getTvProductBuyPrice(product))
|
||||
}
|
||||
|
||||
function productSellLabel(product: Product) {
|
||||
if (isProductTvInactive(product)) return NO_QUOTE_MESSAGE
|
||||
if (isProductTvSellInactive(product)) return '—'
|
||||
return formatTvPrice(getTvProductSellPrice(product))
|
||||
}
|
||||
|
||||
@@ -417,6 +427,8 @@ export function useTvMonitorPage() {
|
||||
productWeightLabel,
|
||||
tickerItemLabel,
|
||||
isProductTvInactive,
|
||||
isProductTvBuyInactive,
|
||||
isProductTvSellInactive,
|
||||
productBuyLabel,
|
||||
productSellLabel,
|
||||
liveQuoteLabel,
|
||||
|
||||
@@ -118,17 +118,17 @@
|
||||
<div class="tv-row__prices">
|
||||
<div
|
||||
class="tv-row__price tv-row__price--sell"
|
||||
:class="{ 'tv-row__price--empty': isProductTvInactive(item) }"
|
||||
:class="{ 'tv-row__price--empty': isProductTvBuyInactive(item) }"
|
||||
>
|
||||
<strong>{{ productBuyLabel(item) }}</strong>
|
||||
<em v-if="!isProductTvInactive(item) && productBuyLabel(item) !== '—'">تومان</em>
|
||||
<em v-if="!isProductTvBuyInactive(item) && productBuyLabel(item) !== '—'">تومان</em>
|
||||
</div>
|
||||
<div
|
||||
class="tv-row__price tv-row__price--buy"
|
||||
:class="{ 'tv-row__price--empty': isProductTvInactive(item) }"
|
||||
:class="{ 'tv-row__price--empty': isProductTvSellInactive(item) }"
|
||||
>
|
||||
<strong>{{ productSellLabel(item) }}</strong>
|
||||
<em v-if="!isProductTvInactive(item) && productSellLabel(item) !== '—'">تومان</em>
|
||||
<em v-if="!isProductTvSellInactive(item) && productSellLabel(item) !== '—'">تومان</em>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
@@ -276,6 +276,8 @@ const {
|
||||
productWeightLabel,
|
||||
tickerItemLabel,
|
||||
isProductTvInactive,
|
||||
isProductTvBuyInactive,
|
||||
isProductTvSellInactive,
|
||||
productBuyLabel,
|
||||
productSellLabel,
|
||||
liveQuoteLabel,
|
||||
|
||||
Reference in New Issue
Block a user