Compare commits

..

No commits in common. "master" and "custom" have entirely different histories.

55 changed files with 304 additions and 2593 deletions

View File

@ -15,7 +15,6 @@
"dependencies": {
"@ant-design/icons-vue": "^7.0.1",
"@fingerprintjs/fingerprintjs": "^4.4.3",
"@pixi/spine-pixi": "^2.1.0",
"ali-oss": "^6.21.0",
"ant-design-vue": "4.x",
"clsx": "^2.1.1",
@ -25,15 +24,12 @@
"oh-vue-icons": "^1.0.0-rc3",
"pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.3",
"pixi.js": "^8.4.0",
"sortablejs": "^1.15.3",
"ua-parser-js": "^1.0.38",
"uuid": "^10.0.0",
"v-viewer": "^3.0.13",
"viewerjs": "^1.11.6",
"vue": "^3.4.29",
"vue-toastification": "^2.0.0-rc.5",
"vue3-colorpicker": "^2.3.0"
"vue": "^3.4.29"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.8.0",

View File

@ -1,175 +0,0 @@
xiaohuli_aixin.png
size:2048,2048
filter:Linear,Linear
pma:true
0
bounds:2,651,48,55
offsets:1,1,50,57
00
bounds:809,25,141,66
offsets:1,1,143,68
H
bounds:578,168,147,202
offsets:1,1,149,204
I
bounds:727,252,43,126
offsets:1,1,45,128
Left ear
bounds:1098,64,160,186
offsets:11,0,171,186
Left eye
bounds:309,690,30,16
Left eyebrow
bounds:966,1177,24,27
Left forearm
bounds:876,924,75,134
offsets:1,2,77,136
Left upper arm
bounds:344,43,123,164
offsets:11,2,137,167
rotate:90
Right ear
bounds:1545,63,193,253
offsets:0,1,193,254
rotate:90
Right eye
bounds:504,820,55,16
Right eyebrow
bounds:876,1144,38,31
Right leg
bounds:1390,72,164,172
offsets:0,2,164,176
Right leg1
bounds:1251,936,184,214
offsets:2,0,187,217
Right lower arm
bounds:1408,1059,150,140
offsets:0,0,163,142
rotate:90
Right lower arm 副本
bounds:2,31,151,148
offsets:0,0,163,148
rotate:90
Right lower arm 副本 3
bounds:661,46,116,146
rotate:90
Right upper arm
bounds:502,38,128,158
offsets:7,2,136,160
rotate:90
body
bounds:2,305,417,401
offsets:239,0,750,812
bu_youshou1
bounds:1232,68,157,182
offsets:0,0,158,184
bu_youshou2
bounds:1329,2,136,124
offsets:1,27,138,152
bu_zuoshou1
bounds:1799,78,156,165
offsets:2,0,158,165
bu_zuoshou2
bounds:193,54,164,140
offsets:0,0,164,141
rotate:180
face
bounds:876,923,413,286
offsets:2,0,433,286
ground
bounds:2,708,1618,99
offsets:1,1,1620,101
maple leaf
bounds:1426,922,115,90
meimao_y
bounds:52,683,38,23
meimao_z
bounds:876,1177,58,27
mouth
bounds:388,652,49,35
offsets:0,0,50,44
mouth2
bounds:451,814,51,22
mouth3
bounds:726,657,76,49
offsets:1,1,78,51
muzhuang
bounds:2,1193,608,430
offsets:1,1,610,432
qipao
bounds:379,372,89,63
tail
bounds:419,347,398,359
offsets:2,0,400,359
tanhao
bounds:1252,1166,43,153
rotate:90
upper lip
bounds:257,221,83,83
water_03_00005
bounds:451,838,423,353
offsets:1,1,424,354
water_03_00006
bounds:2,814,447,377
offsets:1,1,449,378
water_03_00007
bounds:1550,809,461,402
offsets:1,1,462,404
water_03_00008
bounds:1083,1211,465,412
offsets:1,1,467,414
water_03_00009
bounds:612,1206,469,417
offsets:1,0,471,418
water_03_00010
bounds:1550,1213,461,410
offsets:1,0,463,411
weijin2
bounds:1870,7,109,143
offsets:1,2,112,147
rotate:90
weijin_hou
bounds:727,86,145,392
offsets:0,7,145,401
rotate:90
weijin_q1
bounds:876,822,386,153
offsets:7,5,393,159
weijinq_2
bounds:2,177,129,254
offsets:3,1,133,260
rotate:90
xinfeng
bounds:1361,255,289,175
xinfeng2
bounds:1109,443,285,263
offsets:1,1,287,265
xinfeng3
bounds:819,443,288,263
offsets:1,1,290,265
xinfeng3 副本 2
bounds:1652,258,288,172
offsets:1,1,290,174
xinxin
bounds:819,202,268,239
xinzhi
bounds:1621,432,375,392
rotate:90
yanbai_y
bounds:424,678,35,28
yanbai_z
bounds:350,676,55,30
yantong_y
bounds:561,811,23,25
offsets:1,1,25,27
yantong_z
bounds:936,1177,28,27
offsets:1,1,30,29
z
bounds:343,168,233,202
offsets:1,1,235,204
zhifeiji
bounds:1262,809,238,111
offsets:1,1,240,113
图层 10
bounds:1089,252,270,189

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

View File

@ -1,175 +0,0 @@
xiaohuli_dahulu.png
size:2048,2048
filter:Linear,Linear
pma:true
0
bounds:2,651,48,55
offsets:1,1,50,57
00
bounds:809,25,141,66
offsets:1,1,143,68
H
bounds:578,168,147,202
offsets:1,1,149,204
I
bounds:727,252,43,126
offsets:1,1,45,128
Left ear
bounds:1098,64,160,186
offsets:11,0,171,186
Left eye
bounds:309,690,30,16
Left eyebrow
bounds:966,1177,24,27
Left forearm
bounds:876,924,75,134
offsets:1,2,77,136
Left upper arm
bounds:344,43,123,164
offsets:11,2,137,167
rotate:90
Right ear
bounds:1545,63,193,253
offsets:0,1,193,254
rotate:90
Right eye
bounds:504,820,55,16
Right eyebrow
bounds:876,1144,38,31
Right leg
bounds:1390,72,164,172
offsets:0,2,164,176
Right leg1
bounds:1251,936,184,214
offsets:2,0,187,217
Right lower arm
bounds:1408,1059,150,140
offsets:0,0,163,142
rotate:90
Right lower arm 副本
bounds:2,31,151,148
offsets:0,0,163,148
rotate:90
Right lower arm 副本 3
bounds:661,46,116,146
rotate:90
Right upper arm
bounds:502,38,128,158
offsets:7,2,136,160
rotate:90
body
bounds:2,305,417,401
offsets:239,0,750,812
bu_youshou1
bounds:1232,68,157,182
offsets:0,0,158,184
bu_youshou2
bounds:1329,2,136,124
offsets:1,27,138,152
bu_zuoshou1
bounds:1799,78,156,165
offsets:2,0,158,165
bu_zuoshou2
bounds:193,54,164,140
offsets:0,0,164,141
rotate:180
face
bounds:876,923,413,286
offsets:2,0,433,286
ground
bounds:2,708,1618,99
offsets:1,1,1620,101
maple leaf
bounds:1426,922,115,90
meimao_y
bounds:52,683,38,23
meimao_z
bounds:876,1177,58,27
mouth
bounds:388,652,49,35
offsets:0,0,50,44
mouth2
bounds:451,814,51,22
mouth3
bounds:726,657,76,49
offsets:1,1,78,51
muzhuang
bounds:2,1193,608,430
offsets:1,1,610,432
qipao
bounds:379,372,89,63
tail
bounds:419,347,398,359
offsets:2,0,400,359
tanhao
bounds:1252,1166,43,153
rotate:90
upper lip
bounds:257,221,83,83
water_03_00005
bounds:451,838,423,353
offsets:1,1,424,354
water_03_00006
bounds:2,814,447,377
offsets:1,1,449,378
water_03_00007
bounds:1550,809,461,402
offsets:1,1,462,404
water_03_00008
bounds:1083,1211,465,412
offsets:1,1,467,414
water_03_00009
bounds:612,1206,469,417
offsets:1,0,471,418
water_03_00010
bounds:1550,1213,461,410
offsets:1,0,463,411
weijin2
bounds:1870,7,109,143
offsets:1,2,112,147
rotate:90
weijin_hou
bounds:727,86,145,392
offsets:0,7,145,401
rotate:90
weijin_q1
bounds:876,822,386,153
offsets:7,5,393,159
weijinq_2
bounds:2,177,129,254
offsets:3,1,133,260
rotate:90
xinfeng
bounds:1361,255,289,175
xinfeng2
bounds:1109,443,285,263
offsets:1,1,287,265
xinfeng3
bounds:819,443,288,263
offsets:1,1,290,265
xinfeng3 副本 2
bounds:1652,258,288,172
offsets:1,1,290,174
xinxin
bounds:819,202,268,239
xinzhi
bounds:1621,432,375,392
rotate:90
yanbai_y
bounds:424,678,35,28
yanbai_z
bounds:350,676,55,30
yantong_y
bounds:561,811,23,25
offsets:1,1,25,27
yantong_z
bounds:936,1177,28,27
offsets:1,1,30,29
z
bounds:343,168,233,202
offsets:1,1,235,204
zhifeiji
bounds:1262,809,238,111
offsets:1,1,240,113
图层 10
bounds:1089,252,270,189

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

View File

@ -1,175 +0,0 @@
xiaohuli_dazhaohu.png
size:2048,2048
filter:Linear,Linear
pma:true
0
bounds:2,651,48,55
offsets:1,1,50,57
00
bounds:809,25,141,66
offsets:1,1,143,68
H
bounds:578,168,147,202
offsets:1,1,149,204
I
bounds:727,252,43,126
offsets:1,1,45,128
Left ear
bounds:1098,64,160,186
offsets:11,0,171,186
Left eye
bounds:309,690,30,16
Left eyebrow
bounds:966,1177,24,27
Left forearm
bounds:876,924,75,134
offsets:1,2,77,136
Left upper arm
bounds:344,43,123,164
offsets:11,2,137,167
rotate:90
Right ear
bounds:1545,63,193,253
offsets:0,1,193,254
rotate:90
Right eye
bounds:504,820,55,16
Right eyebrow
bounds:876,1144,38,31
Right leg
bounds:1390,72,164,172
offsets:0,2,164,176
Right leg1
bounds:1251,936,184,214
offsets:2,0,187,217
Right lower arm
bounds:1408,1059,150,140
offsets:0,0,163,142
rotate:90
Right lower arm 副本
bounds:2,31,151,148
offsets:0,0,163,148
rotate:90
Right lower arm 副本 3
bounds:661,46,116,146
rotate:90
Right upper arm
bounds:502,38,128,158
offsets:7,2,136,160
rotate:90
body
bounds:2,305,417,401
offsets:239,0,750,812
bu_youshou1
bounds:1232,68,157,182
offsets:0,0,158,184
bu_youshou2
bounds:1329,2,136,124
offsets:1,27,138,152
bu_zuoshou1
bounds:1799,78,156,165
offsets:2,0,158,165
bu_zuoshou2
bounds:193,54,164,140
offsets:0,0,164,141
rotate:180
face
bounds:876,923,413,286
offsets:2,0,433,286
ground
bounds:2,708,1618,99
offsets:1,1,1620,101
maple leaf
bounds:1426,922,115,90
meimao_y
bounds:52,683,38,23
meimao_z
bounds:876,1177,58,27
mouth
bounds:388,652,49,35
offsets:0,0,50,44
mouth2
bounds:451,814,51,22
mouth3
bounds:726,657,76,49
offsets:1,1,78,51
muzhuang
bounds:2,1193,608,430
offsets:1,1,610,432
qipao
bounds:379,372,89,63
tail
bounds:419,347,398,359
offsets:2,0,400,359
tanhao
bounds:1252,1166,43,153
rotate:90
upper lip
bounds:257,221,83,83
water_03_00005
bounds:451,838,423,353
offsets:1,1,424,354
water_03_00006
bounds:2,814,447,377
offsets:1,1,449,378
water_03_00007
bounds:1550,809,461,402
offsets:1,1,462,404
water_03_00008
bounds:1083,1211,465,412
offsets:1,1,467,414
water_03_00009
bounds:612,1206,469,417
offsets:1,0,471,418
water_03_00010
bounds:1550,1213,461,410
offsets:1,0,463,411
weijin2
bounds:1870,7,109,143
offsets:1,2,112,147
rotate:90
weijin_hou
bounds:727,86,145,392
offsets:0,7,145,401
rotate:90
weijin_q1
bounds:876,822,386,153
offsets:7,5,393,159
weijinq_2
bounds:2,177,129,254
offsets:3,1,133,260
rotate:90
xinfeng
bounds:1361,255,289,175
xinfeng2
bounds:1109,443,285,263
offsets:1,1,287,265
xinfeng3
bounds:819,443,288,263
offsets:1,1,290,265
xinfeng3 副本 2
bounds:1652,258,288,172
offsets:1,1,290,174
xinxin
bounds:819,202,268,239
xinzhi
bounds:1621,432,375,392
rotate:90
yanbai_y
bounds:424,678,35,28
yanbai_z
bounds:350,676,55,30
yantong_y
bounds:561,811,23,25
offsets:1,1,25,27
yantong_z
bounds:936,1177,28,27
offsets:1,1,30,29
z
bounds:343,168,233,202
offsets:1,1,235,204
zhifeiji
bounds:1262,809,238,111
offsets:1,1,240,113
图层 10
bounds:1089,252,270,189

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

View File

@ -1,175 +0,0 @@
xiaohuli_dianji.png
size:2048,2048
filter:Linear,Linear
pma:true
0
bounds:2,651,48,55
offsets:1,1,50,57
00
bounds:809,25,141,66
offsets:1,1,143,68
H
bounds:578,168,147,202
offsets:1,1,149,204
I
bounds:727,252,43,126
offsets:1,1,45,128
Left ear
bounds:1098,64,160,186
offsets:11,0,171,186
Left eye
bounds:309,690,30,16
Left eyebrow
bounds:966,1177,24,27
Left forearm
bounds:876,924,75,134
offsets:1,2,77,136
Left upper arm
bounds:344,43,123,164
offsets:11,2,137,167
rotate:90
Right ear
bounds:1545,63,193,253
offsets:0,1,193,254
rotate:90
Right eye
bounds:504,820,55,16
Right eyebrow
bounds:876,1144,38,31
Right leg
bounds:1390,72,164,172
offsets:0,2,164,176
Right leg1
bounds:1251,936,184,214
offsets:2,0,187,217
Right lower arm
bounds:1408,1059,150,140
offsets:0,0,163,142
rotate:90
Right lower arm 副本
bounds:2,31,151,148
offsets:0,0,163,148
rotate:90
Right lower arm 副本 3
bounds:661,46,116,146
rotate:90
Right upper arm
bounds:502,38,128,158
offsets:7,2,136,160
rotate:90
body
bounds:2,305,417,401
offsets:239,0,750,812
bu_youshou1
bounds:1232,68,157,182
offsets:0,0,158,184
bu_youshou2
bounds:1329,2,136,124
offsets:1,27,138,152
bu_zuoshou1
bounds:1799,78,156,165
offsets:2,0,158,165
bu_zuoshou2
bounds:193,54,164,140
offsets:0,0,164,141
rotate:180
face
bounds:876,923,413,286
offsets:2,0,433,286
ground
bounds:2,708,1618,99
offsets:1,1,1620,101
maple leaf
bounds:1426,922,115,90
meimao_y
bounds:52,683,38,23
meimao_z
bounds:876,1177,58,27
mouth
bounds:388,652,49,35
offsets:0,0,50,44
mouth2
bounds:451,814,51,22
mouth3
bounds:726,657,76,49
offsets:1,1,78,51
muzhuang
bounds:2,1193,608,430
offsets:1,1,610,432
qipao
bounds:379,372,89,63
tail
bounds:419,347,398,359
offsets:2,0,400,359
tanhao
bounds:1252,1166,43,153
rotate:90
upper lip
bounds:257,221,83,83
water_03_00005
bounds:451,838,423,353
offsets:1,1,424,354
water_03_00006
bounds:2,814,447,377
offsets:1,1,449,378
water_03_00007
bounds:1550,809,461,402
offsets:1,1,462,404
water_03_00008
bounds:1083,1211,465,412
offsets:1,1,467,414
water_03_00009
bounds:612,1206,469,417
offsets:1,0,471,418
water_03_00010
bounds:1550,1213,461,410
offsets:1,0,463,411
weijin2
bounds:1870,7,109,143
offsets:1,2,112,147
rotate:90
weijin_hou
bounds:727,86,145,392
offsets:0,7,145,401
rotate:90
weijin_q1
bounds:876,822,386,153
offsets:7,5,393,159
weijinq_2
bounds:2,177,129,254
offsets:3,1,133,260
rotate:90
xinfeng
bounds:1361,255,289,175
xinfeng2
bounds:1109,443,285,263
offsets:1,1,287,265
xinfeng3
bounds:819,443,288,263
offsets:1,1,290,265
xinfeng3 副本 2
bounds:1652,258,288,172
offsets:1,1,290,174
xinxin
bounds:819,202,268,239
xinzhi
bounds:1621,432,375,392
rotate:90
yanbai_y
bounds:424,678,35,28
yanbai_z
bounds:350,676,55,30
yantong_y
bounds:561,811,23,25
offsets:1,1,25,27
yantong_z
bounds:936,1177,28,27
offsets:1,1,30,29
z
bounds:343,168,233,202
offsets:1,1,235,204
zhifeiji
bounds:1262,809,238,111
offsets:1,1,240,113
图层 10
bounds:1089,252,270,189

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

View File

@ -1,175 +0,0 @@
xiaohuli_duxin.png
size:2048,2048
filter:Linear,Linear
pma:true
0
bounds:2,651,48,55
offsets:1,1,50,57
00
bounds:809,25,141,66
offsets:1,1,143,68
H
bounds:578,168,147,202
offsets:1,1,149,204
I
bounds:727,252,43,126
offsets:1,1,45,128
Left ear
bounds:1098,64,160,186
offsets:11,0,171,186
Left eye
bounds:309,690,30,16
Left eyebrow
bounds:966,1177,24,27
Left forearm
bounds:876,924,75,134
offsets:1,2,77,136
Left upper arm
bounds:344,43,123,164
offsets:11,2,137,167
rotate:90
Right ear
bounds:1545,63,193,253
offsets:0,1,193,254
rotate:90
Right eye
bounds:504,820,55,16
Right eyebrow
bounds:876,1144,38,31
Right leg
bounds:1390,72,164,172
offsets:0,2,164,176
Right leg1
bounds:1251,936,184,214
offsets:2,0,187,217
Right lower arm
bounds:1408,1059,150,140
offsets:0,0,163,142
rotate:90
Right lower arm 副本
bounds:2,31,151,148
offsets:0,0,163,148
rotate:90
Right lower arm 副本 3
bounds:661,46,116,146
rotate:90
Right upper arm
bounds:502,38,128,158
offsets:7,2,136,160
rotate:90
body
bounds:2,305,417,401
offsets:239,0,750,812
bu_youshou1
bounds:1232,68,157,182
offsets:0,0,158,184
bu_youshou2
bounds:1329,2,136,124
offsets:1,27,138,152
bu_zuoshou1
bounds:1799,78,156,165
offsets:2,0,158,165
bu_zuoshou2
bounds:193,54,164,140
offsets:0,0,164,141
rotate:180
face
bounds:876,923,413,286
offsets:2,0,433,286
ground
bounds:2,708,1618,99
offsets:1,1,1620,101
maple leaf
bounds:1426,922,115,90
meimao_y
bounds:52,683,38,23
meimao_z
bounds:876,1177,58,27
mouth
bounds:388,652,49,35
offsets:0,0,50,44
mouth2
bounds:451,814,51,22
mouth3
bounds:726,657,76,49
offsets:1,1,78,51
muzhuang
bounds:2,1193,608,430
offsets:1,1,610,432
qipao
bounds:379,372,89,63
tail
bounds:419,347,398,359
offsets:2,0,400,359
tanhao
bounds:1252,1166,43,153
rotate:90
upper lip
bounds:257,221,83,83
water_03_00005
bounds:451,838,423,353
offsets:1,1,424,354
water_03_00006
bounds:2,814,447,377
offsets:1,1,449,378
water_03_00007
bounds:1550,809,461,402
offsets:1,1,462,404
water_03_00008
bounds:1083,1211,465,412
offsets:1,1,467,414
water_03_00009
bounds:612,1206,469,417
offsets:1,0,471,418
water_03_00010
bounds:1550,1213,461,410
offsets:1,0,463,411
weijin2
bounds:1870,7,109,143
offsets:1,2,112,147
rotate:90
weijin_hou
bounds:727,86,145,392
offsets:0,7,145,401
rotate:90
weijin_q1
bounds:876,822,386,153
offsets:7,5,393,159
weijinq_2
bounds:2,177,129,254
offsets:3,1,133,260
rotate:90
xinfeng
bounds:1361,255,289,175
xinfeng2
bounds:1109,443,285,263
offsets:1,1,287,265
xinfeng3
bounds:819,443,288,263
offsets:1,1,290,265
xinfeng3 副本 2
bounds:1652,258,288,172
offsets:1,1,290,174
xinxin
bounds:819,202,268,239
xinzhi
bounds:1621,432,375,392
rotate:90
yanbai_y
bounds:424,678,35,28
yanbai_z
bounds:350,676,55,30
yantong_y
bounds:561,811,23,25
offsets:1,1,25,27
yantong_z
bounds:936,1177,28,27
offsets:1,1,30,29
z
bounds:343,168,233,202
offsets:1,1,235,204
zhifeiji
bounds:1262,809,238,111
offsets:1,1,240,113
图层 10
bounds:1089,252,270,189

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

View File

@ -1,175 +0,0 @@
xiaohuli_shuixing.png
size:2048,2048
filter:Linear,Linear
pma:true
0
bounds:2,651,48,55
offsets:1,1,50,57
00
bounds:809,25,141,66
offsets:1,1,143,68
H
bounds:578,168,147,202
offsets:1,1,149,204
I
bounds:727,252,43,126
offsets:1,1,45,128
Left ear
bounds:1098,64,160,186
offsets:11,0,171,186
Left eye
bounds:309,690,30,16
Left eyebrow
bounds:966,1177,24,27
Left forearm
bounds:876,924,75,134
offsets:1,2,77,136
Left upper arm
bounds:344,43,123,164
offsets:11,2,137,167
rotate:90
Right ear
bounds:1545,63,193,253
offsets:0,1,193,254
rotate:90
Right eye
bounds:504,820,55,16
Right eyebrow
bounds:876,1144,38,31
Right leg
bounds:1390,72,164,172
offsets:0,2,164,176
Right leg1
bounds:1251,936,184,214
offsets:2,0,187,217
Right lower arm
bounds:1408,1059,150,140
offsets:0,0,163,142
rotate:90
Right lower arm 副本
bounds:2,31,151,148
offsets:0,0,163,148
rotate:90
Right lower arm 副本 3
bounds:661,46,116,146
rotate:90
Right upper arm
bounds:502,38,128,158
offsets:7,2,136,160
rotate:90
body
bounds:2,305,417,401
offsets:239,0,750,812
bu_youshou1
bounds:1232,68,157,182
offsets:0,0,158,184
bu_youshou2
bounds:1329,2,136,124
offsets:1,27,138,152
bu_zuoshou1
bounds:1799,78,156,165
offsets:2,0,158,165
bu_zuoshou2
bounds:193,54,164,140
offsets:0,0,164,141
rotate:180
face
bounds:876,923,413,286
offsets:2,0,433,286
ground
bounds:2,708,1618,99
offsets:1,1,1620,101
maple leaf
bounds:1426,922,115,90
meimao_y
bounds:52,683,38,23
meimao_z
bounds:876,1177,58,27
mouth
bounds:388,652,49,35
offsets:0,0,50,44
mouth2
bounds:451,814,51,22
mouth3
bounds:726,657,76,49
offsets:1,1,78,51
muzhuang
bounds:2,1193,608,430
offsets:1,1,610,432
qipao
bounds:379,372,89,63
tail
bounds:419,347,398,359
offsets:2,0,400,359
tanhao
bounds:1252,1166,43,153
rotate:90
upper lip
bounds:257,221,83,83
water_03_00005
bounds:451,838,423,353
offsets:1,1,424,354
water_03_00006
bounds:2,814,447,377
offsets:1,1,449,378
water_03_00007
bounds:1550,809,461,402
offsets:1,1,462,404
water_03_00008
bounds:1083,1211,465,412
offsets:1,1,467,414
water_03_00009
bounds:612,1206,469,417
offsets:1,0,471,418
water_03_00010
bounds:1550,1213,461,410
offsets:1,0,463,411
weijin2
bounds:1870,7,109,143
offsets:1,2,112,147
rotate:90
weijin_hou
bounds:727,86,145,392
offsets:0,7,145,401
rotate:90
weijin_q1
bounds:876,822,386,153
offsets:7,5,393,159
weijinq_2
bounds:2,177,129,254
offsets:3,1,133,260
rotate:90
xinfeng
bounds:1361,255,289,175
xinfeng2
bounds:1109,443,285,263
offsets:1,1,287,265
xinfeng3
bounds:819,443,288,263
offsets:1,1,290,265
xinfeng3 副本 2
bounds:1652,258,288,172
offsets:1,1,290,174
xinxin
bounds:819,202,268,239
xinzhi
bounds:1621,432,375,392
rotate:90
yanbai_y
bounds:424,678,35,28
yanbai_z
bounds:350,676,55,30
yantong_y
bounds:561,811,23,25
offsets:1,1,25,27
yantong_z
bounds:936,1177,28,27
offsets:1,1,30,29
z
bounds:343,168,233,202
offsets:1,1,235,204
zhifeiji
bounds:1262,809,238,111
offsets:1,1,240,113
图层 10
bounds:1089,252,270,189

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

View File

@ -1,175 +0,0 @@
xiaohuli_xiaoxitixing.png
size:2048,2048
filter:Linear,Linear
pma:true
0
bounds:2,651,48,55
offsets:1,1,50,57
00
bounds:809,25,141,66
offsets:1,1,143,68
H
bounds:578,168,147,202
offsets:1,1,149,204
I
bounds:727,252,43,126
offsets:1,1,45,128
Left ear
bounds:1098,64,160,186
offsets:11,0,171,186
Left eye
bounds:309,690,30,16
Left eyebrow
bounds:966,1177,24,27
Left forearm
bounds:876,924,75,134
offsets:1,2,77,136
Left upper arm
bounds:344,43,123,164
offsets:11,2,137,167
rotate:90
Right ear
bounds:1545,63,193,253
offsets:0,1,193,254
rotate:90
Right eye
bounds:504,820,55,16
Right eyebrow
bounds:876,1144,38,31
Right leg
bounds:1390,72,164,172
offsets:0,2,164,176
Right leg1
bounds:1251,936,184,214
offsets:2,0,187,217
Right lower arm
bounds:1408,1059,150,140
offsets:0,0,163,142
rotate:90
Right lower arm 副本
bounds:2,31,151,148
offsets:0,0,163,148
rotate:90
Right lower arm 副本 3
bounds:661,46,116,146
rotate:90
Right upper arm
bounds:502,38,128,158
offsets:7,2,136,160
rotate:90
body
bounds:2,305,417,401
offsets:239,0,750,812
bu_youshou1
bounds:1232,68,157,182
offsets:0,0,158,184
bu_youshou2
bounds:1329,2,136,124
offsets:1,27,138,152
bu_zuoshou1
bounds:1799,78,156,165
offsets:2,0,158,165
bu_zuoshou2
bounds:193,54,164,140
offsets:0,0,164,141
rotate:180
face
bounds:876,923,413,286
offsets:2,0,433,286
ground
bounds:2,708,1618,99
offsets:1,1,1620,101
maple leaf
bounds:1426,922,115,90
meimao_y
bounds:52,683,38,23
meimao_z
bounds:876,1177,58,27
mouth
bounds:388,652,49,35
offsets:0,0,50,44
mouth2
bounds:451,814,51,22
mouth3
bounds:726,657,76,49
offsets:1,1,78,51
muzhuang
bounds:2,1193,608,430
offsets:1,1,610,432
qipao
bounds:379,372,89,63
tail
bounds:419,347,398,359
offsets:2,0,400,359
tanhao
bounds:1252,1166,43,153
rotate:90
upper lip
bounds:257,221,83,83
water_03_00005
bounds:451,838,423,353
offsets:1,1,424,354
water_03_00006
bounds:2,814,447,377
offsets:1,1,449,378
water_03_00007
bounds:1550,809,461,402
offsets:1,1,462,404
water_03_00008
bounds:1083,1211,465,412
offsets:1,1,467,414
water_03_00009
bounds:612,1206,469,417
offsets:1,0,471,418
water_03_00010
bounds:1550,1213,461,410
offsets:1,0,463,411
weijin2
bounds:1870,7,109,143
offsets:1,2,112,147
rotate:90
weijin_hou
bounds:727,86,145,392
offsets:0,7,145,401
rotate:90
weijin_q1
bounds:876,822,386,153
offsets:7,5,393,159
weijinq_2
bounds:2,177,129,254
offsets:3,1,133,260
rotate:90
xinfeng
bounds:1361,255,289,175
xinfeng2
bounds:1109,443,285,263
offsets:1,1,287,265
xinfeng3
bounds:819,443,288,263
offsets:1,1,290,265
xinfeng3 副本 2
bounds:1652,258,288,172
offsets:1,1,290,174
xinxin
bounds:819,202,268,239
xinzhi
bounds:1621,432,375,392
rotate:90
yanbai_y
bounds:424,678,35,28
yanbai_z
bounds:350,676,55,30
yantong_y
bounds:561,811,23,25
offsets:1,1,25,27
yantong_z
bounds:936,1177,28,27
offsets:1,1,30,29
z
bounds:343,168,233,202
offsets:1,1,235,204
zhifeiji
bounds:1262,809,238,111
offsets:1,1,240,113
图层 10
bounds:1089,252,270,189

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

View File

@ -1,175 +0,0 @@
xiaohuli_xunhuan.png
size:2048,2048
filter:Linear,Linear
pma:true
0
bounds:2,651,48,55
offsets:1,1,50,57
00
bounds:809,25,141,66
offsets:1,1,143,68
H
bounds:578,168,147,202
offsets:1,1,149,204
I
bounds:727,252,43,126
offsets:1,1,45,128
Left ear
bounds:1098,64,160,186
offsets:11,0,171,186
Left eye
bounds:309,690,30,16
Left eyebrow
bounds:966,1177,24,27
Left forearm
bounds:876,924,75,134
offsets:1,2,77,136
Left upper arm
bounds:344,43,123,164
offsets:11,2,137,167
rotate:90
Right ear
bounds:1545,63,193,253
offsets:0,1,193,254
rotate:90
Right eye
bounds:504,820,55,16
Right eyebrow
bounds:876,1144,38,31
Right leg
bounds:1390,72,164,172
offsets:0,2,164,176
Right leg1
bounds:1251,936,184,214
offsets:2,0,187,217
Right lower arm
bounds:1408,1059,150,140
offsets:0,0,163,142
rotate:90
Right lower arm 副本
bounds:2,31,151,148
offsets:0,0,163,148
rotate:90
Right lower arm 副本 3
bounds:661,46,116,146
rotate:90
Right upper arm
bounds:502,38,128,158
offsets:7,2,136,160
rotate:90
body
bounds:2,305,417,401
offsets:239,0,750,812
bu_youshou1
bounds:1232,68,157,182
offsets:0,0,158,184
bu_youshou2
bounds:1329,2,136,124
offsets:1,27,138,152
bu_zuoshou1
bounds:1799,78,156,165
offsets:2,0,158,165
bu_zuoshou2
bounds:193,54,164,140
offsets:0,0,164,141
rotate:180
face
bounds:876,923,413,286
offsets:2,0,433,286
ground
bounds:2,708,1618,99
offsets:1,1,1620,101
maple leaf
bounds:1426,922,115,90
meimao_y
bounds:52,683,38,23
meimao_z
bounds:876,1177,58,27
mouth
bounds:388,652,49,35
offsets:0,0,50,44
mouth2
bounds:451,814,51,22
mouth3
bounds:726,657,76,49
offsets:1,1,78,51
muzhuang
bounds:2,1193,608,430
offsets:1,1,610,432
qipao
bounds:379,372,89,63
tail
bounds:419,347,398,359
offsets:2,0,400,359
tanhao
bounds:1252,1166,43,153
rotate:90
upper lip
bounds:257,221,83,83
water_03_00005
bounds:451,838,423,353
offsets:1,1,424,354
water_03_00006
bounds:2,814,447,377
offsets:1,1,449,378
water_03_00007
bounds:1550,809,461,402
offsets:1,1,462,404
water_03_00008
bounds:1083,1211,465,412
offsets:1,1,467,414
water_03_00009
bounds:612,1206,469,417
offsets:1,0,471,418
water_03_00010
bounds:1550,1213,461,410
offsets:1,0,463,411
weijin2
bounds:1870,7,109,143
offsets:1,2,112,147
rotate:90
weijin_hou
bounds:727,86,145,392
offsets:0,7,145,401
rotate:90
weijin_q1
bounds:876,822,386,153
offsets:7,5,393,159
weijinq_2
bounds:2,177,129,254
offsets:3,1,133,260
rotate:90
xinfeng
bounds:1361,255,289,175
xinfeng2
bounds:1109,443,285,263
offsets:1,1,287,265
xinfeng3
bounds:819,443,288,263
offsets:1,1,290,265
xinfeng3 副本 2
bounds:1652,258,288,172
offsets:1,1,290,174
xinxin
bounds:819,202,268,239
xinzhi
bounds:1621,432,375,392
rotate:90
yanbai_y
bounds:424,678,35,28
yanbai_z
bounds:350,676,55,30
yantong_y
bounds:561,811,23,25
offsets:1,1,25,27
yantong_z
bounds:936,1177,28,27
offsets:1,1,30,29
z
bounds:343,168,233,202
offsets:1,1,235,204
zhifeiji
bounds:1262,809,238,111
offsets:1,1,240,113
图层 10
bounds:1089,252,270,189

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

View File

@ -1,175 +0,0 @@
xiaohuli_yemianbuhuoyue.png
size:2048,2048
filter:Linear,Linear
pma:true
0
bounds:2,651,48,55
offsets:1,1,50,57
00
bounds:809,25,141,66
offsets:1,1,143,68
H
bounds:578,168,147,202
offsets:1,1,149,204
I
bounds:727,252,43,126
offsets:1,1,45,128
Left ear
bounds:1098,64,160,186
offsets:11,0,171,186
Left eye
bounds:309,690,30,16
Left eyebrow
bounds:966,1177,24,27
Left forearm
bounds:876,924,75,134
offsets:1,2,77,136
Left upper arm
bounds:344,43,123,164
offsets:11,2,137,167
rotate:90
Right ear
bounds:1545,63,193,253
offsets:0,1,193,254
rotate:90
Right eye
bounds:504,820,55,16
Right eyebrow
bounds:876,1144,38,31
Right leg
bounds:1390,72,164,172
offsets:0,2,164,176
Right leg1
bounds:1251,936,184,214
offsets:2,0,187,217
Right lower arm
bounds:1408,1059,150,140
offsets:0,0,163,142
rotate:90
Right lower arm 副本
bounds:2,31,151,148
offsets:0,0,163,148
rotate:90
Right lower arm 副本 3
bounds:661,46,116,146
rotate:90
Right upper arm
bounds:502,38,128,158
offsets:7,2,136,160
rotate:90
body
bounds:2,305,417,401
offsets:239,0,750,812
bu_youshou1
bounds:1232,68,157,182
offsets:0,0,158,184
bu_youshou2
bounds:1329,2,136,124
offsets:1,27,138,152
bu_zuoshou1
bounds:1799,78,156,165
offsets:2,0,158,165
bu_zuoshou2
bounds:193,54,164,140
offsets:0,0,164,141
rotate:180
face
bounds:876,923,413,286
offsets:2,0,433,286
ground
bounds:2,708,1618,99
offsets:1,1,1620,101
maple leaf
bounds:1426,922,115,90
meimao_y
bounds:52,683,38,23
meimao_z
bounds:876,1177,58,27
mouth
bounds:388,652,49,35
offsets:0,0,50,44
mouth2
bounds:451,814,51,22
mouth3
bounds:726,657,76,49
offsets:1,1,78,51
muzhuang
bounds:2,1193,608,430
offsets:1,1,610,432
qipao
bounds:379,372,89,63
tail
bounds:419,347,398,359
offsets:2,0,400,359
tanhao
bounds:1252,1166,43,153
rotate:90
upper lip
bounds:257,221,83,83
water_03_00005
bounds:451,838,423,353
offsets:1,1,424,354
water_03_00006
bounds:2,814,447,377
offsets:1,1,449,378
water_03_00007
bounds:1550,809,461,402
offsets:1,1,462,404
water_03_00008
bounds:1083,1211,465,412
offsets:1,1,467,414
water_03_00009
bounds:612,1206,469,417
offsets:1,0,471,418
water_03_00010
bounds:1550,1213,461,410
offsets:1,0,463,411
weijin2
bounds:1870,7,109,143
offsets:1,2,112,147
rotate:90
weijin_hou
bounds:727,86,145,392
offsets:0,7,145,401
rotate:90
weijin_q1
bounds:876,822,386,153
offsets:7,5,393,159
weijinq_2
bounds:2,177,129,254
offsets:3,1,133,260
rotate:90
xinfeng
bounds:1361,255,289,175
xinfeng2
bounds:1109,443,285,263
offsets:1,1,287,265
xinfeng3
bounds:819,443,288,263
offsets:1,1,290,265
xinfeng3 副本 2
bounds:1652,258,288,172
offsets:1,1,290,174
xinxin
bounds:819,202,268,239
xinzhi
bounds:1621,432,375,392
rotate:90
yanbai_y
bounds:424,678,35,28
yanbai_z
bounds:350,676,55,30
yantong_y
bounds:561,811,23,25
offsets:1,1,25,27
yantong_z
bounds:936,1177,28,27
offsets:1,1,30,29
z
bounds:343,168,233,202
offsets:1,1,235,204
zhifeiji
bounds:1262,809,238,111
offsets:1,1,240,113
图层 10
bounds:1089,252,270,189

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

View File

@ -11,7 +11,6 @@ import { computed } from 'vue'
import asyncLoader from './utils/asyncLoader'
import useLayoutStore from './layout/useLayoutStore'
const Grid = asyncLoader(() => import('./layout/grid'))
const Fox = asyncLoader(() => import('./fox'))
const settings = useSettingsStore()
const blockSize = computed(() => settings.state.blockSize + 'rem')
const blockPadding = computed(() => settings.state.blockPadding + 'rem')
@ -29,9 +28,6 @@ const layout = useLayoutStore()
<Sider />
<LoginModal />
<Grid v-if="layout.ready" />
<div class="fixed z-40 right-[14%] top-8">
<Fox />
</div>
</div>
</template>

View File

@ -1,66 +1,16 @@
export const aIUrl = 'https://metaso.cn/?s=uitab&referrer_s=uitab&q='
export const translateUrl = 'https://fanyi.baidu.com/mtpe-individual/multimodal?lang=zh2en&query='
// oss地址
// 获取 ossKey 地址
export const ossKeyUrl = import.meta.env.PROD
? 'http://192.168.110.28:8300/ossKey'
: 'http://192.168.110.28:8300/ossKey'
// 获取 oss 根目录地址
export const ossBase = import.meta.env.PROD
? 'http://btab.oss-cn-hangzhou.aliyuncs.com'
: 'http://btab.oss-cn-hangzhou.aliyuncs.com'
// oss cdn 加速地址
export const ossCdnBase = import.meta.env.PROD ? ossBase : ossBase
// 后端地址
export const apiBase = import.meta.env.PROD
? 'http://192.168.110.28:8300'
: 'http://192.168.110.28:8300'
// 后端 cdn 加速地址
export const cdnBase = import.meta.env.PROD ? apiBase : apiBase
// 图片后缀名
export const imgArr = [
'bmp',
'cod',
'gif',
'lef',
'jpe',
'jpeg',
'jpg',
'jfif',
'svg',
'tif',
'tiff',
'ras',
'cmx',
'ico',
'pnm',
'pbm',
'pgm',
'rgb',
'xbm',
'xpm',
'xwd',
'png'
]
// 视频后缀名
export const videoArr = [
'mp4',
'mpg',
'mpeg',
'mpe',
'qt',
'mov',
'm4v',
'wmv',
'avi',
'webm',
'flv',
'mp2',
'mpa',
'mpv2',
'lsf',
'lsx',
'asf',
'asr',
'asx',
'movie'
]

View File

@ -1,134 +0,0 @@
// 重构代码
import { Application, Assets } from 'pixi.js'
import 'pixi.js/unsafe-eval'
import '@pixi/spine-pixi'
import { Spine, TrackEntry } from '@pixi/spine-pixi'
import { defineComponent, onMounted, onUnmounted, ref, watch } from 'vue'
import useRouterStore from '@/useRouterStore'
import useSearchStore from '@/layout/header/search/useSearchStore'
import useLayoutStore from '@/layout/useLayoutStore'
const stageStrList = [
'dazhaohu',
'xunhuan',
'yemianbuhuoyue',
'dahulu',
'shuixing',
'duxin',
'aixin',
'dianji',
'xiaoxitixing'
]
const load = async (stageStr: string) => {
await Assets.load({ alias: stageStr, src: `/fox/xiaohuli_${stageStr}.json` })
await Assets.load({
alias: stageStr + '_atlas',
src: `/fox/xiaohuli_${stageStr}.atlas`
})
}
export default defineComponent(() => {
let container: HTMLCanvasElement | null = null
const app = new Application()
let spine: Spine | null = null
let track: TrackEntry | null = null
const sleep = ref(false)
const run = (stageStr: string) => {
if (spine) {
app.stage.removeChild(spine)
spine.destroy()
}
spine = Spine.from({ skeleton: stageStr, atlas: stageStr + '_atlas' })
track = spine.state.setAnimation(0, stageStr, stageStr === 'xunhuan' || stageStr === 'dahulu')
spine.x = 80
spine.y = 200
spine.scale = 0.2
app.stage.addChild(spine)
const handle = () => {
if (track?.isComplete()) {
app.ticker.remove(handle)
if (stageStr !== 'xunhuan' && stageStr !== 'dahulu') {
run(sleep.value ? 'dahulu' : 'xunhuan')
}
}
}
app.ticker.add(handle)
}
watch(sleep, (val) => {
if (val) {
run('yemianbuhuoyue')
} else {
run('shuixing')
}
})
onMounted(async () => {
if (!container) return
await app.init({
width: 250,
height: 195,
backgroundAlpha: 0,
resolution: window.devicePixelRatio || 1,
autoDensity: true,
antialias: true,
background: 'transparent',
backgroundColor: 'transparent',
canvas: container
})
for (const str of stageStrList) {
await load(str)
}
watch(
() => layout.currentMode,
() => {
run('dazhaohu')
},
{ immediate: true }
)
const handle = () => {
if (document.visibilityState === 'visible') {
sleep.value = false
run('shuixing')
}
}
window.addEventListener('visibilitychange', handle)
let it: any = 0
const handleMove = () => {
clearTimeout(it)
sleep.value = false
it = setTimeout(() => {
sleep.value = true
}, 10000)
}
window.addEventListener('mousemove', handleMove)
onUnmounted(() => {
window.removeEventListener('visibilitychange', handle)
window.removeEventListener('mousemove', handleMove)
})
})
const router = useRouterStore()
const search = useSearchStore()
const layout = useLayoutStore()
watch(
() => [router.path, search.focus],
([a, b]) => {
if (a || b) {
run('duxin')
}
}
)
return () => (
<canvas
ref={(el) => (container = el as any)}
onMouseenter={() => {
run('dianji')
}}
onClick={() => {
run('aixin')
}}
/>
)
})

View File

@ -5,7 +5,6 @@ import { OhVueIcon, addIcons } from 'oh-vue-icons'
import { MdKeyboardcommandkey, FaCompass, FaPencilRuler } from 'oh-vue-icons/icons'
import CustomAdder from './CustomAdder'
import clsx from 'clsx'
import ThemeProvider from '@/utils/ThemeProvider'
addIcons(MdKeyboardcommandkey, FaCompass, FaPencilRuler)
const ItemButton = defineComponent({
@ -55,57 +54,55 @@ export default defineComponent(() => {
const isGame = computed(() => layout.state.current === 0)
const type = ref(1)
return () => (
<div class={clsx('w-full h-full relative flex', isGame.value && 'bg-[#2c2e3e]')}>
<ThemeProvider dark={isGame.value}>
{isGame.value && <AdderPageBack />}
<div
class={
'w-[200px] h-full relative z-10 pt-[100px] ' +
(isGame.value ? 'pl-6 pr-2' : 'bg-white/60 backdrop-blur px-4')
}
>
<ItemButton
name="md-keyboardcommandkey"
label="功能组件"
active={type.value === 0}
onClick={() => {
type.value = 0
}}
/>
<ItemButton
name="fa-compass"
label="网站图标"
active={type.value === 1}
onClick={() => {
type.value = 1
}}
/>
<ItemButton
name="fa-pencil-ruler"
label="自定义网址"
active={type.value === 2}
onClick={() => {
type.value = 2
}}
/>
</div>
<div
class={
'w-0 h-full flex-grow relative z-10 flex flex-col ' +
(isGame.value ? '' : 'bg-white/80 backdrop-blur')
}
onContextmenu={(e) => e.stopPropagation()}
>
<div class="w-full h-[60px]"></div>
<div class="w-full h-0 flex-grow p-6">
<div class="w-full h-full relative">
<Transition>
{type.value === 0 ? '' : type.value === 1 ? '' : <CustomAdder />}
</Transition>
</div>
<div class={clsx("w-full h-full relative flex", isGame.value&&"bg-[#2c2e3e]")}>
{isGame.value && <AdderPageBack />}
<div
class={
'w-[200px] h-full relative z-10 pt-[100px] ' +
(isGame.value ? 'pl-6 pr-2' : 'bg-white/60 backdrop-blur px-4')
}
>
<ItemButton
name="md-keyboardcommandkey"
label="功能组件"
active={type.value === 0}
onClick={() => {
type.value = 0
}}
/>
<ItemButton
name="fa-compass"
label="网站图标"
active={type.value === 1}
onClick={() => {
type.value = 1
}}
/>
<ItemButton
name="fa-pencil-ruler"
label="自定义网址"
active={type.value === 2}
onClick={() => {
type.value = 2
}}
/>
</div>
<div
class={
'w-0 h-full flex-grow relative z-10 flex flex-col ' +
(isGame.value ? '' : 'bg-white/80 backdrop-blur')
}
onContextmenu={(e) => e.stopPropagation()}
>
<div class="w-full h-[60px]"></div>
<div class="w-full h-0 flex-grow p-6">
<div class="w-full h-full relative">
<Transition>
{type.value === 0 ? '' : type.value === 1 ? '' : <CustomAdder />}
</Transition>
</div>
</div>
</ThemeProvider>
</div>
</div>
)
})

View File

@ -1,16 +1,11 @@
import { computed, defineComponent, reactive, ref, watch } from 'vue'
import useLayoutStore from '../useLayoutStore'
import { Button, Form, Input, InputGroup } from 'ant-design-vue'
import { ConfigProvider, Form, Input, theme } from 'ant-design-vue'
import { OhVueIcon, addIcons } from 'oh-vue-icons'
import { MdUpload, MdImage, MdCheck } from 'oh-vue-icons/icons'
import clsx from 'clsx'
import ImageUploader from '@/utils/ImageUploader'
import useLink from './useLink'
import { CheckOutlined } from '@ant-design/icons-vue'
import { v4 as uuid } from 'uuid'
import type { Block } from '../layout.types'
import { ColorPicker } from 'vue3-colorpicker'
import 'vue3-colorpicker/style.css'
import { globalToast } from '@/main'
addIcons(MdUpload, MdImage, MdCheck)
@ -35,10 +30,6 @@ const TypeSelector = defineComponent({
background: {
type: String,
default: ''
},
name: {
type: String,
default: ''
}
},
emits: {
@ -83,14 +74,12 @@ const TypeSelector = defineComponent({
}}
>
<span
class="text-[16px]"
class="text-[20px]"
style={{
color: props.color
}}
>
{props.text
? props.text.substring(0, 2)
: props.name.substring(0, 2).toLocaleUpperCase() || 'A'}
{props.text ? props.text.substring(0, 2) : 'A'}
</span>
{props.value === 1 && (
<div
@ -119,122 +108,112 @@ const TypeSelector = defineComponent({
)
}
})
export default defineComponent(() => {
const layout = useLayoutStore()
const form = reactive({
link: '',
name: '',
text: '',
background: 'rgb(247,169,78)',
color: 'rgb(255,255,255)',
icon: '',
type: 0 // 0 默认1 文字
})
const isGame = computed(() => layout.state.current === 0)
const debounced = ref('')
watch(
() => form.link,
(val, _, onCleanup) => {
const it = setTimeout(() => {
debounced.value = val
}, 500)
onCleanup(() => {
clearTimeout(it)
})
export default defineComponent({
props: {
mode: {
type: Number,
default: 0
},
page: {
type: Number,
default: 0
}
)
const info = useLink(debounced)
watch(info, (val) => {
if (val.name) form.name = val.name
if (val.icon) form.icon = val.icon
})
return () => (
<div
class={
'absolute left-0 top-0 w-full h-full rounded-2xl py-5 pl-6 pr-[30%] ' +
(isGame.value ? 'bg-white/20' : 'bg-white/20')
},
setup(props, ctx) {
const layout = useLayoutStore()
const form = reactive({
link: '',
name: '',
text: '',
background: '#f7a94e',
color: 'rgba(255,255,255,1)',
icon: '',
type: 0 // 0 默认1 文字
})
const isGame = computed(() => layout.state.current === 0)
const debounced = ref('')
watch(
() => form.link,
(val, _, onCleanup) => {
const it = setTimeout(() => {
debounced.value = val
}, 500)
onCleanup(() => {
clearTimeout(it)
})
}
>
<Form labelCol={{ span: 4 }} labelAlign="left">
<Form.Item label="地址">
<InputGroup compact style="display:flex">
<Input
v-model:value={form.link}
)
const info = useLink(debounced)
console.log(info);
watch(info, (val) => {
console.log(val);
if (val.name) form.name = val.name
if (val.icon) form.icon = val.icon
})
return () => (
<div
class={
'absolute left-0 top-0 w-full h-full rounded-2xl p-5 ' +
(isGame.value ? 'bg-white/20' : 'bg-white/20')
}
>
<div class="flex flex-col">
<div></div>
</div>
<div class={clsx('flex flex-col text-[14px] gap-y-3', isGame.value ? 'text-white' : '')}>
<div class={clsx('gap-x-6 flex items-center')}>
<span></span>
<input
v-model={form.link}
placeholder="搜索想要添加的网址导航"
class="w-0 flex-grow"
class={clsx(
'w-[350px] rounded-md outline-none h-[40px] px-[10px]',
isGame.value ? 'bg-black/[.1]' : ''
)}
></input>
<span class={'cursor-pointer'}></span>
</div>
<div class={clsx('gap-x-6 flex items-center')}>
<span></span>
<input
v-model={form.name}
placeholder="网站名称"
class={clsx(
'w-[350px] rounded-md outline-none h-[40px] px-[10px]',
isGame.value ? 'bg-black/[.1]' : ''
)}
></input>
</div>
<div class={clsx('gap-x-6 flex items-start')}>
<span></span>
<TypeSelector
v-model:value={form.type}
v-model:icon={form.icon}
text={form.text}
color={form.color}
background={form.background}
/>
<Button></Button>
</InputGroup>
</Form.Item>
<Form.Item label="名称">
<Input v-model:value={form.name} />
</Form.Item>
<Form.Item label="图标">
<TypeSelector
v-model:value={form.type}
v-model:icon={form.icon}
name={form.name}
text={form.text}
color={form.color}
background={form.background}
/>
</Form.Item>
{form.type === 1 && (
<>
<Form.Item label="文字颜色">
<ColorPicker
class="shadow-lg"
format="rgb"
shape="square"
v-model:pureColor={form.color}
/>
</Form.Item>
<Form.Item label="图标背景">
<ColorPicker
class="shadow-lg"
format="rgb"
shape="square"
v-model:pureColor={form.background}
/>
</Form.Item>
<Form.Item label="图标文字">
<Input v-model:value={form.text} maxlength={2} />
</Form.Item>
</>
)}
<Form.Item label=" " colon={false}>
<Button
type="primary"
size="large"
icon={<CheckOutlined />}
onClick={() => {
if (form.type === 1 && !form.text && !form.name) {
globalToast.error('文字图标请至少填写文字或者名称')
return
}
const id = uuid()
const data: Block = {
link: form.link,
name: '',
icon: form.type === 0 ? info.icon : '',
background: form.type === 0 ? '' : form.background,
color: form.type === 0 ? '' : form.color,
text:
form.type === 0 ? '' : form.text || form.name.substring(0, 2).toLocaleUpperCase(),
label: form.name,
extra: {
id
}
}
layout.addBlock(data)
}}
>
</Button>
</Form.Item>
</Form>
</div>
)
</div>
<div class={clsx('gap-x-6 flex items-center')}>
<span></span>
<button
v-model:value={form.name}
placeholder="网站名称"
class={clsx(
'bg-gradient-to-b from-[#ffaa4e] to-[#ff6227] rounded-lg w-[94px] h-[40px] text-[16px] ',
isGame.value ? 'bg-black/[.1]' : ''
)}
>
</button>
</div>
</div>
</div>
)
}
})

View File

@ -22,6 +22,8 @@ export default function useLink(url: Ref<string>) {
(val) => {
if (!val) return
const tag = val.match(/(?<=http(s?):\/\/)[^/]*/g)?.[0] || val
console.log(tag);
request<LinkInfo>('GET', `/api/app/pic/info/${tag}`).then((res) => {
Object.assign(info, res)
})

View File

@ -1,117 +1,5 @@
import { Button, Select, Slider } from 'ant-design-vue'
import { computed, defineComponent, ref, Transition, watch } from 'vue'
import useLayoutStore from '../useLayoutStore'
import Rect from '@/utils/Rect'
import useResource from './useResource'
import { DownloadOutlined, EyeInvisibleOutlined, SwapOutlined } from '@ant-design/icons-vue'
import SettingItem from '@/settings/SettingItem'
import useSettingsStore from '@/settings/useSettingsStore'
import { v4 as uuid } from 'uuid'
import { defineComponent } from 'vue'
export default defineComponent(() => {
const layout = useLayoutStore()
const selected = ref(0)
watch(
() => layout.state.current,
(val) => {
selected.value = val
},
{ immediate: true }
)
const resource = useResource(
computed(() => layout.state.content[selected.value].background),
'background'
)
const settings = useSettingsStore()
return () => (
<div class="absolute left-0 top-0 w-full h-full p-4 overflow-y-auto">
<SettingItem
noBg
v-slots={{
label: () => <div></div>
}}
>
<Select
class="w-[100px]"
options={[
{ label: '游戏', value: 0 },
{ label: '工作', value: 1 },
{ label: '休闲', value: 2 }
]}
v-model:value={selected.value}
/>
</SettingItem>
<div class="px-4">
<div class="h-[180px]">
{resource.video && resource.type !== 'own' ? (
<video class="w-full h-full" src={resource.video} autoplay={false} controls />
) : (
<div
class="w-full h-full bg-center bg-no-repeat bg-cover"
style={{
backgroundImage: `url('${resource.image}')`
}}
></div>
)}
</div>
<div class="flex justify-between items-center py-4">
<Button type="primary" icon={<SwapOutlined />}>
</Button>
<Button
type="text"
icon={<DownloadOutlined />}
onClick={() => {
window.open(resource.video || resource.image, '_blank')
}}
>
</Button>
</div>
</div>
<SettingItem
noRoundedB
v-slots={{
label: () => <div></div>
}}
>
<Slider
v-model:value={settings.state.maskOpacity}
step={0.01}
tooltipOpen={false}
min={0}
max={0.7}
/>
</SettingItem>
<SettingItem
noRoundedT
v-slots={{
label: () => <div></div>
}}
>
<Slider
v-model:value={settings.state.maskFilter}
step={0.1}
tooltipOpen={false}
min={0}
max={20}
/>
</SettingItem>
<Transition>
{(settings.state.maskFilter > 0 || settings.state.maskOpacity > 0) && (
<div
class="flex justify-end mr-4"
onClick={() => {
settings.state.maskOpacity = 0
settings.state.maskFilter = 0
}}
>
<Button type="text" icon={<EyeInvisibleOutlined />}>
</Button>
</div>
)}
</Transition>
</div>
)
return () => <div class="absolute left-0 top-0 w-full h-full p-4">this is background</div>
})

View File

@ -1,31 +1,21 @@
import { defineComponent } from 'vue'
import useLayoutStore from '../useLayoutStore'
import useSettingsStore from '@/settings/useSettingsStore'
import useBackgroundStore from './useBackgroundStore'
export default defineComponent({
setup() {
const layout = useLayoutStore()
const settings = useSettingsStore()
const background = useBackgroundStore()
return () => (
<div class="absolute left-0 top-0 w-full h-screen z-0">
{layout.background.video ? (
<video src={layout.background.video} class="w-full h-full" />
) : (
{background.resource.type === 'image' ? (
<div
class="w-full h-full bg-center bg-cover bg-no-repeat"
style={{
backgroundImage: `url('${layout.background.image}')`
backgroundImage: `url('${background.resource.url}')`
}}
></div>
) : (
<video src={background.resource.url} class="w-full h-full" />
)}
<div
class="absolute left-0 top-0 w-full h-full bg-black"
style={{
zIndex: 1,
backgroundColor: `rgba(0,0,0,${settings.state.maskOpacity})`,
backdropFilter: `blur(${settings.state.maskFilter}px)`
}}
></div>
</div>
)
}

View File

@ -1,102 +0,0 @@
import { ossCdnBase, videoArr } from '@/config'
import db from '@/db'
import { reactive, watch, type Ref } from 'vue'
const defaultBackground =
'https://aihlp.com.cn/admin/wallpaper/508d3994-3727-4839-bfe9-41b97ccf4fba_66a3272c874d41e5b9ec7562fe5822cd (1).jpg'
const defaultResource = {
image: '',
video: '',
brief: '',
type: 'default' as 'default' | 'own' | 'third' | 'local'
}
export default function useResource(tag: Ref<string>, type: string) {
const resource = reactive(defaultResource)
watch(
tag,
(val) => {
// '' 表示使用默认,如果是背景,使用默认背景图片
if (!val) {
Object.assign(resource, {
...defaultResource,
image: type === 'background' ? defaultBackground : ''
})
return
}
if (val.startsWith('http')) {
// 内源
if (val.startsWith(ossCdnBase)) {
// 地址后缀
const suffix = val.split('.').pop()
if (!suffix) {
return
}
if (videoArr.includes(suffix)) {
// 内部视频
// 先显示截图,再去数据库看是否有存货
resource.video = ''
resource.image = val + '?x-oss-process=video/snapshot,t_0,f_jpg,m_fast'
resource.brief = val + '?x-oss-process=video/snapshot,t_0,f_jpg,w_400,h_225,m_fast'
db.getItem<{ tag: string; file: Blob }[]>('videoList').then((res) => {
if (!res) return
const item = res.find((item) => item.tag === val)
if (item) {
resource.video = URL.createObjectURL(item.file)
resource.type = 'local'
} else {
// 不存在,需要存入
fetch(val)
.then((res) => res.blob())
.then((blob) => {
if (res.length > 10) {
res.pop()
}
res.unshift({ tag: val, file: blob })
resource.video = URL.createObjectURL(blob)
resource.type = 'own'
})
}
})
} else {
// 图片
resource.image = val
resource.video = ''
resource.brief = val + '?x-oss-process=image/resize,w_400,h_225'
resource.type = 'own'
}
return
}
// 外部资源
const suffix = val.split('.').pop()
if (!suffix) {
resource.image = val
resource.video = ''
resource.brief = val
resource.type = 'third'
return
}
resource.image = videoArr.includes(suffix) ? '' : val
resource.video = videoArr.includes(suffix) ? val : ''
resource.brief = val
resource.type = 'third'
return
}
// 本地
db.getItem<{ tag: string; file: Blob; type: 'image' | 'video' }[]>('localList').then(
(res) => {
if (!res) return
const item = res.find((item) => item.tag === val)
if (!item) return
const url = URL.createObjectURL(item.file)
resource.image = item.type === 'image' ? url : ''
resource.video = item.type === 'video' ? url : ''
resource.brief = url
resource.type = 'local'
}
)
},
{ immediate: true }
)
return resource
}

View File

@ -1,10 +1,8 @@
import { defineComponent, ref } from 'vue'
import { Button, Checkbox, Divider, Modal } from 'ant-design-vue'
import { Button, Checkbox, ConfigProvider, Divider, message, Modal, theme } from 'ant-design-vue'
import useSearchConfigStore from './useSearchConfigStore'
import { EditOutlined, DeleteOutlined, PlusOutlined } from '@ant-design/icons-vue'
import asyncLoader from '@/utils/asyncLoader'
import ThemeProvider from '@/utils/ThemeProvider'
import { globalToast } from '@/main'
const SearchAdder = asyncLoader(() => import('./SearchAdder'))
const SearchItem = defineComponent({
props: {
@ -68,7 +66,7 @@ const SearchItem = defineComponent({
onChange={(e) => {
const checked = e.target.checked
if (!checked && props.url === searchConfig.current.url) {
globalToast.warning('不可隐藏当前使用搜索引擎')
message.warning('不可隐藏当前使用搜索引擎')
} else {
ctx.emit('update:modelValue', e.target.checked)
}
@ -97,7 +95,7 @@ const SearchItem = defineComponent({
icon={<DeleteOutlined />}
onClick={() => {
if (props.url === searchConfig.current.url) {
globalToast.warning('不可删除当前使用搜索引擎')
message.warning('不可删除当前使用搜索引擎')
} else {
const idx = searchConfig.customList.findIndex((el) => el.url === props.url)
searchConfig.customList.splice(idx, 1)
@ -120,7 +118,7 @@ export default defineComponent(() => {
class="w-full h-full bg-white/80 backdrop-blur p-4 flex flex-col select-text"
onContextmenu={(e) => e.stopPropagation()}
>
<ThemeProvider>
<ConfigProvider theme={{ token: theme.defaultAlgorithm(theme.defaultSeed) }}>
<h2 class="text-center tracking-widest font-bold text-xl text-black/80"></h2>
<div class="grid grid-cols-2 gap-4">
<Divider></Divider>
@ -179,7 +177,7 @@ export default defineComponent(() => {
>
<SearchAdder selected={showAdder.value as any} />
</Modal>
</ThemeProvider>
</ConfigProvider>
</div>
)
})

View File

@ -25,11 +25,7 @@ export interface Block {
export type LayoutPages = { list: Block[]; label: string; name: string }[]
export interface Layout {
content: [
{ background: ''; pages: LayoutPages },
{ background: ''; pages: LayoutPages },
{ background: ''; pages: LayoutPages }
]
content: [LayoutPages, LayoutPages, LayoutPages]
current: 0 | 1 | 2 // 游戏,工作,轻娱
currentPage: number
dir: { [key: string]: Block[] }

View File

@ -6,7 +6,6 @@ import { PxHeadset, PxAddBox, PxCheck } from 'oh-vue-icons/icons'
import useRouterStore from '@/useRouterStore'
import useLayoutStore from '../useLayoutStore'
import useUserStore from '@/user/useUserStore'
import AvatarCircle from '@/user/AvatarCircle'
initIcons()
addIcons(PxHeadset, PxAddBox, PxCheck)
@ -77,7 +76,7 @@ export default defineComponent(() => {
<div class="w-full h-[64px]" />
<div class="w-full h-0 flex-grow overflow-auto relative no-scrollbar">
<TransitionGroup>
{layout.currentMode.pages.map((el, idx) => (
{layout.state.content[layout.state.current].map((el, idx) => (
<Item
key={idx}
name={el.name}
@ -91,7 +90,7 @@ export default defineComponent(() => {
))}
</TransitionGroup>
<Transition>
{layout.currentMode.pages.length > 0 && (
{layout.state.content[layout.state.current]?.length > 0 && (
<div
class="absolute w-full h-[56px] rounded-lg bg-white/40 left-0 transition-all"
style={{
@ -118,7 +117,7 @@ export default defineComponent(() => {
}}
/>
<div
class="w-[56px] h-[56px] rounded-full border-white border-[2px] border-solid overflow-hidden cursor-pointer"
class="w-[56px] h-[56px] bg-white/40 rounded-full border-white border-[2px] border-solid overflow-hidden cursor-pointer"
onClick={() => {
if (user.isLogin) {
router.path = 'settings-user'
@ -126,9 +125,7 @@ export default defineComponent(() => {
router.path = 'global-login'
}
}}
>
<AvatarCircle />
</div>
></div>
</div>
{/* 添加页面 */}
<Transition name="page-adder">
@ -164,7 +161,7 @@ export default defineComponent(() => {
<div
class="w-full mt-2 py-1 rounded-lg bg-white text-center text-sm shadow hover:shadow-lg transition-all cursor-pointer"
onClick={() => {
layout.currentMode.pages.push({
layout.state.content[layout.state.current].push({
list: [],
label: label.value,
name: selected.value.name

View File

@ -1,16 +1,10 @@
import { defineStore } from 'pinia'
import type { Block, Layout } from './layout.types'
import type { Layout } from './layout.types'
import { computed, reactive, ref, toRaw, watch } from 'vue'
import db from '@/db'
import useResource from './background/useResource'
import { globalToast } from '@/main'
const defaultLayout: Layout = {
content: [
{ background: '', pages: [] },
{ background: '', pages: [] },
{ background: '', pages: [] }
],
content: [[], [], []],
current: 0,
currentPage: 0,
dir: {},
@ -41,43 +35,15 @@ export default defineStore('layout', () => {
state.currentPage = 0
}
)
const currentMode = computed(() => state.content[state.current])
const currentPage = computed(() => {
return (
currentMode.value.pages[state.simple ? 0 : state.currentPage] || {
list: [],
label: '',
name: ''
}
)
})
const background = useResource(
computed(() => state.content[state.current]?.background || ''),
'background'
const currentPageList = computed(() =>
state.simple ? [] : state.content[state.current]?.[state.currentPage]?.list || []
)
// 是让时间和搜索改变位置,使画面更紧凑 —— @/layout/grid
const isCompact = ref(false)
// 添加图标
const addBlock = (block: Block, _page: number = -1) => {
const page = _page >= 0 ? _page : state.currentPage
console.log(state.content[state.current].pages[page])
if (!state.content[state.current].pages[page]) {
globalToast.warning('请先添加页面')
return
}
const pageList = state.content[state.current].pages[page].list
pageList.push(block)
globalToast.success('添加成功')
}
return {
state,
ready,
currentMode,
currentPage,
isCompact,
background,
addBlock
currentPageList,
isCompact
}
})

View File

@ -7,18 +7,14 @@ import App from './App.vue'
import getFp from './utils/getFp'
import vOutsideClick from './utils/vOutsideClick'
import dayjs from 'dayjs'
import Toast, { useToast, type PluginOptions } from 'vue-toastification'
import 'vue-toastification/dist/index.css'
import 'dayjs/locale/zh-cn'
dayjs.locale('zh-cn')
const app = createApp(App)
export const globalToast = useToast()
// ! persist 利用 localstorage请不要在大量数据时使用
// 大量数据(扩张内容,文件),清直接使用 ./db.ts
app.use(createPinia().use(persist))
app.use(Toast)
app.directive('outside-click', vOutsideClick)
getFp().then((fp) => {
console.info('fp:', fp)

View File

@ -1,42 +0,0 @@
import clsx from 'clsx'
import { defineComponent, type SlotsType, type VNode } from 'vue'
export default defineComponent({
props: {
noRoundedB: {
type: Boolean,
default: false
},
noRoundedT: {
type: Boolean,
default: false
},
noBg: {
type: Boolean,
default: false
}
},
slots: {} as SlotsType<{
label?: () => VNode[]
default?: () => VNode[]
end?: () => VNode[]
}>,
setup(props, ctx) {
return () => (
<div
class={clsx('flex items-center py-2 px-3 rounded-lg', {
'rounded-b-none': props.noRoundedB,
'rounded-t-none': props.noRoundedT,
'bg-black/5': !props.noBg
})}
style={{
marginBottom: props.noRoundedB ? 0 : '12px'
}}
>
<div class="text-sm text-black/60 mr-4">{ctx.slots.label?.()}</div>
<div class="w-0 flex-grow">{ctx.slots.default?.()}</div>
{ctx.slots.end?.()}
</div>
)
}
})

View File

@ -1,8 +1,9 @@
import AvatarCircle from '@/user/AvatarCircle'
import useRouterStore from '@/useRouterStore'
import asyncLoader from '@/utils/asyncLoader'
import { computed, defineComponent, Transition } from 'vue'
const Content = asyncLoader(() => import('./SettingsOverlayContent'))
const UserPage = asyncLoader(() => import('@/user/UserPage'))
const BackgroundPage = asyncLoader(() => import('@/layout/background/BackgroundPage'))
const SettingsTab = defineComponent({
props: {
@ -41,7 +42,7 @@ export default defineComponent(() => {
{/* 背景遮罩 */}
{show.value && (
<div
class="w-full h-screen"
class="w-full h-screen backdrop-blur-sm"
onClick={() => {
router.path = ''
}}
@ -61,9 +62,7 @@ export default defineComponent(() => {
router.path = 'settings-user'
}}
>
<div class="w-12 h-12 relative">
<AvatarCircle />
</div>
<div class="w-12 h-12 rounded-full overflow-hidden bg-black/20"></div>
</div>
<SettingsTab label="壁纸" path="settings-background" />
<SettingsTab label="图标" path="settings-block" />
@ -75,7 +74,15 @@ export default defineComponent(() => {
<SettingsTab label="重置" path="settings-reset" />
<SettingsTab label="问题反馈" path="settings-fallback" />
</div>
<Content />
<div class="w-0 h-full flex-grow bg-white/80 backdrop-blur">
<Transition>
{router.path === 'settings-user' ? (
<UserPage />
) : router.path === 'settings-background' ? (
<BackgroundPage />
) : null}
</Transition>
</div>
</div>
)}
</Transition>

View File

@ -1,21 +0,0 @@
import useRouterStore from '@/useRouterStore'
import { defineComponent, Transition } from 'vue'
import UserPage from '@/user/UserPage'
import BackgroundPage from '@/layout/background/BackgroundPage'
import ThemeProvider from '@/utils/ThemeProvider'
export default defineComponent(() => {
const router = useRouterStore()
return () => (
<div class="w-0 h-full flex-grow bg-white/80 backdrop-blur">
<ThemeProvider>
<Transition>
{router.path === 'settings-user' ? (
<UserPage />
) : router.path === 'settings-background' ? (
<BackgroundPage />
) : null}
</Transition>
</ThemeProvider>
</div>
)
})

View File

@ -7,8 +7,7 @@ export default defineStore(
'settings',
() => {
const state = reactive({
maskOpacity: 0,
maskFilter: 0,
backgroundTag: '',
// 显示隐藏
showSider: 'show' as VisibleState,
showDock: 'show' as VisibleState,

View File

@ -1,22 +0,0 @@
import { defineComponent } from 'vue'
import { OhVueIcon, addIcons } from 'oh-vue-icons'
import { FaUserAlt } from 'oh-vue-icons/icons'
import useUserStore from './useUserStore'
addIcons(FaUserAlt)
export default defineComponent(() => {
const { profile } = useUserStore()
return () => {
return (
<div
class="w-full h-full rounded-full bg-black/20 flex justify-center items-center bg-center bg-no-repeat bg-cover"
style={{
backgroundImage: `url('${profile?.avatar}')`
}}
>
{!profile.avatar && <OhVueIcon name="fa-user-alt" fill="white" scale={1.2} />}
</div>
)
}
})

View File

@ -34,10 +34,8 @@ export default defineComponent(() => {
</div>
<div class="flex flex-col">
<form>
<input placeholder="邮箱" v-model={form.email} />
<input placeholder="密码" type="password" v-model={form.password} />
</form>
<input placeholder="邮箱" v-model={form.email} />
<input placeholder="密码" type="password" v-model={form.password} />
<button
onClick={() => {
request<string>('POST', '/api/user/login', {
@ -45,7 +43,6 @@ export default defineComponent(() => {
returnType: 'text'
}).then((res) => {
user.token = res
router.path = ''
})
}}
>

View File

@ -1,86 +1,19 @@
import useRouterStore from '@/useRouterStore'
import { Button, Modal, Tag } from 'ant-design-vue'
import { Button } from 'ant-design-vue'
import { defineComponent } from 'vue'
import AvatarCircle from './AvatarCircle'
import useUserStore from './useUserStore'
import { EditOutlined, LoginOutlined, LogoutOutlined } from '@ant-design/icons-vue'
import { globalToast } from '@/main'
const labelStyle = 'w-16 text-black/60'
export default defineComponent(() => {
const router = useRouterStore()
const user = useUserStore()
return () => (
<div class="absolute left-0 top-0 w-full h-full p-4 flex flex-col">
<div class="flex justify-center py-4">
<div class="w-16 h-16 relative">
<AvatarCircle />
</div>
</div>
{user.isLogin && (
<div class="h-0 flex-grow py-4 px-12">
<div class="flex py-2">
<div class={labelStyle}>:</div>
<div class="w-0 flex-grow overflow-hidden text-ellipsis whitespace-nowrap break-all">
{user.profile.username}
</div>
</div>
<div class="flex py-2">
<div class={labelStyle}>:</div> {user.profile.birthday}
</div>
<div class="flex py-2">
<div class={labelStyle}>:</div>
<Tag color={user.profile.gender === 1 ? 'blue' : 'red'}>
{user.profile.gender === 1 ? '男' : '女'}
</Tag>
</div>
</div>
)}
<div class="flex justify-around items-center my-10">
{user.isLogin ? (
<>
<Button
onClick={() => {
router.path = 'global-login'
}}
icon={<EditOutlined />}
type="primary"
>
</Button>
<Button
type="text"
icon={<LogoutOutlined />}
onClick={() => {
Modal.confirm({
title: '退出登录',
content: '确定要退出登录吗?',
onOk: () => {
router.path = ''
user.logout()
globalToast.success('已退出登录')
}
})
}}
>
退
</Button>
</>
) : (
<Button
type="primary"
icon={<LoginOutlined />}
size="large"
onClick={() => {
router.path = 'global-login'
}}
>
</Button>
)}
</div>
<div class="absolute left-0 top-0 w-full h-full p-4">
this is user
<Button
onClick={() => {
router.path = 'global-login'
}}
>
</Button>
</div>
)
})

View File

@ -1,48 +1,43 @@
import request from '@/utils/request'
import { defineStore } from 'pinia'
import { computed, reactive, ref, watch } from 'vue'
import { computed, ref, watch } from 'vue'
interface UserInfo {
id: string
username: string
created: string
vipUntil: string
gender: number
birthday: string
brief: string
email: string
password: string
type: string
updated: string
avatar: string
openId: string
}
const defaultUserInfo: UserInfo = {
id: '',
username: '',
gender: 0,
birthday: '',
avatar: '',
openId: ''
}
export default defineStore('user', () => {
const token = ref(localStorage.getItem('token') || '')
watch(token, (val) => {
localStorage.setItem('token', val)
})
const profile = reactive(defaultUserInfo)
const profile = ref<null | UserInfo>(null)
watch(
token,
(val) => {
if (!val) return
request<UserInfo>('GET', '/api/profile').then((res) => {
Object.assign(profile, res)
profile.value = res
})
},
{ immediate: true }
)
const isLogin = computed(() => !!token.value && !!profile.id)
const logout = () => {
token.value = ''
Object.assign(profile, defaultUserInfo)
}
const isLogin = computed(() => !!token.value && !!profile.value)
return {
token,
profile,
isLogin,
logout
isLogin
}
})

View File

@ -1,10 +1,10 @@
import { defineComponent } from 'vue'
import { OhVueIcon, addIcons } from 'oh-vue-icons'
import { MdUpload, FaEye } from 'oh-vue-icons/icons'
import { ConfigProvider, message, theme } from 'ant-design-vue'
import upload from './upload'
import 'viewerjs/dist/viewer.css'
import { api as showViewer } from 'v-viewer'
import { globalToast } from '@/main'
addIcons(MdUpload, FaEye)
@ -35,60 +35,62 @@ export default defineComponent({
let input: HTMLInputElement | null = null
return () => (
<div>
<input
type="file"
accept=".png,.jpeg,.jpg,.svg"
style="display:none"
ref={(el) => (input = el as any)}
onChange={(e) => {
const el = e.target as any
const file: File | undefined = el.files?.[0]
el.value = ''
if (!file) return
console.log(file.size, props.size)
if (file.size > props.size * 1000 * 1000) {
globalToast.warning(`大小不得超过${props.size}mb`)
return
}
upload(file, 'test').then((res) => {
ctx.emit('update:value', res)
})
}}
/>
<div
class="flex justify-center items-center rounded bg-slate-200 hover:bg-slate-300 transition-all bg-cover bg-no-repeat bg-center cursor-pointer shadow"
style={{
width: props.width + 'px',
height: props.width / props.ratio + 'px',
backgroundImage: `url('${props.value}')`
}}
onClick={() => {
input?.click()
}}
>
{props.value ? (
<div class="w-full h-full opacity-0 hover:opacity-100 relative transition-all bg-slate-800/20 flex justify-center items-center">
<div
class="px-1 rounded hover:bg-white/20"
onClick={(e) => {
e.stopPropagation()
showViewer({
images: [props.value],
options: {
navbar: false,
toolbar: false
}
})
}}
>
<OhVueIcon name="fa-eye" scale={1.2} fill="rgba(255,255,255,.4)" />
<ConfigProvider theme={{ token: theme.defaultAlgorithm(theme.defaultSeed) }}>
<input
type="file"
accept=".png,.jpeg,.jpg,.svg"
style="display:none"
ref={(el) => (input = el as any)}
onChange={(e) => {
const el = e.target as any
const file: File | undefined = el.files?.[0]
el.value = ''
if (!file) return
console.log(file.size, props.size)
if (file.size > props.size * 1000 * 1000) {
message.warn(`大小不得超过${props.size}mb`)
return
}
upload(file, 'test').then((res) => {
ctx.emit('update:value', res)
})
}}
/>
<div
class="flex justify-center items-center rounded bg-slate-200 hover:bg-slate-300 transition-all bg-cover bg-no-repeat bg-center cursor-pointer shadow"
style={{
width: props.width + 'px',
height: props.width / props.ratio + 'px',
backgroundImage: `url('${props.value}')`
}}
onClick={() => {
input?.click()
}}
>
{props.value ? (
<div class="w-full h-full opacity-0 hover:opacity-100 relative transition-all bg-slate-800/20 flex justify-center items-center">
<div
class="px-1 rounded hover:bg-white/20"
onClick={(e) => {
e.stopPropagation()
showViewer({
images: [props.value],
options: {
navbar: false,
toolbar: false
}
})
}}
>
<OhVueIcon name="fa-eye" scale={1.2} fill="rgba(255,255,255,.4)" />
</div>
</div>
</div>
) : (
<OhVueIcon name="md-upload" scale={2} fill="rgba(0,0,0,0.2)" />
)}
</div>
{/* <div class="text-xs mt-1 text-black/60">支持上传 .png, .jpeg, .jpg, .svg</div>{' '} */}
) : (
<OhVueIcon name="md-upload" scale={2} fill="rgba(0,0,0,0.2)" />
)}
</div>
{/* <div class="text-xs mt-1 text-black/60">支持上传 .png, .jpeg, .jpg, .svg</div>{' '} */}
</ConfigProvider>
</div>
)
}

View File

@ -1,41 +0,0 @@
import { defineComponent, onMounted, onUnmounted, ref } from 'vue'
// 特定比例显示矩形
export default defineComponent({
props: {
ratio: {
type: Number,
default: 1
}
},
setup(props, ctx) {
let dom: HTMLDivElement | null = null
const height = ref(0)
onMounted(() => {
if (!dom) return
const handle = () => {
if (!dom) return
const { width } = dom.getBoundingClientRect()
console.log(width)
height.value = width * props.ratio
}
const listen = new ResizeObserver(handle)
handle()
listen.observe(dom)
onUnmounted(() => {
listen.disconnect()
})
})
return () => (
<div
ref={(el) => (dom = el as any)}
class="w-full relative"
style={{
paddingBottom: height.value + 'px'
}}
>
<div class="absolute left-0 top-0 w-full h-full">{ctx.slots.default?.()}</div>
</div>
)
}
})

View File

@ -1,29 +0,0 @@
import { ConfigProvider, theme } from 'ant-design-vue'
import { defineComponent } from 'vue'
import zhCN from 'ant-design-vue/es/locale/zh_CN'
export default defineComponent({
props: {
dark: {
type: Boolean,
default: false
}
},
setup(props, ctx) {
return () => (
<ConfigProvider
theme={{
algorithm: props.dark ? theme.darkAlgorithm : theme.defaultAlgorithm,
token: {
colorPrimary: '#f7a94e',
colorBgBase: props.dark ? '#393a41' : '#fff',
colorBorder: 'transparent'
}
}}
locale={zhCN}
>
{ctx.slots.default?.()}
</ConfigProvider>
)
}
})

View File

@ -1,20 +1,24 @@
import { ossBase } from './../config'
import { ossBase, ossKeyUrl } from './../config'
import OSS from 'ali-oss'
import { v4 as uuid } from 'uuid'
import request from './request'
export default async function upload(file: File, root: string) {
const token = localStorage.getItem('token')
if (!token) {
throw new Error('尚未登录,无法上传')
}
const config = await request<{
region: string
accessKeyId: string
accessKeySecret: string
securityToken: string
bucket: string
path: string
}>('POST', '/api/ossKey')
const config = await fetch(ossKeyUrl, {
method: 'POST',
headers: {
Authorization:
'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NjlkZjA3Y2RhMjkyZTNiZTc0OGM5MmMifQ.9k9-C_Im2r2fONfT6rdAZDxapkqtwGtiVBSen59JDXY'
}
}).then(
(res) =>
res.json() as Promise<{
region: string
accessKeyId: string
accessKeySecret: string
securityToken: string
bucket: string
path: string
}>
)
const ext = file.name.split('.').pop()
const path = `${config.path}/${root}/${uuid()}.${ext}`
const client = new OSS({
@ -24,11 +28,13 @@ export default async function upload(file: File, root: string) {
stsToken: config.securityToken,
bucket: config.bucket
})
console.log(path)
const { name } = await client.put(path, file, {
mime: file.type,
headers: {
'Content-Type': file.type
}
})
console.log(name)
return ossBase + '/' + name
}

View File

@ -11,10 +11,6 @@ export default defineConfig({
server: {
host: '0.0.0.0',
port: 8100,
cors: {
origin: '*',
methods: '*'
},
proxy: {
'/baiduSuggestion': {
target: 'https://suggestion.baidu.com',