Huanyi 3 tygodni temu
rodzic
commit
821dd07fb7

+ 1 - 1
.env.production

@@ -15,7 +15,7 @@ VITE_APP_MONITOR_ADMIN = '/admin/applications'
 VITE_APP_SNAILJOB_ADMIN = '/snail-job'
 
 # 生产环境
-VITE_APP_BASE_API = 'http://8.136.194.143/api'
+VITE_APP_BASE_API = 'http://www.hoomeng.pet/api'
 
 # 是否在打包时开启压缩,支持 gzip 和 brotli
 VITE_BUILD_COMPRESS = gzip

+ 1 - 0
package.json

@@ -8,6 +8,7 @@
   "type": "module",
   "scripts": {
     "dev": "vite serve --mode development",
+    "prod": "vite serve --mode production",
     "build:prod": "vite build --mode production",
     "build:dev": "vite build --mode development",
     "preview": "vite preview",

+ 6 - 4
src/api/system/areaStation/types.ts

@@ -54,10 +54,12 @@ export interface AreaStationVO {
    */
   status: number;
 
-    /**
-     * 子对象
-     */
-    children: AreaStationVO[];
+  /**
+   * 子对象
+   */
+  children: AreaStationVO[];
+
+  parentId: number | string;
 }
 
 export interface AreaStationForm extends BaseEntity {

+ 1 - 0
src/assets/icons/svg/anamaly-upload.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774244269226" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="18830" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024"><path d="M526.925944 110.523209c-212.498742 0-384.763131 172.264389-384.763131 384.763131s172.264389 384.763131 384.763131 384.763131 384.763131-172.264389 384.763131-384.763131S739.424686 110.523209 526.925944 110.523209zM494.184239 211.852012c7.05672-7.566326 16.136515-11.348466 27.237341-11.348466 13.619182 0 23.454178 4.043083 29.507034 12.105712 6.548136 9.587356 9.574053 21.444405 9.078773 35.55989l-9.834996 341.220429c-1.51347 12.613272-4.799306 21.940708-9.834996 27.993564-6.052856 6.560416-13.121855 9.834996-21.184485 9.834996-7.566326 0-13.879102-3.02694-18.914792-9.078773-5.556553-7.057743-8.073886-16.646122-7.566326-28.750811l-9.078773-341.220429C482.57483 233.036497 486.110353 220.930785 494.184239 211.852012zM563.033303 758.863411c-11.100826 11.088546-24.966625 16.645099-41.611723 16.645099-17.153682-0.50756-31.280424-6.312776-42.36897-17.401322-9.587356-11.609409-14.375405-24.459065-14.375405-38.585807 0.496304-16.137539 5.544273-29.754674 15.131629-40.8555 10.592242-10.593266 24.459065-15.888875 41.612747-15.888875 16.137539 0 29.754674 5.296633 40.856523 15.888875 10.591219 11.608386 15.886829 25.226544 15.886829 40.8555C577.657372 735.161592 572.60838 748.272191 563.033303 758.863411z" fill="currentColor" p-id="18831"></path></svg>

+ 1 - 0
src/assets/icons/svg/archieves-management.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774238400188" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6372" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024"><path d="M866.7 521.4c-4.1-4.7-10.1-6.2-16.2-7-5 0.1-9.9 1.8-14 4.8L791 562.8l88.7 87.5 40.1-43.7c4.7-4.1 6.3-9.9 7-16-0.1-6.2-2.8-12-7.4-16.2l-52.7-53z m-291.2-93.7l-257.7-0.2c-28.3 0.6-50.9-23.2-50.6-50.7-0.6-27.8 23.6-49.9 51.7-49.6l257.7 0.2c28.3-0.6 50.9 23.2 50.6 50.7-0.3 27.5-23.6 49.8-51.7 49.6zM472.6 628.6l-154.1-0.6c-28.3 0.6-50.9-23.2-50.6-50.7-0.6-27.8 23.6-49.9 51.7-49.6l153.3 0.3c28.3-0.6 50.8 23.2 50.6 50.7-0.3 27.5-22.6 49.3-50.9 49.9zM693.2 99l-469.7-1.8c-68-0.1-123.6 53.8-124.4 120.4l-1.8 586.3c0 66.8 55 121.3 123.6 122.6l170.5 0.4 0.5-108.5 422.9-422.8 0.1-173.6c2.4-68.9-52.8-122.7-121.7-123zM505.1 839.2l-0.2 87.3 88.9 0.3 258.1-254.3-88.7-87.5-258.1 254.2z m0 0" p-id="6373" fill="currentColor"></path></svg>

Plik diff jest za duży
+ 0 - 0
src/assets/icons/svg/audit-management.svg


+ 1 - 0
src/assets/icons/svg/chain-brand.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774238297079" class="icon" viewBox="0 0 1029 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3070" xmlns:xlink="http://www.w3.org/1999/xlink" width="1029" height="1024"><path d="M1027.583233 830.242636s-101.735397 20.449326-204.49326 41.409885l-137.010484 152.347479-147.235148-250.504244c-8.17973 0.511233-16.359461 1.533699-25.050424 1.5337s-16.870694-0.511233-25.050424-1.5337l-147.235148 250.504244-137.010484-152.347479c-102.757863-21.471792-204.49326-41.409885-204.49326-41.409885l160.015976-272.487269c-25.561658-51.634548-40.898652-109.403894-40.898652-170.240639C119.633158 173.308038 296.008595 0 513.793917 0s394.671992 173.308038 394.671992 387.514728c0 61.347978-14.825761 119.117324-40.898652 170.240639l160.015976 272.487269zM513.793917 160.015976c-124.229656 0-224.942586 100.201697-224.942586 223.92012s100.712931 223.92012 224.942586 223.92012 224.942586-100.201697 224.942586-223.92012-100.712931-223.92012-224.942586-223.92012z m72.083874 250.504244c-2.044933 1.533699-2.556166 4.089865-2.044932 6.134797l20.960559 88.443335c1.533699 5.623565-4.601098 10.224663-9.71343 6.646031l-77.707439-47.544683c-2.044933-1.533699-4.601098-1.533699-6.646031 0l-77.707439 47.544683c-5.112332 2.556166-11.247129-1.533699-9.713429-6.646031l20.960559-88.443335c0.511233-2.044933-0.511233-4.601098-2.044933-6.134797L372.693568 351.217174c-4.601098-3.578632-2.044933-10.735896 3.578632-11.247129l90.9995-7.157264c2.556166-0.511233 4.601098-1.533699 5.623565-4.089865l35.275087-83.842237c2.044933-5.623565 9.71343-5.623565 11.758363 0l35.275087 83.842237c1.022466 2.044933 3.067399 3.578632 5.623565 4.089865l90.999501 7.157264c5.623565 0.511233 8.17973 7.668497 3.578632 11.247129L585.877791 410.52022z" fill="currentColor" p-id="3071"></path></svg>

+ 1 - 0
src/assets/icons/svg/customer-management.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774244120239" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11794" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024"><path d="M502.496 63.136c125.888 0 227.936 100.384 227.936 224.192 0 123.84-102.048 224.224-227.936 224.224-125.888 0-227.936-100.384-227.936-224.224C274.56 163.488 376.64 63.136 502.496 63.136L502.496 63.136zM502.496 63.136c125.888 0 227.936 100.384 227.936 224.192 0 123.84-102.048 224.224-227.936 224.224-125.888 0-227.936-100.384-227.936-224.224C274.56 163.488 376.64 63.136 502.496 63.136L502.496 63.136zM417.024 586.304l189.984 0c162.624 0 294.432 129.632 294.432 289.6l0 18.656c0 63.04-131.84 65.44-294.432 65.44l-189.984 0c-162.624 0-294.432-0.096-294.432-65.44l0-18.656C122.592 715.936 254.4 586.304 417.024 586.304L417.024 586.304zM417.024 586.304" fill="currentColor" p-id="11795"></path></svg>

+ 1 - 0
src/assets/icons/svg/fulfiller-management.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774238417184" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7577" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024"><path d="M776.96 256a42.666667 42.666667 0 0 1 41.514667 32.789333l72.896 306.176a149.333333 149.333333 0 1 1-251.285334 114.176L640 704H384a149.333333 149.333333 0 0 1-298.581333 5.12L85.333333 704V490.666667a21.333333 21.333333 0 0 1 21.333334-21.333334h202.666666c80.554667 0 151.168 42.517333 190.656 106.346667l2.176-0.106667a148.821333 148.821333 0 0 0 72.042667-25.109333l3.882667-2.709333a149.994667 149.994667 0 0 0 24.746666-22.528l3.072-3.562667a149.76 149.76 0 0 0 16.128-23.914667l2.176-4.181333A148.693333 148.693333 0 0 0 640 426.666667v-152.362667l0.192 0.213333A21.333333 21.333333 0 0 1 661.333333 256h115.626667zM234.666667 618.666667a85.333333 85.333333 0 1 0 0 170.666666 85.333333 85.333333 0 0 0 0-170.666666z m554.666666 0a85.333333 85.333333 0 1 0 0 170.666666 85.333333 85.333333 0 0 0 0-170.666666zM362.666667 170.666667a64 64 0 0 1 64 64v106.666666a64 64 0 0 1-64 64H192a64 64 0 0 1-64-64v-106.666666a64 64 0 0 1 64-64h170.666667z m437.333333 0a32 32 0 0 1 0 64h-149.333333a32 32 0 0 1 0-64h149.333333z" fill="currentColor" p-id="7578"></path></svg>

+ 1 - 0
src/assets/icons/svg/fulfiller-pool.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774244208357" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15541" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024"><path d="M853.333333 597.333333h-85.333333v-51.2l-256-256-256 256V768h341.333333v85.333333H170.666667v-298.666666H128l384-384 384 384h-42.666667v42.666666z m-106.666666 128c-34.133333 0-64-29.866667-64-64s29.866667-64 64-64 64 29.866667 64 64-29.866667 64-64 64zM682.666667 725.333333h128l42.666666 42.666667v85.333333h-213.333333v-85.333333l42.666667-42.666667z" fill="currentColor" p-id="15542"></path></svg>

+ 1 - 0
src/assets/icons/svg/level-management.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774244230850" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16639" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024"><path d="M810.666667 789.333333l21.333333 149.333334-149.333333-64-149.333334 64 21.333334-149.333334-106.666667-106.666666 149.333333-21.333334 85.333334-128 85.333333 128 149.333333 21.333334zM448 469.333333a192 192 0 1 1 192-192 192 192 0 0 1-192 192z m0 42.666667h85.333333a199.466667 199.466667 0 0 1 84.266667 40.106667L576 618.666667l-192 42.666666 128 149.333334-23.253333 128H256c-106.666667 0-149.333333-70.613333-149.333333-170.666667s202.666667-256 256-256h85.333333z" p-id="16640" fill="currentColor"></path></svg>

+ 1 - 0
src/assets/icons/svg/merchant-classification.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774245665561" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1708" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M180.256 582.4c28.8 0 52.288-23.488 52.288-52.256 0-28.8-23.52-52.288-52.288-52.288-28.768 0-52.256 23.52-52.256 52.288 0 28.768 23.488 52.256 52.256 52.256z m0 298.656c28.8 0 52.288-23.488 52.288-52.256s-23.52-52.256-52.288-52.256C151.488 776.544 128 800 128 828.8s23.488 52.256 52.256 52.256z m0-597.312c28.8 0 52.288-23.52 52.288-52.288 0-28.768-23.52-52.256-52.288-52.256C151.488 179.2 128 202.688 128 231.456c0 28.8 23.488 52.288 52.256 52.288zM862.944 582.4c28.768 0 52.256-23.488 52.256-52.256 0-28.8-23.488-52.288-52.256-52.288h-512c-28.8 0-52.288 23.52-52.288 52.288 0 28.768 23.52 52.256 52.288 52.256h512z m0 298.656c28.768 0 52.256-23.488 52.256-52.256s-23.488-52.256-52.256-52.256h-512c-28.8 0-52.288 23.488-52.288 52.256s23.52 52.256 52.288 52.256h512zM298.656 231.456c0 28.8 23.52 52.288 52.288 52.288h512c28.768 0 52.256-23.52 52.256-52.288 0-28.768-23.488-52.256-52.256-52.256h-512c-28.8 0-52.288 23.488-52.288 52.256z" p-id="1709" fill="currentColor"></path></svg>

Plik diff jest za duży
+ 0 - 0
src/assets/icons/svg/order-dispatch.svg


Plik diff jest za duży
+ 0 - 0
src/assets/icons/svg/order-list.svg


+ 1 - 0
src/assets/icons/svg/order-management.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774238437887" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8691" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024"><path d="M634.88 969.728H348.16v-81.92h286.72c177.152 0 239.616-155.648 239.616-301.056v-450.56H267.264v514.048h-81.92V136.192c0-45.056 36.864-81.92 81.92-81.92h608.256c45.056 0 81.92 36.864 81.92 81.92v449.536C957.44 819.2 830.464 969.728 634.88 969.728z" fill="currentColor" p-id="8692"></path><path d="M629.76 969.728h-399.36c-90.112 0-163.84-62.464-163.84-138.24v-49.152c0-76.8 73.728-138.24 163.84-138.24h402.432v81.92H230.4c-44.032 0-81.92 25.6-81.92 56.32v49.152c0 29.696 37.888 56.32 81.92 56.32h399.36v81.92zM717.824 328.704H423.936c-22.528 0-40.96-18.432-40.96-40.96s18.432-40.96 40.96-40.96h293.888c22.528 0 40.96 18.432 40.96 40.96s-18.432 40.96-40.96 40.96zM641.024 503.808H423.936c-22.528 0-40.96-18.432-40.96-40.96s18.432-40.96 40.96-40.96h217.088c22.528 0 40.96 18.432 40.96 40.96s-18.432 40.96-40.96 40.96z" fill="currentColor" p-id="8693"></path><path d="M632.832 951.296c-84.992 0-154.624-69.632-154.624-154.624s69.632-154.624 154.624-154.624 154.624 69.632 154.624 154.624-69.632 154.624-154.624 154.624z m0-226.304c-39.936 0-72.704 32.768-72.704 72.704s32.768 72.704 72.704 72.704c39.936 0 72.704-32.768 72.704-72.704s-32.768-72.704-72.704-72.704z" fill="currentColor" p-id="8694"></path></svg>

+ 1 - 0
src/assets/icons/svg/pet-management.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774244149150" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13110" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024"><path d="M314.9824 571.35104c78.2336-17.24416 103.2192-87.28576 68.9152-166.4-13.55776-31.3344-68.28032-138.69056-90.7264-182.59968-12.14464 10.19904-22.17984 21.9136-29.22496 34.93888-26.74688 49.27488-28.59008 158.65856-42.06592 295.23968 24.3712 16.1792 55.7056 27.01312 93.10208 18.8416z m558.98112-184.79104a31.47776 31.47776 0 0 0-34.67264-30.18752c-30.35136 3.072-77.08672 3.072-116.9408-17.08032-65.1264-32.99328-37.0688-80.60928-90.8288-130.8672-54.4768-50.93376-194.21184-56.48384-288.01024-16.26112 36.78208 74.71104 90.7264 186.20416 103.64928 222.28992 37.15072 104.18176-20.31616 188.8256-109.11744 215.67488-52.0192 15.7696-93.02016 7.22944-123.71968-9.216a2106.1632 2106.1632 0 0 1-9.07264 63.95904c-9.58464 60.2112-22.4256 110.08-35.10272 149.42208a59.55584 59.55584 0 0 0 57.89696 92.93824l0.53248 0.512h416.23552c0.96256 0.1024 2.02752 0.18432 2.99008 0.18432a35.75808 35.75808 0 0 0 31.86688-51.9168 237.85472 237.85472 0 0 0-97.50528-139.38688c1.8432-39.07584 10.99776-74.97728 33.25952-98.57024 46.36672-49.19296 162.97984-12.67712 226.24256-96.09216 31.15008-41.2672 33.8944-112.64 32.29696-155.40224z m-292.2496 15.29856a45.01504 45.01504 0 0 1-44.9536-45.056c0-24.90368 20.15232-45.056 44.9536-45.056 24.82176 0 44.97408 20.15232 44.97408 45.056 0 24.90368-20.15232 45.056-44.97408 45.056z" fill="currentColor" p-id="13111"></path></svg>

+ 1 - 0
src/assets/icons/svg/platform-purchase.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774244299057" class="icon" viewBox="0 0 1112 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="19905" xmlns:xlink="http://www.w3.org/1999/xlink" width="1112" height="1024"><path d="M1112.702976 772.388571V81.92A105.325714 105.325714 0 0 0 1013.22869 0h-936.228571a111.177143 111.177143 0 0 0-58.514286 46.811429A128.731429 128.731429 0 0 0 0.931547 128.731429v643.657142a111.177143 111.177143 0 0 0 46.811429 87.771429 175.542857 175.542857 0 0 0 76.068571 11.702857h392.045715v76.068572H211.582976a35.108571 35.108571 0 0 0-35.108571 35.108571 40.96 40.96 0 0 0 35.108571 40.96h690.468571a40.96 40.96 0 0 0 35.108572-40.96 35.108571 35.108571 0 0 0-35.108572-35.108571h-304.274285v-76.068572h444.708571a99.474286 99.474286 0 0 0 70.217143-99.474286zM100.405833 76.068571z m-11.702857 5.851429z m0 0z m-5.851429 702.171429z m5.851429 5.851428z m942.08-11.702857v11.702857H77.000119V99.474286h5.851428a5.851429 5.851429 0 0 0 5.851429-5.851429h947.931429v678.765714h-5.851429z" p-id="19906" fill="currentColor"></path><path d="M416.382976 397.897143a40.96 40.96 0 0 0-40.96 40.96 40.96 40.96 0 0 0 81.92 0 40.96 40.96 0 0 0-40.96-40.96zM556.817262 397.897143a40.96 40.96 0 0 0-40.96 40.96 40.96 40.96 0 0 0 81.92 0 40.96 40.96 0 0 0-40.96-40.96zM697.251547 397.897143a40.96 40.96 0 0 0-40.96 40.96 40.96 40.96 0 0 0 81.92 0 40.96 40.96 0 0 0-40.96-40.96z" p-id="19907" fill="currentColor"></path></svg>

+ 1 - 0
src/assets/icons/svg/service-list.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774244079385" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10702" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024"><path d="M163.2 654.08a378.88 378.88 0 0 0 12.16-97.92V448a181.76 181.76 0 0 1 357.76-45.44 32 32 0 1 0 64-16 245.12 245.12 0 0 0-209.28-180.48 31.36 31.36 0 0 0 0-3.84 33.28 33.28 0 0 0-64 0 31.36 31.36 0 0 0 0 5.12A245.12 245.12 0 0 0 112 448v108.16A228.48 228.48 0 0 1 69.76 707.2a31.36 31.36 0 0 0-7.04 11.52 71.68 71.68 0 0 0-12.8 38.4c0 87.04 154.24 132.48 307.2 132.48s307.2-45.44 307.2-132.48c0-126.72-323.84-160.64-501.12-103.04z m192 171.52c-158.08 0-243.2-48.64-243.2-68.48a14.72 14.72 0 0 1 3.2-7.68 307.2 307.2 0 0 1 174.72-55.04 64 64 0 0 0 0 11.52 64 64 0 1 0 128 0 64 64 0 0 0 0-11.52c117.76 10.24 180.48 48.64 180.48 64s-86.4 67.2-241.28 67.2z m583.68-499.84a32 32 0 0 0-32-32H666.24a32 32 0 0 0 0 64h240.64a32 32 0 0 0 32-32z m-32 167.68H737.92a32 32 0 0 0 0 64h168.96a32 32 0 0 0 0-64z m0 199.04H786.56a32 32 0 0 0 0 64h120.32a32 32 0 0 0 0-64z" fill="currentColor" p-id="10703"></path></svg>

Plik diff jest za duży
+ 0 - 0
src/assets/icons/svg/service-management.svg


Plik diff jest za duży
+ 0 - 0
src/assets/icons/svg/store-info.svg


+ 1 - 0
src/assets/icons/svg/store-management.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774238324639" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4190" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024"><path d="M871.850667 469.333333c-72.618667 0-125.184-38.186667-125.184-85.333333 0 47.146667-52.650667 85.333333-125.141334 85.333333C564.565333 469.333333 512 431.146667 512 384c0 47.189333-52.650667 85.333333-109.482667 85.333333C329.898667 469.333333 277.333333 431.146667 277.333333 384c0 47.104-52.650667 85.333333-109.482666 85.333333-32.512 0-61.013333-7.637333-82.517334-20.309333v489.344A42.624 42.624 0 0 0 127.658667 981.333333H554.666667v-255.872A42.666667 42.666667 0 0 1 597.333333 682.666667h128c23.594667 0 42.666667 18.688 42.666667 42.794666V981.333333h128.384c22.869333 0 42.24-19.242667 42.24-42.965333v-487.68a129.194667 129.194667 0 0 1-66.773333 18.645333M840.533333 74.666667c-5.632-15.744-34.858667-32-62.592-32H246.016c-27.946667 0-57.045333 16.256-62.549333 32L42.666667 298.666667c0 47.189333 52.522667 85.333333 125.141333 85.333333C224.64 384 277.333333 345.770667 277.333333 298.666667c0 47.146667 52.522667 85.333333 125.141334 85.333333C459.306667 384 512 345.856 512 298.666667c0 47.146667 52.522667 85.333333 109.482667 85.333333 72.533333 0 125.184-38.186667 125.184-85.333333 0 47.146667 52.522667 85.333333 125.141333 85.333333C928.64 384 981.333333 345.770667 981.333333 298.666667l-140.8-224z" fill="currentColor" p-id="4191"></path></svg>

+ 1 - 0
src/assets/icons/svg/tag-management.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774244167111" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14175" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024"><path d="M932.987763 96 720.625878 96C670.569149 96 600.654688 124.958956 565.258512 160.355132L208.570182 517.043462C173.175902 552.437741 173.175902 610.357549 208.570182 645.753725L474.246275 911.426026C509.640554 946.822202 567.560362 946.822202 602.956538 911.426026L959.641075 554.741488C995.041043 519.345312 1024 449.430851 1024 399.374122L1024 187.012236C1024 136.955506 983.044493 96 932.987763 96L932.987763 96ZM811.638115 399.374122C761.372816 399.374122 720.625878 358.627184 720.625878 308.361884 720.625878 258.096585 761.372816 217.349648 811.638115 217.349648 861.903414 217.349648 902.650352 258.096585 902.650352 308.361884 902.650352 358.627184 861.903414 399.374122 811.638115 399.374122L811.638115 399.374122ZM74.653261 602.847142 399.242714 927.436595C364.862842 945.60112 321.065098 940.273114 292.221804 911.426026L26.54571 645.753725C-8.84857 610.357549-8.84857 552.437741 26.54571 517.043462L383.234038 160.355132C418.630214 124.958956 488.544678 96 538.601408 96L74.653261 559.94625C62.8558 571.745606 62.8558 591.049683 74.653261 602.847142L74.653261 602.847142Z" p-id="14176"></path></svg>

+ 2 - 2
src/components/CustomerDetailDrawer/index.vue

@@ -123,7 +123,7 @@ import { ref, computed, watch, onMounted, getCurrentInstance, toRefs } from 'vue
 import { getCustomer } from '@/api/archieves/customer';
 import { listPetByUser } from '@/api/archieves/pet';
 import { listAllChangeLog } from '@/api/archieves/changeLog';
-import { listOnStore } from '@/api/system/areaStation';
+import { listAreaStation } from '@/api/system/areaStation';
 import { listSubOrderOnCustomer } from '@/api/order/subOrder/index';
 import { listAllService } from '@/api/service/list/index';
 
@@ -187,7 +187,7 @@ const getStatusTagType = (status) => {
 
 const loadAreaStation = async () => {
   if (allNodes.value.length === 0) {
-    const res = await listOnStore();
+    const res = await listAreaStation();
     allNodes.value = res.data || [];
   }
 };

+ 64 - 44
src/views/archieves/customer/index.vue

@@ -6,12 +6,9 @@
         <div class="card-header">
           <span class="title">用户管理</span>
           <div class="header-actions">
-            <el-select v-model="searchForm.areaId" placeholder="所属区域" style="width: 150px; margin-right: 10px" clearable @change="onSearchAreaChange">
-              <el-option v-for="area in areaList" :key="area.id" :label="area.name" :value="area.id" />
-            </el-select>
-            <el-select v-model="searchForm.stationId" placeholder="所属站点" style="width: 150px; margin-right: 10px" clearable @change="handleSearch">
-              <el-option v-for="station in filteredStationList" :key="station.id" :label="station.name" :value="station.id" />
-            </el-select>
+            <el-cascader v-model="searchRegionValue" :options="areaCascaderOptions"
+                         :props="{ checkStrictly: true, value: 'id', label: 'name' }"
+                         placeholder="所属站点" style="width: 350px; margin-right: 10px" clearable @change="handleSearchRegionChange" />
             <el-input v-model="searchForm.keyword" placeholder="搜索姓名/手机号" style="width: 200px; margin-right: 10px;" clearable @keyup.enter="handleSearch" @clear="handleSearch" />
             <el-button type="primary" icon="Plus" @click="handleAdd" v-hasPermi="['archieves:customer:add']">新增用户</el-button>
           </div>
@@ -119,6 +116,9 @@
       @pet-delete="handlePetDelete"
     />
 
+    <!-- Pet Profile Drawer -->
+    <pet-detail-drawer v-model:visible="petDrawerVisible" :pet-id="selectedPetId" editable @remark-saved="getList" />
+
     <!-- Add/Edit User Dialog -->
     <el-dialog v-model="dialogVisible" :title="isEdit ? '编辑用户' : '新增用户'" width="700px" destroy-on-close>
       <el-form :model="form" label-width="90px" class="user-form">
@@ -140,17 +140,11 @@
 <!--                          @visible-change="handleBrandVisibleChange" />-->
 <!--            </el-form-item>-->
 <!--          </el-col>-->
-          <el-col :span="12">
-            <el-form-item label="所属区域">
-              <el-cascader v-model="formAreaValue" :options="areaTreeOptions" placeholder="请选择区域"
-                           style="width: 100%" clearable @change="handleFormAreaChange" />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
+          <el-col :span="24">
             <el-form-item label="所属站点">
-              <el-select v-model="form.stationId" style="width: 100%" filterable placeholder="请选择站点" clearable :disabled="!form.areaId">
-                <el-option v-for="station in formStationList" :key="station.id" :label="station.name" :value="station.id" />
-              </el-select>
+              <el-cascader v-model="formAreaValue" :options="areaTreeOptions" placeholder="请选择站点"
+                           :props="{ checkStrictly: true, value: 'value', label: 'label' }"
+                           style="width: 100%" clearable @change="handleFormAreaChange" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -385,11 +379,12 @@ import { listCustomer, getCustomer, addCustomer, updateCustomer, delCustomer, ch
 import { listAllTag } from '@/api/archieves/tag'
 import { listPetByUser, addPet, updatePet, delPet } from '@/api/archieves/pet'
 import { listAllChangeLog } from '@/api/archieves/changeLog'
-import { listOnStore } from '@/api/system/areaStation'
+import { listAreaStation } from '@/api/system/areaStation'
 import { listOnStore as listBrandOnStore } from '@/api/system/tenant'
 import { regionData, codeToText } from 'element-china-area-data'
 import PageSelect from '@/components/PageSelect/index.vue'
 import CustomerDetailDrawer from '@/components/CustomerDetailDrawer/index.vue'
+import PetDetailDrawer from '@/components/PetDetailDrawer/index.vue'
 import { useUserStore } from '@/store/modules/user'
 
 const userStore = useUserStore()
@@ -403,32 +398,43 @@ const submitLoading = ref(false)
 const total = ref(0)
 
 const allNodes = ref([])
-const areaList = computed(() => allNodes.value.filter(n => n.type === 1))
-const filteredStationList = computed(() => {
-  const areaId = searchForm.areaId
-  const stations = allNodes.value.filter(n => n.type === 2)
-  if (areaId) {
-    return stations.filter(s => s.parentId === areaId)
-  }
-  return stations
-})
-const formStationList = computed(() => {
-  const areaId = form.areaId
-  const stations = allNodes.value.filter(n => n.type === 2)
-  if (areaId) {
-    return stations.filter(s => s.parentId === areaId)
+const searchRegionValue = ref([])
+
+const areaCascaderOptions = computed(() => {
+  const buildTree = (data, parentId) => {
+    return data
+      .filter(item => String(item.parentId) === String(parentId))
+      .map(item => {
+        const children = buildTree(data, item.id)
+        const node = { id: item.id, name: item.name }
+        if (children.length > 0) node.children = children
+        return node
+      })
   }
-  return stations
+  return buildTree(allNodes.value, 0)
 })
 
 const loadAreaStation = () => {
-  listOnStore().then((res) => {
+  listAreaStation().then((res) => {
     allNodes.value = res.data || []
   })
 }
 
-const onSearchAreaChange = () => {
-  searchForm.stationId = undefined
+const handleSearchRegionChange = (value) => {
+  if (value && value.length > 0) {
+    const lastId = value[value.length - 1]
+    const node = allNodes.value.find(n => String(n.id) === String(lastId))
+    if (node && String(node.type) === '2') {
+      searchForm.stationId = lastId
+      searchForm.areaId = node.parentId
+    } else {
+      searchForm.areaId = lastId
+      searchForm.stationId = undefined
+    }
+  } else {
+    searchForm.areaId = undefined
+    searchForm.stationId = undefined
+  }
   handleSearch()
 }
 
@@ -468,6 +474,8 @@ const customerDetailRef = ref(null)
 const userAvatarDisplayUrl = ref('')
 const petAvatarDisplayUrl = ref('')
 const petVaccineCertDisplayUrl = ref('')
+const petDrawerVisible = ref(false)
+const selectedPetId = ref(null)
 
 const brandList = ref([])
 const brandTotal = ref(0)
@@ -546,16 +554,26 @@ const areaTreeOptions = computed(() => {
         return node
       })
   }
-  const areaData = allNodes.value.filter(n => n.type === 0 || n.type === 1)
+  const areaData = allNodes.value
   return buildTree(areaData, 0)
 })
 
 const handleFormAreaChange = (value) => {
-  form.stationId = undefined
   if (value && value.length > 0) {
-    form.areaId = value[value.length - 1]
+    const lastId = value[value.length - 1]
+    const node = allNodes.value.find(n => String(n.id) === String(lastId))
+    if (node) {
+      if (String(node.type) === '2') {
+        form.stationId = lastId
+        form.areaId = node.parentId
+      } else {
+        form.areaId = lastId
+        form.stationId = undefined
+      }
+    }
   } else {
     form.areaId = undefined
+    form.stationId = undefined
   }
 }
 
@@ -638,12 +656,13 @@ const handleEdit = (row) => {
     })
     userAvatarDisplayUrl.value = data.avatarUrl || ''
     // Restore area cascader value path
-    if (data.areaId) {
+    const targetId = data.stationId || data.areaId
+    if (targetId) {
       const findPath = (nodes, targetId, path = []) => {
         for (const node of nodes) {
           const currentPath = [...path, node.id]
-          if (node.id === targetId) return currentPath
-          const children = allNodes.value.filter(n => (n.type === 0 || n.type === 1) && String(n.parentId) === String(node.id))
+          if (String(node.id) === String(targetId)) return currentPath
+          const children = allNodes.value.filter(n => String(n.parentId) === String(node.id))
           if (children.length > 0) {
             const result = findPath(children, targetId, currentPath)
             if (result) return result
@@ -651,8 +670,8 @@ const handleEdit = (row) => {
         }
         return null
       }
-      const roots = allNodes.value.filter(n => (n.type === 0 || n.type === 1) && String(n.parentId) === '0')
-      formAreaValue.value = findPath(roots, data.areaId) || []
+      const roots = allNodes.value.filter(n => String(n.parentId) === '0')
+      formAreaValue.value = findPath(roots, targetId) || []
     } else {
       formAreaValue.value = []
     }
@@ -851,7 +870,8 @@ const openAddPet = () => {
 }
 
 const handlePetDetail = (row) => {
-  ElMessage.info(`查看宠物 [${row.name}] 详情`)
+  selectedPetId.value = row.id;
+  petDrawerVisible.value = true;
 }
 
 const handlePetEdit = (row) => {

+ 146 - 112
src/views/merchant/storeManagement/index.vue

@@ -6,11 +6,9 @@
       <div class="search-actions">
         <el-input v-model="queryParams.storeOrContact" placeholder="搜索门店名称/联系人" prefix-icon="Search"
                   class="search-input" clearable @keyup.enter="handleQuery" @clear="handleQuery" />
-        <el-cascader v-model="searchRegionValue" :options="areaOptions" placeholder="所属城市"
-                     class="filter-cascader" clearable @change="handleSearchAreaChange" />
-        <el-select v-model="queryParams.station" placeholder="所属站点" class="filter-select" clearable @change="handleQuery">
-          <el-option v-for="site in searchSiteOptions" :key="site.value" :label="site.label" :value="site.value" />
-        </el-select>
+        <el-cascader v-model="searchRegionValue" :options="areaOptions"
+                     :props="{ checkStrictly: true, value: 'id', label: 'name' }"
+                     placeholder="所属站点" class="filter-cascader" style="width: 350px" clearable @change="handleSearchAreaChange" />
         <el-select v-model="queryParams.status" placeholder="状态" class="filter-select-mini" clearable @change="handleQuery">
           <el-option v-for="item in statusList" :key="item.value" :label="item.label" :value="item.value" />
         </el-select>
@@ -66,8 +64,7 @@
           </template>
         </el-table-column>
 
-        <!-- 归属区域/站点 -->
-        <el-table-column label="归属区域/站点" align="left" width="180">
+        <el-table-column label="所属站点" align="left" width="180">
           <template #default="scope">
             <div class="location-info">
               <div class="area-name">{{ getRegionNameBySite(scope.row.site) }}</div>
@@ -200,21 +197,12 @@
                           style="width: 100%">
           </el-date-picker>
         </el-form-item>
-        <el-row :gutter="10">
-          <el-col :span="12">
-            <el-form-item label="所在区域" prop="regionId">
-              <el-cascader v-model="regionValue" :options="areaOptions" placeholder="选择区域" style="width: 100%"
-                           @change="handleAreaChange" />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="归属站点" prop="site">
-              <el-select v-model="form.site" placeholder="选择站点" :disabled="!form.regionId">
-                <el-option v-for="site in siteOptions" :key="site.value" :label="site.label" :value="site.value" />
-              </el-select>
-            </el-form-item>
-          </el-col>
-        </el-row>
+        <el-form-item label="所属站点" prop="site">
+          <el-cascader v-model="regionValue" :options="areaOptions" 
+                       :props="{ value: 'id', label: 'name' }"
+                       placeholder="请选择所属站点" style="width: 100%"
+                       @change="handleAreaChange" />
+        </el-form-item>
         <el-form-item label="详细地址">
           <el-row :gutter="10" style="margin-bottom: 10px">
             <el-col :span="24">
@@ -260,8 +248,7 @@
             <el-descriptions-item label="有效期至">{{ parseTime(detailData.validity, '{y}-{m}-{d}') }}</el-descriptions-item>
             <el-descriptions-item label="联系人">{{ detailData.contact }}</el-descriptions-item>
             <el-descriptions-item label="联系电话">{{ detailData.contactNumber }}</el-descriptions-item>
-            <el-descriptions-item label="所在区域">{{ getRegionNameBySite(detailData.site) }}</el-descriptions-item>
-            <el-descriptions-item label="归属站点">{{ detailData.siteName }}</el-descriptions-item>
+            <el-descriptions-item label="所属站点">{{ detailData.siteName }}</el-descriptions-item>
             <el-descriptions-item label="详细地址">{{ detailData.detailAddress }}</el-descriptions-item>
             <el-descriptions-item label="营业执照">
               <image-preview v-if="detailData.businessLicenseUrl" :src="detailData.businessLicenseUrl" :width="80" :height="60" />
@@ -334,8 +321,8 @@ import { listOnStore as listTenantCategoriesOnStore } from '@/api/system/tenantC
 import { listAllService as listServiceOnStore } from '@/api/service/list';
 import { listSubOrderOnStore } from '@/api/order/subOrder';
 import { SubOrderStoreVO } from '@/api/order/subOrder/types';
-import { listOnStore as listAreaStationOnStore } from '@/api/system/areaStation';
-import { SysAreaStationOnStoreVo } from '@/api/system/areaStation/types';
+import { listAreaStation } from '@/api/system/areaStation';
+import { AreaStationVO } from '@/api/system/areaStation/types';
 import { regionData, codeToText, textToCode } from 'element-china-area-data';
 import PageSelect from '@/components/PageSelect/index.vue';
 import { useUserStore } from '@/store/modules/user';
@@ -362,21 +349,19 @@ const searchSiteOptions = ref<any[]>([]); // 搜索的站点选项
 
 /** 处理搜索区域选择变化 */
 const handleSearchAreaChange = (value: any[]) => {
-  // 清空级联站点
-  queryParams.value.station = undefined;
-
   if (value && value.length > 0) {
-    const areaId = value[value.length - 1];
-    queryParams.value.area = areaId;
-    searchSiteOptions.value = areaStationList.value
-      .filter((item: any) => String(item.type) === '2' && String(item.parentId) === String(areaId))
-      .map((item: any) => ({
-        value: String(item.id),
-        label: item.name
-      }));
+    const lastId = value[value.length - 1];
+    const node = areaStationList.value.find(item => String(item.id) === String(lastId));
+    if (node && String(node.type) === '2') {
+      queryParams.value.station = lastId;
+      queryParams.value.area = node.parentId;
+    } else {
+      queryParams.value.area = lastId;
+      queryParams.value.station = undefined;
+    }
   } else {
     queryParams.value.area = undefined;
-    searchSiteOptions.value = [];
+    queryParams.value.station = undefined;
   }
   handleQuery();
 };
@@ -397,7 +382,7 @@ const serviceList = ref<any[]>([]); // 服务项目列表
 const statusList = ref<StoreStatusVO[]>([]); // 状态列表
 const tenantCategoriesList = ref<any[]>([]); // 商户分类列表
 const tenantCategoriesTotal = ref(0); // 商户分类总数
-const areaStationList = ref<SysAreaStationOnStoreVo[]>([]); // 区域站点列表
+const areaStationList = ref<AreaStationVO[]>([]); // 区域站点列表
 const areaOptions = ref<any[]>([]); // 所在区域树形选项
 const siteOptions = ref<any[]>([]); // 归属站点选项
 
@@ -656,8 +641,9 @@ const handleSelectionChange = (selection: StoreVO[]) => {
 
 /** 新增按钮操作 */
 const handleAdd = () => {
-  if (!areaOptions.value || areaOptions.value.length === 0) {
-    proxy?.$modal.msgWarning("请先配置区域站点");
+  const hasStation = areaStationList.value.some((item: any) => String(item.type) === '2');
+  if (!hasStation) {
+    proxy?.$modal.msgWarning("请先在区域站点中配置类型为“站点”的数据");
     return;
   }
   reset();
@@ -690,30 +676,23 @@ const handleUpdate = async (row?: StoreVO) => {
 
   if (res.data.site) {
     form.value.site = String(res.data.site);
+    const path: any[] = [];
+    let currentId = res.data.site;
+    while (currentId && String(currentId) !== '0') {
+      path.unshift(String(currentId));
+      const node = areaStationList.value.find((item: any) => String(item.id) === String(currentId));
+      if (node) {
+        currentId = node.parentId;
+      } else {
+        break;
+      }
+    }
+    regionValue.value = path;
+    
+    // 设置 regionId
     const siteData = areaStationList.value.find((item: any) => String(item.id) === String(res.data.site));
     if (siteData) {
-      const regionId = siteData.parentId;
-      form.value.regionId = String(regionId);
-
-      const path: any[] = [];
-      let currentId = regionId;
-      while (currentId && String(currentId) !== '0') {
-        path.unshift(String(currentId));
-        const currentArea = areaStationList.value.find((item: any) => String(item.id) === String(currentId));
-        if (currentArea) {
-          currentId = currentArea.parentId;
-        } else {
-          break;
-        }
-      }
-      regionValue.value = path;
-
-      siteOptions.value = areaStationList.value
-        .filter((item: any) => String(item.type) === '2' && String(item.parentId) === String(regionId))
-        .map((item: any) => ({
-          value: String(item.id),
-          label: item.name
-        }));
+      form.value.regionId = String(siteData.parentId);
     }
   }
 
@@ -754,36 +733,76 @@ const handleExport = () => {
   }, `store_${new Date().getTime()}.xlsx`)
 }
 
-/** 获取经纬度 */
+/** 高德地图 Key 配置 */
+const amapKey = 'a30e76f457c14b6570925522be37565d';
+const securityJsCode = '531ae14ec1dff87e552e1ea51e848582';
+
+/** 动态加载高德地图脚本 */
+const loadAMapScript = (): Promise<any> => {
+  // 设置安全密钥
+  (window as any)._AMapSecurityConfig = {
+    securityJsCode: securityJsCode,
+  };
+  return new Promise((resolve, reject) => {
+    if ((window as any).AMap) {
+      resolve((window as any).AMap);
+      return;
+    }
+    const script = document.createElement('script');
+    script.src = `https://webapi.amap.com/maps?v=2.0&key=${amapKey}`;
+    script.onload = () => resolve((window as any).AMap);
+    script.onerror = reject;
+    document.head.appendChild(script);
+  });
+};
+
+/** 根据详细地址使用高德地图 Geocoder 获取经纬度 */
 const getGeolocation = () => {
-  if ('geolocation' in navigator) {
-    navigator.geolocation.getCurrentPosition(
-      (position) => {
-        form.value.longitude = position.coords.longitude.toFixed(6);
-        form.value.latitude = position.coords.latitude.toFixed(6);
-        proxy?.$modal.msgSuccess('获取经纬度成功');
-      },
-      (error) => {
-        let errorMessage = '获取位置失败';
-        switch (error.code) {
-          case error.PERMISSION_DENIED:
-            errorMessage = '用户拒绝了地理定位请求';
-            break;
-          case error.POSITION_UNAVAILABLE:
-            errorMessage = '位置信息不可用';
-            break;
-          case error.TIMEOUT:
-            errorMessage = '获取位置超时';
-            break;
-          case error.UNKNOWN_ERROR:
-            errorMessage = '未知错误';
-            break;
+  // 拼接完整地址(省市区 + 详细地址)
+  let areaText = '';
+  if (addressCascaderValue.value && addressCascaderValue.value.length > 0) {
+    areaText = addressCascaderValue.value.map((code: string) => codeToText[code] || '').join('');
+  }
+  const detailAddr = form.value.detailAddress || '';
+  const fullAddress = (areaText + detailAddr).trim();
+
+  if (!fullAddress) {
+    proxy?.$modal.msgWarning('请先填写省市区和详细地址');
+    return;
+  }
+
+  // 确保高德地图脚本已加载
+  const doGeocode = () => {
+    const AMap = (window as any).AMap;
+    if (!AMap) {
+      proxy?.$modal.msgError('高德地图脚本未加载,请稍后重试');
+      return;
+    }
+    AMap.plugin('AMap.Geocoder', () => {
+      const geocoder = new AMap.Geocoder();
+      geocoder.getLocation(fullAddress, (status: string, result: any) => {
+        if (status === 'complete' && result.info === 'OK') {
+          const location = result.geocodes[0]?.location;
+          if (location) {
+            form.value.longitude = location.lng.toFixed(6);
+            form.value.latitude = location.lat.toFixed(6);
+            proxy?.$modal.msgSuccess('获取经纬度成功');
+          } else {
+            proxy?.$modal.msgError('未能解析到该地址的坐标,请检查地址是否准确');
+          }
+        } else {
+          proxy?.$modal.msgError('地理编码失败:' + (result.info || status));
         }
-        proxy?.$modal.msgError(errorMessage);
-      }
-    );
+      });
+    });
+  };
+
+  if ((window as any).AMap) {
+    doGeocode();
   } else {
-    proxy?.$modal.msgError('您的浏览器不支持地理定位');
+    loadAMapScript().then(() => doGeocode()).catch(() => {
+      proxy?.$modal.msgError('高德地图加载失败,请检查网络');
+    });
   }
 };
 
@@ -821,14 +840,12 @@ const getServiceList = async () => {
 /** 获取区域站点列表 */
 const getAreaStationList = async () => {
   try {
-    const res = await listAreaStationOnStore();
+    const res = await listAreaStation();
     const data = res.data || res;
     areaStationList.value = data;
 
-    // 分离所在区域数据(type为0或1)
-    const areaData = data.filter((item: any) => String(item.type) === '0' || String(item.type) === '1');
-    // 构建树形结构
-    areaOptions.value = buildTree(areaData, 0);
+    // 构建包含所有层级(区域和站点)的树
+    areaOptions.value = buildSearchTree(data, 0);
 
     // 初始化站点数据为空
     siteOptions.value = [];
@@ -837,6 +854,23 @@ const getAreaStationList = async () => {
   }
 };
 
+/** 构建搜索树形结构(包含站点) */
+const buildSearchTree = (data: any[], parentId: any): any[] => {
+  return data
+    .filter(item => String(item.parentId) === String(parentId))
+    .map(item => {
+      const children = buildSearchTree(data, item.id);
+      const res: any = {
+        id: item.id,
+        name: item.name,
+      };
+      if (children && children.length > 0) {
+        res.children = children;
+      }
+      return res;
+    });
+};
+
 /** 构建树形结构 */
 const buildTree = (data: any[], parentId: any): any[] => {
   return data
@@ -853,25 +887,18 @@ const buildTree = (data: any[], parentId: any): any[] => {
 
 /** 处理所在区域选择变化 */
 const handleAreaChange = (value: any[]) => {
-  // 清空归属站点选择
-  form.value.site = undefined;
-
   if (value && value.length > 0) {
-    // 获取最后一级的id
-    const areaId = value[value.length - 1];
-    // 更新regionId
-    form.value.regionId = String(areaId);
-    // 过滤出parentId等于areaId的站点
-    siteOptions.value = areaStationList.value
-      .filter((item: any) => String(item.type) === '2' && String(item.parentId) === String(areaId))
-      .map((item: any) => ({
-        value: String(item.id),
-        label: item.name
-      }));
+    const lastId = value[value.length - 1];
+    form.value.site = lastId;
+    
+    // 找到当前选择节点的父节点作为 regionId (如果需要)
+    const node = areaStationList.value.find(item => String(item.id) === String(lastId));
+    if (node) {
+      form.value.regionId = String(node.parentId);
+    }
   } else {
-    // 如果没有选择区域,清空站点选项和regionId
+    form.value.site = undefined;
     form.value.regionId = undefined;
-    siteOptions.value = [];
   }
 };
 
@@ -1004,6 +1031,10 @@ onMounted(() => {
   getServiceList();
   getAreaStationList();
   getStatusList();
+  // 提前加载高德地图脚本,加快首次地理编码速度
+  loadAMapScript().catch(() => {
+    console.warn('高德地图预加载失败,将在首次使用时重试');
+  });
 });
 </script>
 
@@ -1041,7 +1072,10 @@ onMounted(() => {
   width: 240px;
 }
 
-.filter-cascader, .filter-select {
+.filter-cascader {
+  width: 420px;
+}
+.filter-select {
   width: 150px;
 }
 

+ 2 - 2
src/views/order/management/components/CustomerDetailDrawer.vue

@@ -105,7 +105,7 @@ import { ref, computed, watch, getCurrentInstance, toRefs } from 'vue'
 import { getCustomer } from '@/api/archieves/customer'
 import { listPetByUser } from '@/api/archieves/pet'
 import { listAllChangeLog } from '@/api/archieves/changeLog'
-import { listOnStore } from '@/api/system/areaStation'
+import { listAreaStation } from '@/api/system/areaStation'
 
 const props = defineProps({
   visible: {
@@ -143,7 +143,7 @@ const mockOrders = ref([
 
 const loadAreaStation = async () => {
   if(allNodes.value.length === 0) {
-    const res = await listOnStore()
+    const res = await listAreaStation()
     allNodes.value = res.data || []
   }
 }

+ 2 - 2
src/views/order/management/index.vue

@@ -189,7 +189,7 @@ import RemarkDialog from './components/RemarkDialog.vue';
 import PetDetailDrawer from '@/components/PetDetailDrawer/index.vue';
 import { listAllService } from '@/api/service/list/index';
 import { listSubOrder, dispatchSubOrder, getSubOrderInfo, cancelSubOrder, remarkSubOrder, confirmSubOrder, nursingSummarySubOrder } from '@/api/order/subOrder/index';
-import { listOnStore as listAreaStationOnStore } from '@/api/system/areaStation';
+import { listAreaStation } from '@/api/system/areaStation';
 import { getStore } from '@/api/system/store';
 import { reward } from '@/api/fulfiller/pool';
 import { getPet } from '@/api/archieves/pet';
@@ -233,7 +233,7 @@ const getServiceList = () => {
 };
 
 const getAreaStationList = () => {
-  listAreaStationOnStore().then((res) => {
+  listAreaStation().then((res) => {
     const list = res.data || [];
     areaStationList.value = list;
     const map = {};

+ 30 - 55
src/views/order/purchase/components/AddUserDialog.vue

@@ -10,26 +10,12 @@
         </el-col>
 
         <el-col :span="24"><div class="form-section-header">基本资料</div></el-col>
-        <el-col :span="12">
-          <el-form-item label="录入来源">
-            <PageSelect v-model="form.source"
-              :options="brandList.map(item => ({ value: item.name, label: item.name }))"
-              :total="brandTotal" :pageSize="10" placeholder="请选择所属品牌"
-              @page-change="handleBrandPageChange"
-              @visible-change="handleBrandVisibleChange" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="所属区域">
-            <el-cascader v-model="formAreaValue" :options="areaTreeOptions" placeholder="请选择区域"
-              style="width: 100%" clearable @change="handleFormAreaChange" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
+        <!-- 录入来源不在表单中展示,自动使用当前登录用户的 tenantId,提交时静默传递 -->
+        <el-col :span="24">
           <el-form-item label="所属站点">
-            <el-select v-model="form.stationId" style="width: 100%" filterable placeholder="请选择站点" clearable :disabled="!form.areaId">
-              <el-option v-for="station in formStationList" :key="station.id" :label="station.name" :value="station.id" />
-            </el-select>
+            <el-cascader v-model="formAreaValue" :options="areaTreeOptions" placeholder="请选择站点"
+              :props="{ checkStrictly: true, value: 'value', label: 'label' }"
+              style="width: 100%" clearable @change="handleFormAreaChange" />
           </el-form-item>
         </el-col>
         <el-col :span="12">
@@ -116,10 +102,10 @@ import { ElMessage } from 'element-plus'
 import { globalHeaders } from '@/utils/request'
 import { addCustomerOnOrder } from '@/api/archieves/customer'
 import { listAllTag } from '@/api/archieves/tag'
-import { listOnStore } from '@/api/system/areaStation'
-import { listOnStore as listBrandOnStore } from '@/api/system/tenant'
+import { listAreaStation } from '@/api/system/areaStation'
 import { regionData } from 'element-china-area-data'
 import PageSelect from '@/components/PageSelect/index.vue'
+import { useUserStore } from '@/store/modules/user'
 
 const props = defineProps({
   visible: { type: Boolean, default: false }
@@ -134,9 +120,10 @@ const { sys_user_sex, sys_house_type, sys_entry_method } = toRefs(
 
 const submitLoading = ref(false)
 
+// 获取当前登录用户的 tenantId
+const userStore = useUserStore()
+
 const allNodes = ref([])
-const brandList = ref([])
-const brandTotal = ref(0)
 const allUserTags = ref([])
 
 const formAreaValue = ref([])
@@ -163,7 +150,8 @@ const form = reactive({
   entryMethod: '',
   entryPassword: '',
   keyLocation: '',
-  source: '',
+  // 录入来源默认为当前登录用户的 tenantId
+  tenantId: userStore.tenantId,
   emergencyContact: '',
   emergencyPhone: '',
   memberLevel: 0,
@@ -187,7 +175,9 @@ const resetForm = () => {
   Object.assign(form, {
     name: '', phone: '', avatar: undefined, gender: undefined, birthday: '', idCard: '',
     areaId: undefined, stationId: undefined, regionCode: '', region: [], address: '',
-    houseType: '', entryMethod: '', entryPassword: '', keyLocation: '', source: '',
+    houseType: '', entryMethod: '', entryPassword: '', keyLocation: '',
+    // 重置时依然保留当前 tenantId 作为录入来源
+    tenantId: userStore.tenantId,
     emergencyContact: '', emergencyPhone: '', memberLevel: 0, status: 0, remark: '', tagIds: []
   })
 }
@@ -203,45 +193,30 @@ const areaTreeOptions = computed(() => {
         return node
       })
   }
-  const areaData = allNodes.value.filter(n => n.type === 0 || n.type === 1)
+  const areaData = allNodes.value
   return buildTree(areaData, 0)
 })
 
-const formStationList = computed(() => {
-  const areaId = form.areaId
-  const stations = allNodes.value.filter(n => n.type === 2)
-  if (areaId) {
-    return stations.filter(s => s.parentId === areaId)
-  }
-  return stations
-})
-
 const handleFormAreaChange = (value) => {
-  form.stationId = undefined
   if (value && value.length > 0) {
-    form.areaId = value[value.length - 1]
+    const lastId = value[value.length - 1]
+    const node = allNodes.value.find(n => String(n.id) === String(lastId))
+    if (node) {
+      if (String(node.type) === '2') {
+        form.stationId = lastId
+        form.areaId = node.parentId
+      } else {
+        form.areaId = lastId
+        form.stationId = undefined
+      }
+    }
   } else {
     form.areaId = undefined
+    form.stationId = undefined
   }
 }
 
-const getBrandList = async (pageNum = 1) => {
-  const res = await listBrandOnStore({ pageNum, pageSize: 10 })
-  if (res.code === 200) {
-    brandList.value = res.rows || []
-    brandTotal.value = res.total || 0
-  }
-}
-
-const handleBrandPageChange = (page) => {
-  getBrandList(Number(page))
-}
-
-const handleBrandVisibleChange = (visible) => {
-  if (visible) {
-    getBrandList(1)
-  }
-}
+// 品牌列表相关逻辑已移除,录入来源改为自动使用当前用户 tenantId
 
 const loadTags = () => {
   listAllTag({ category: 'user', status: 0 }).then((res) => {
@@ -250,7 +225,7 @@ const loadTags = () => {
 }
 
 const loadAreaStation = () => {
-  listOnStore().then((res) => {
+  listAreaStation().then((res) => {
     allNodes.value = res.data || []
   })
 }

+ 1 - 0
vite.config.ts

@@ -25,6 +25,7 @@ export default defineConfig(({ mode, command }) => {
       proxy: {
         [env.VITE_APP_BASE_API]: {
           target: 'http://127.0.0.1:8080',
+          // target: 'http://www.hoomeng.pet/api',
           changeOrigin: true,
           ws: true,
           rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików