feat:站点列表功能拓展、绑定邮箱、修改密码
This commit is contained in:
314
src/constants/site-options.ts
Normal file
314
src/constants/site-options.ts
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
// 地区选项
|
||||||
|
export const regionOptions = [
|
||||||
|
{ label: 'Afghanistan', value: 'Afghanistan/AF/+93' },
|
||||||
|
{ label: 'Albania', value: 'Albania/AL/+355' },
|
||||||
|
{ label: 'Algeria', value: 'Algeria/DZ/+213' },
|
||||||
|
{ label: 'Angola', value: 'Angola/AO/+244' },
|
||||||
|
{ label: 'Anguilla', value: 'Anguilla/AI/+1264' },
|
||||||
|
{ label: 'Antigua and Barbuda', value: 'Antigua and Barbuda/AG/+268' },
|
||||||
|
{ label: 'Argentina', value: 'Argentina/AR/+54' },
|
||||||
|
{ label: 'Armenia', value: 'Armenia/AM/+374' },
|
||||||
|
{ label: 'Aruba', value: 'Aruba/AW/+297' },
|
||||||
|
{ label: 'Australia', value: 'Australia/AU/+61' },
|
||||||
|
{ label: 'Austria', value: 'Austria/AT/+43' },
|
||||||
|
{ label: 'Azerbaijan', value: 'Azerbaijan/AZ/+994' },
|
||||||
|
{ label: 'Bahamas', value: 'Bahamas/BS/+1242' },
|
||||||
|
{ label: 'Bahrain', value: 'Bahrain/BH/+973' },
|
||||||
|
{ label: 'Bangladesh', value: 'Bangladesh/BD/+880' },
|
||||||
|
{ label: 'Barbados', value: 'Barbados/BB/+1246' },
|
||||||
|
{ label: 'Belarus', value: 'Belarus/BY/+375' },
|
||||||
|
{ label: 'Belgium', value: 'Belgium/BE/+32' },
|
||||||
|
{ label: 'Belize', value: 'Belize/BZ/+501' },
|
||||||
|
{ label: 'Benin', value: 'Benin/BJ/+229' },
|
||||||
|
{ label: 'Bermuda', value: 'Bermuda/BM/+1441' },
|
||||||
|
{ label: 'Bhutan', value: 'Bhutan/BT/+975' },
|
||||||
|
{ label: 'Bolivia', value: 'Bolivia/BO/+591' },
|
||||||
|
{ label: 'Botswana', value: 'Botswana/BW/+267' },
|
||||||
|
{ label: 'Brasil', value: 'Brasil/BR/+55' },
|
||||||
|
{ label: 'Brunei', value: 'Brunei/BN/+673' },
|
||||||
|
{ label: 'Burkina Faso', value: 'Burkina Faso/BF/+226' },
|
||||||
|
{ label: 'Burundi', value: 'Burundi/BI/+257' },
|
||||||
|
{ label: 'Cabo Verde', value: 'Cabo Verde/CV/+238' },
|
||||||
|
{ label: 'Cambodia', value: 'Cambodia/KH/+855' },
|
||||||
|
{ label: 'Cameroon', value: 'Cameroon/CM/+237' },
|
||||||
|
{ label: 'Canada', value: 'Canada/CA/+1' },
|
||||||
|
{ label: 'Cayman Islands', value: 'Cayman Islands/KY/+1345' },
|
||||||
|
{ label: 'Central African', value: 'Central African/CF/+236' },
|
||||||
|
{ label: 'Chad', value: 'Chad/TD/+235' },
|
||||||
|
{ label: 'Chile', value: 'Chile/CL/+56' },
|
||||||
|
{ label: 'China', value: 'China/CN/+86' },
|
||||||
|
{ label: 'Christmas Island', value: 'Christmas Island/CX/+618' },
|
||||||
|
{ label: 'Colombia', value: 'Colombia/CO/+57' },
|
||||||
|
{ label: 'Comoros', value: 'Comoros/KM/+269' },
|
||||||
|
{ label: 'Congo', value: 'Congo/CD/+243' },
|
||||||
|
{ label: 'Congo', value: 'Congo/CG/+242' },
|
||||||
|
{ label: 'Costa Rica', value: 'Costa Rica/CR/+506' },
|
||||||
|
{ label: "Cote d'Ivoire", value: "Cote d'Ivoire/CI/+225" },
|
||||||
|
{ label: 'Croatia', value: 'Croatia/HR/+385' },
|
||||||
|
{ label: 'Cuba', value: 'Cuba/CU/+53' },
|
||||||
|
{ label: 'Cyprus', value: 'Cyprus/CY/+357' },
|
||||||
|
{ label: 'Czech', value: 'Czech/CZ/+420' },
|
||||||
|
{ label: 'Denmark', value: 'Denmark/DK/+45' },
|
||||||
|
{ label: 'Djibouti', value: 'Djibouti/DJ/+253' },
|
||||||
|
{ label: 'Dominica', value: 'Dominica/DM/+1767' },
|
||||||
|
{ label: 'Dominican', value: 'Dominican/DO/+1809' },
|
||||||
|
{ label: 'Ecuador', value: 'Ecuador/EC/+593' },
|
||||||
|
{ label: 'Egypt', value: 'Egypt/EG/+20' },
|
||||||
|
{ label: 'Equatorial Guinea', value: 'Equatorial Guinea/GQ/+240' },
|
||||||
|
{ label: 'Eritrea', value: 'Eritrea/ER/+291' },
|
||||||
|
{ label: 'Estonia', value: 'Estonia/EE/+372' },
|
||||||
|
{ label: 'Ethiopia', value: 'Ethiopia/ET/+251' },
|
||||||
|
{ label: 'Falkland Islands', value: 'Falkland Islands/FK/+500' },
|
||||||
|
{ label: 'Fiji', value: 'Fiji/FJ/+679' },
|
||||||
|
{ label: 'Finland', value: 'Finland/FI/+358' },
|
||||||
|
{ label: 'France', value: 'France/FR/+33' },
|
||||||
|
{ label: 'French Guiana', value: 'French Guiana/GF/+594' },
|
||||||
|
{ label: 'French Polynesia', value: 'French Polynesia/PF/+689' },
|
||||||
|
{ label: 'Gabon', value: 'Gabon/GA/+241' },
|
||||||
|
{ label: 'Gambia', value: 'Gambia/GM/+220' },
|
||||||
|
{ label: 'Georgia', value: 'Georgia/GE/+995' },
|
||||||
|
{ label: 'Germany', value: 'Germany/DE/+49' },
|
||||||
|
{ label: 'Ghana', value: 'Ghana/GH/+233' },
|
||||||
|
{ label: 'Greece', value: 'Greece/GR/+30' },
|
||||||
|
{ label: 'Greenland', value: 'Greenland/GL/+45' },
|
||||||
|
{ label: 'Grenada', value: 'Grenada/GD/+1473' },
|
||||||
|
{ label: 'Guam', value: 'Guam/GU/+1' },
|
||||||
|
{ label: 'Guatemala', value: 'Guatemala/GT/+502' },
|
||||||
|
{ label: 'Guinea', value: 'Guinea/GN/+224' },
|
||||||
|
{ label: 'Guinea-Bissau', value: 'Guinea-Bissau/GW/+245' },
|
||||||
|
{ label: 'Guyana', value: 'Guyana/GY/+592' },
|
||||||
|
{ label: 'Haiti', value: 'Haiti/HT/+509' },
|
||||||
|
{ label: 'Honduras', value: 'Honduras/HN/+504' },
|
||||||
|
{ label: 'Hong Kong', value: 'Hong Kong/HK/+852' },
|
||||||
|
{ label: 'Hungary', value: 'Hungary/HU/+36' },
|
||||||
|
{ label: 'Iceland', value: 'Iceland/IS/+354' },
|
||||||
|
{ label: 'India', value: 'India/IN/+91' },
|
||||||
|
{ label: 'Indonesia', value: 'Indonesia/ID/+62' },
|
||||||
|
{ label: 'Iran', value: 'Iran/IR/+98' },
|
||||||
|
{ label: 'Iraq', value: 'Iraq/IQ/+964' },
|
||||||
|
{ label: 'Ireland', value: 'Ireland/IE/+353' },
|
||||||
|
{ label: 'Israel', value: 'Israel/IL/+972' },
|
||||||
|
{ label: 'Italy', value: 'Italy/IT/+39' },
|
||||||
|
{ label: 'Jamaica', value: 'Jamaica/JM/+876' },
|
||||||
|
{ label: 'Japan', value: 'Japan/JP/+81' },
|
||||||
|
{ label: 'Jordan', value: 'Jordan/JO/+962' },
|
||||||
|
{ label: 'Kazakhstan', value: 'Kazakhstan/KZ/+7' },
|
||||||
|
{ label: 'Kenya', value: 'Kenya/KE/+254' },
|
||||||
|
{ label: 'Kiribati', value: 'Kiribati/KI/+686' },
|
||||||
|
{ label: 'Korea', value: 'Korea/KR/+82' },
|
||||||
|
{ label: 'Kuwait', value: 'Kuwait/KW/+965' },
|
||||||
|
{ label: 'Kyrgyzstan', value: 'Kyrgyzstan/KG/+996' },
|
||||||
|
{ label: 'Lao', value: 'Lao/LA/+856' },
|
||||||
|
{ label: 'Latvia', value: 'Latvia/LV/+371' },
|
||||||
|
{ label: 'Lebanon', value: 'Lebanon/LB/+961' },
|
||||||
|
{ label: 'Lesotho', value: 'Lesotho/LS/+266' },
|
||||||
|
{ label: 'Liberia', value: 'Liberia/LR/+231' },
|
||||||
|
{ label: 'Libya', value: 'Libya/LY/+218' },
|
||||||
|
{ label: 'Liechtenstein', value: 'Liechtenstein/LI/+423' },
|
||||||
|
{ label: 'Lithuania', value: 'Lithuania/LT/+370' },
|
||||||
|
{ label: 'Luxembourg', value: 'Luxembourg/LU/+352' },
|
||||||
|
{ label: 'Macao', value: 'Macao/MO/+853' },
|
||||||
|
{ label: 'Macedonia', value: 'Macedonia/MK/+389' },
|
||||||
|
{ label: 'Madagascar', value: 'Madagascar/MG/+261' },
|
||||||
|
{ label: 'Malawi', value: 'Malawi/MW/+265' },
|
||||||
|
{ label: 'Malaysia', value: 'Malaysia/MY/+60' },
|
||||||
|
{ label: 'Maldives', value: 'Maldives/MV/+960' },
|
||||||
|
{ label: 'Mali', value: 'Mali/ML/+223' },
|
||||||
|
{ label: 'Malta', value: 'Malta/MT/+356' },
|
||||||
|
{ label: 'Marshall Islands', value: 'Marshall Islands/MH/+692' },
|
||||||
|
{ label: 'Mauritania', value: 'Mauritania/MR/+222' },
|
||||||
|
{ label: 'Mauritius', value: 'Mauritius/MU/+230' },
|
||||||
|
{ label: 'Mexico', value: 'Mexico/MX/+52' },
|
||||||
|
{ label: 'Micronesia', value: 'Micronesia/FM/+691' },
|
||||||
|
{ label: 'Moldova', value: 'Moldova/MD/+373' },
|
||||||
|
{ label: 'Monaco', value: 'Monaco/MC/+377' },
|
||||||
|
{ label: 'Mongolia', value: 'Mongolia/MN/+976' },
|
||||||
|
{ label: 'Montenegro', value: 'Montenegro/ME/+382' },
|
||||||
|
{ label: 'Morocco', value: 'Morocco/MA/+212' },
|
||||||
|
{ label: 'Mozambique', value: 'Mozambique/MZ/+258' },
|
||||||
|
{ label: 'Myanmar', value: 'Myanmar/MM/+95' },
|
||||||
|
{ label: 'Namibia', value: 'Namibia/NA/+264' },
|
||||||
|
{ label: 'Nauru', value: 'Nauru/NR/+674' },
|
||||||
|
{ label: 'Nepal', value: 'Nepal/NP/+977' },
|
||||||
|
{ label: 'Netherlands', value: 'Netherlands/NL/+31' },
|
||||||
|
{ label: 'Netherlands Antilles', value: 'Netherlands Antilles/AN/+599' },
|
||||||
|
{ label: 'New Caledonia', value: 'New Caledonia/NC/+687' },
|
||||||
|
{ label: 'New Zealand', value: 'New Zealand/NZ/+64' },
|
||||||
|
{ label: 'Nicaragua', value: 'Nicaragua/NI/+505' },
|
||||||
|
{ label: 'Niger', value: 'Niger/NE/+227' },
|
||||||
|
{ label: 'Nigeria', value: 'Nigeria/NG/+234' },
|
||||||
|
{ label: 'Niue', value: 'Niue/NU/+683' },
|
||||||
|
{ label: 'North Korea', value: 'North Korea/KP/+850' },
|
||||||
|
{ label: 'Norway', value: 'Norway/NO/+47' },
|
||||||
|
{ label: 'Oman', value: 'Oman/OM/+968' },
|
||||||
|
{ label: 'Pakistan', value: 'Pakistan/PK/+92' },
|
||||||
|
{ label: 'Palau', value: 'Palau/PW/+680' },
|
||||||
|
{ label: 'Palestine', value: 'Palestine/PS/+970' },
|
||||||
|
{ label: 'Panama', value: 'Panama/PA/+507' },
|
||||||
|
{ label: 'Papua New Guinea', value: 'Papua New Guinea/PG/+675' },
|
||||||
|
{ label: 'Paraguay', value: 'Paraguay/PY/+595' },
|
||||||
|
{ label: 'Peru', value: 'Peru/PE/+51' },
|
||||||
|
{ label: 'Philippines', value: 'Philippines/PH/+63' },
|
||||||
|
{ label: 'Pitcairn Islands', value: 'Pitcairn Islands/PN/+64' },
|
||||||
|
{ label: 'Poland', value: 'Poland/PL/+48' },
|
||||||
|
{ label: 'Portuguese', value: 'Portuguese/PT/+351' },
|
||||||
|
{ label: 'Puerto Rico', value: 'Puerto Rico/PR/+1787' },
|
||||||
|
{ label: 'Qatar', value: 'Qatar/QA/+974' },
|
||||||
|
{ label: 'Romania', value: 'Romania/RO/+40' },
|
||||||
|
{ label: 'Russia', value: 'Russia/RU/+7' },
|
||||||
|
{ label: 'Rwanda', value: 'Rwanda/RW/+250' },
|
||||||
|
{ label: 'Saint Kitts and Nevis', value: 'Saint Kitts and Nevis/KN/+1869' },
|
||||||
|
{ label: 'Saint Lucia', value: 'Saint Lucia/LC/+1758' },
|
||||||
|
{ label: 'Saint Vincent and the Grenadines', value: 'Saint Vincent and the Grenadines/VC/+1784' },
|
||||||
|
{ label: 'Saint-Martin', value: 'Saint-Martin/MF/+1721' },
|
||||||
|
{ label: 'Salvador', value: 'Salvador/SV/+503' },
|
||||||
|
{ label: 'Samoa', value: 'Samoa/WS/+685' },
|
||||||
|
{ label: 'San Marino', value: 'San Marino/SM/+378' },
|
||||||
|
{ label: 'Sao Tome and Principe', value: 'Sao Tome and Principe/ST/+239' },
|
||||||
|
{ label: 'Saudi Arabia', value: 'Saudi Arabia/SA/+966' },
|
||||||
|
{ label: 'Senegal', value: 'Senegal/SN/+221' },
|
||||||
|
{ label: 'Serbia', value: 'Serbia/RS/+381' },
|
||||||
|
{ label: 'Seychelles', value: 'Seychelles/SC/+248' },
|
||||||
|
{ label: 'Sierra Leone', value: 'Sierra Leone/SL/+232' },
|
||||||
|
{ label: 'Singapore', value: 'Singapore/SG/+65' },
|
||||||
|
{ label: 'Slovak', value: 'Slovak/SK/+421' },
|
||||||
|
{ label: 'Slovenia', value: 'Slovenia/SI/+386' },
|
||||||
|
{ label: 'Solomon Islands', value: 'Solomon Islands/SB/+677' },
|
||||||
|
{ label: 'Somalia', value: 'Somalia/SO/+252' },
|
||||||
|
{ label: 'South Africa', value: 'South Africa/ZA/+27' },
|
||||||
|
{ label: 'South Sudan', value: 'South Sudan/SS/+211' },
|
||||||
|
{ label: 'Spain', value: 'Spain/ES/+34' },
|
||||||
|
{ label: 'Sri Lanka', value: 'Sri Lanka/LK/+94' },
|
||||||
|
{ label: 'Sudan', value: 'Sudan/SD/+249' },
|
||||||
|
{ label: 'Suriname', value: 'Suriname/SR/+597' },
|
||||||
|
{ label: 'Swaziland', value: 'Swaziland/SZ/+268' },
|
||||||
|
{ label: 'Sweden', value: 'Sweden/SE/+46' },
|
||||||
|
{ label: 'Swiss', value: 'Swiss/CH/+41' },
|
||||||
|
{ label: 'Syria', value: 'Syria/SY/+963' },
|
||||||
|
{ label: 'Taiwan', value: 'Taiwan/TW/+886' },
|
||||||
|
{ label: 'Tajikistan', value: 'Tajikistan/TJ/+992' },
|
||||||
|
{ label: 'Tanzania', value: 'Tanzania/TZ/+255' },
|
||||||
|
{ label: 'Thailand', value: 'Thailand/TH/+66' },
|
||||||
|
{ label: 'The Cook Islands', value: 'The Cook Islands/CK/+682' },
|
||||||
|
{ label: 'The Turks and Caicos Islands', value: 'The Turks and Caicos Islands/TC/+1649' },
|
||||||
|
{ label: 'The United States Virgin Islands', value: 'The United States Virgin Islands/VI/+1340' },
|
||||||
|
{ label: 'Timor-Leste', value: 'Timor-Leste/TL/+670' },
|
||||||
|
{ label: 'Togo', value: 'Togo/TG/+228' },
|
||||||
|
{ label: 'Tokelau', value: 'Tokelau/TK/+690' },
|
||||||
|
{ label: 'Tonga', value: 'Tonga/TO/+676' },
|
||||||
|
{ label: 'Trinidad and Tobago', value: 'Trinidad and Tobago/TT/+1868' },
|
||||||
|
{ label: 'Tunisia', value: 'Tunisia/TN/+216' },
|
||||||
|
{ label: 'Turkey', value: 'Turkey/TR/+90' },
|
||||||
|
{ label: 'Turkmenistan', value: 'Turkmenistan/TM/+993' },
|
||||||
|
{ label: 'Tuvalu', value: 'Tuvalu/TV/+688' },
|
||||||
|
{ label: 'Uganda', value: 'Uganda/UG/+256' },
|
||||||
|
{ label: 'Ukraine', value: 'Ukraine/UA/+380' },
|
||||||
|
{ label: 'United Arab Emirates', value: 'United Arab Emirates/AE/+971' },
|
||||||
|
{ label: 'United Kingdom', value: 'United Kingdom/UK/+44' },
|
||||||
|
{ label: 'United States', value: 'United States/US/+1' },
|
||||||
|
{ label: 'Uruguay', value: 'Uruguay/UY/+598' },
|
||||||
|
{ label: 'Uzbekistan', value: 'Uzbekistan/UZ/+998' },
|
||||||
|
{ label: 'Vanuatu', value: 'Vanuatu/VU/+678' },
|
||||||
|
{ label: 'Vatican', value: 'Vatican/VA/+379' },
|
||||||
|
{ label: 'Venezuela', value: 'Venezuela/VE/+58' },
|
||||||
|
{ label: 'Vietnam', value: 'Vietnam/VN/+84' },
|
||||||
|
{ label: 'Yemen', value: 'Yemen/YE/+967' },
|
||||||
|
{ label: 'Zambia', value: 'Zambia/ZM/+260' },
|
||||||
|
{ label: 'Zimbabwe', value: 'Zimbabwe/ZW/+263' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 时区选项
|
||||||
|
export const timeZoneOptions = [
|
||||||
|
{ label: 'Pacific/Wake', value: 'Pacific/Wake' },
|
||||||
|
{ label: 'Pacific/Midway', value: 'Pacific/Midway' },
|
||||||
|
{ label: 'Pacific/Honolulu', value: 'Pacific/Honolulu' },
|
||||||
|
{ label: 'America/Anchorage', value: 'America/Anchorage' },
|
||||||
|
{ label: 'America/Los_Angeles', value: 'America/Los_Angeles' },
|
||||||
|
{ label: 'America/Phoenix', value: 'America/Phoenix' },
|
||||||
|
{ label: 'America/Chihuahua', value: 'America/Chihuahua' },
|
||||||
|
{ label: 'America/Denver', value: 'America/Denver' },
|
||||||
|
{ label: 'America/Tegucigalpa', value: 'America/Tegucigalpa' },
|
||||||
|
{ label: 'America/Chicago', value: 'America/Chicago' },
|
||||||
|
{ label: 'America/Mexico_City', value: 'America/Mexico_City' },
|
||||||
|
{ label: 'Canada/Saskatchewan', value: 'Canada/Saskatchewan' },
|
||||||
|
{ label: 'America/Bogota', value: 'America/Bogota' },
|
||||||
|
{ label: 'America/New_York', value: 'America/New_York' },
|
||||||
|
{ label: 'America/Indiana/Indianapolis', value: 'America/Indiana/Indianapolis' },
|
||||||
|
{ label: 'America/Caracas', value: 'America/Caracas' },
|
||||||
|
{ label: 'America/Asuncion', value: 'America/Asuncion' },
|
||||||
|
{ label: 'America/Halifax', value: 'America/Halifax' },
|
||||||
|
{ label: 'America/Cuiaba', value: 'America/Cuiaba' },
|
||||||
|
{ label: 'America/La_Paz', value: 'America/La_Paz' },
|
||||||
|
{ label: 'Canada/Newfoundland', value: 'Canada/Newfoundland' },
|
||||||
|
{ label: 'America/Sao_Paulo', value: 'America/Sao_Paulo' },
|
||||||
|
{ label: 'America/Buenos_Aires', value: 'America/Buenos_Aires' },
|
||||||
|
{ label: 'America/Cayenne', value: 'America/Cayenne' },
|
||||||
|
{ label: 'America/Godthab', value: 'America/Godthab' },
|
||||||
|
{ label: 'America/Montevideo', value: 'America/Montevideo' },
|
||||||
|
{ label: 'America/Santiago', value: 'America/Santiago' },
|
||||||
|
{ label: 'Atlantic/South_Georgia', value: 'Atlantic/South_Georgia' },
|
||||||
|
{ label: 'Atlantic/Azores', value: 'Atlantic/Azores' },
|
||||||
|
{ label: 'Atlantic/Cape_Verde', value: 'Atlantic/Cape_Verde' },
|
||||||
|
{ label: 'Africa/Casablanca', value: 'Africa/Casablanca' },
|
||||||
|
{ label: 'UTC', value: 'UTC' },
|
||||||
|
{ label: 'Europe/London', value: 'Europe/London' },
|
||||||
|
{ label: 'Atlantic/Reykjavik', value: 'Atlantic/Reykjavik' },
|
||||||
|
{ label: 'Europe/Amsterdam', value: 'Europe/Amsterdam' },
|
||||||
|
{ label: 'Europe/Belgrade', value: 'Europe/Belgrade' },
|
||||||
|
{ label: 'Europe/Brussels', value: 'Europe/Brussels' },
|
||||||
|
{ label: 'Europe/Sarajevo', value: 'Europe/Sarajevo' },
|
||||||
|
{ label: 'Africa/Algiers', value: 'Africa/Algiers' },
|
||||||
|
{ label: 'Europe/Athens', value: 'Europe/Athens' },
|
||||||
|
{ label: 'Asia/Beirut', value: 'Asia/Beirut' },
|
||||||
|
{ label: 'Africa/Cairo', value: 'Africa/Cairo' },
|
||||||
|
{ label: 'Asia/Damascus', value: 'Asia/Damascus' },
|
||||||
|
{ label: 'Africa/Harare', value: 'Africa/Harare' },
|
||||||
|
{ label: 'Europe/Vilnius', value: 'Europe/Vilnius' },
|
||||||
|
{ label: 'Asia/Jerusalem', value: 'Asia/Jerusalem' },
|
||||||
|
{ label: 'Asia/Amman', value: 'Asia/Amman' },
|
||||||
|
{ label: 'Asia/Baghdad', value: 'Asia/Baghdad' },
|
||||||
|
{ label: 'Europe/Minsk', value: 'Europe/Minsk' },
|
||||||
|
{ label: 'Asia/Kuwait', value: 'Asia/Kuwait' },
|
||||||
|
{ label: 'Africa/Nairobi', value: 'Africa/Nairobi' },
|
||||||
|
{ label: 'Asia/Istanbul', value: 'Asia/Istanbul' },
|
||||||
|
{ label: 'Asia/Tehran', value: 'Asia/Tehran' },
|
||||||
|
{ label: 'Asia/Muscat', value: 'Asia/Muscat' },
|
||||||
|
{ label: 'Asia/Baku', value: 'Asia/Baku' },
|
||||||
|
{ label: 'Europe/Moscow', value: 'Europe/Moscow' },
|
||||||
|
{ label: 'Asia/Tbilisi', value: 'Asia/Tbilisi' },
|
||||||
|
{ label: 'Asia/Yerevan', value: 'Asia/Yerevan' },
|
||||||
|
{ label: 'Asia/Kabul', value: 'Asia/Kabul' },
|
||||||
|
{ label: 'Asia/Karachi', value: 'Asia/Karachi' },
|
||||||
|
{ label: 'Asia/Yekaterinburg', value: 'Asia/Yekaterinburg' },
|
||||||
|
{ label: 'Asia/Tashkent', value: 'Asia/Tashkent' },
|
||||||
|
{ label: 'Asia/Kolkata', value: 'Asia/Kolkata' },
|
||||||
|
{ label: 'Asia/Colombo', value: 'Asia/Colombo' },
|
||||||
|
{ label: 'Asia/Katmandu', value: 'Asia/Katmandu' },
|
||||||
|
{ label: 'Asia/Dhaka', value: 'Asia/Dhaka' },
|
||||||
|
{ label: 'Asia/Rangoon', value: 'Asia/Rangoon' },
|
||||||
|
{ label: 'Asia/Bangkok', value: 'Asia/Bangkok' },
|
||||||
|
{ label: 'Asia/Novosibirsk', value: 'Asia/Novosibirsk' },
|
||||||
|
{ label: 'Asia/Hong_Kong', value: 'Asia/Hong_Kong' },
|
||||||
|
{ label: 'Asia/Krasnoyarsk', value: 'Asia/Krasnoyarsk' },
|
||||||
|
{ label: 'Asia/Kuala_Lumpur', value: 'Asia/Kuala_Lumpur' },
|
||||||
|
{ label: 'Australia/Perth', value: 'Australia/Perth' },
|
||||||
|
{ label: 'Asia/Taipei', value: 'Asia/Taipei' },
|
||||||
|
{ label: 'Asia/Ulaanbaatar', value: 'Asia/Ulaanbaatar' },
|
||||||
|
{ label: 'Asia/Irkutsk', value: 'Asia/Irkutsk' },
|
||||||
|
{ label: 'Asia/Tokyo', value: 'Asia/Tokyo' },
|
||||||
|
{ label: 'Asia/Seoul', value: 'Asia/Seoul' },
|
||||||
|
{ label: 'Australia/Adelaide', value: 'Australia/Adelaide' },
|
||||||
|
{ label: 'Australia/Darwin', value: 'Australia/Darwin' },
|
||||||
|
{ label: 'Australia/Brisbane', value: 'Australia/Brisbane' },
|
||||||
|
{ label: 'Australia/Canberra', value: 'Australia/Canberra' },
|
||||||
|
{ label: 'Pacific/Guam', value: 'Pacific/Guam' },
|
||||||
|
{ label: 'Australia/Hobart', value: 'Australia/Hobart' },
|
||||||
|
{ label: 'Asia/Yakutsk', value: 'Asia/Yakutsk' },
|
||||||
|
{ label: 'Pacific/Noumea', value: 'Pacific/Noumea' },
|
||||||
|
{ label: 'Asia/Vladivostok', value: 'Asia/Vladivostok' },
|
||||||
|
{ label: 'Pacific/Auckland', value: 'Pacific/Auckland' },
|
||||||
|
{ label: 'Pacific/Fiji', value: 'Pacific/Fiji' },
|
||||||
|
{ label: 'Asia/Magadan', value: 'Asia/Magadan' },
|
||||||
|
{ label: 'Asia/Kamchatka', value: 'Asia/Kamchatka' },
|
||||||
|
{ label: 'Pacific/Tongatapu', value: 'Pacific/Tongatapu' }
|
||||||
|
];
|
||||||
@@ -3,13 +3,16 @@ import { Modal } from 'ant-design-vue';
|
|||||||
import { useAuthStore } from '@/store/modules/auth';
|
import { useAuthStore } from '@/store/modules/auth';
|
||||||
import { useRouterPush } from '@/hooks/common/router';
|
import { useRouterPush } from '@/hooks/common/router';
|
||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
const { t } = useI18n();
|
||||||
|
const router = useRouter();
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'UserAvatar'
|
name: 'UserAvatar'
|
||||||
});
|
});
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const { routerPushByKey, toLogin } = useRouterPush();
|
const { toLogin } = useRouterPush();
|
||||||
|
|
||||||
function loginOrRegister() {
|
function loginOrRegister() {
|
||||||
toLogin();
|
toLogin();
|
||||||
@@ -37,13 +40,17 @@ function logout() {
|
|||||||
</ButtonIcon>
|
</ButtonIcon>
|
||||||
<template #overlay>
|
<template #overlay>
|
||||||
<AMenu>
|
<AMenu>
|
||||||
<!-- <AMenuItem @click="routerPushByKey('user-center')">-->
|
<AMenuItem @click="router.push('/user-center/email')">
|
||||||
<!-- <div class="flex-center gap-8px">-->
|
<div class="flex-center gap-8px">
|
||||||
<!-- <SvgIcon icon="ph:user-circle" class="text-icon" />-->
|
{{ $t('common.setemail') }}
|
||||||
<!-- {{ $t('common.userCenter') }}-->
|
</div>
|
||||||
<!-- </div>-->
|
</AMenuItem>
|
||||||
<!-- </AMenuItem>-->
|
<AMenuItem @click="router.push('/user-center/resetpwd')">
|
||||||
<!-- <AMenuDivider />-->
|
<div class="flex-center gap-8px">
|
||||||
|
{{ $t('common.resetpwd') }}
|
||||||
|
</div>
|
||||||
|
</AMenuItem>
|
||||||
|
<AMenuDivider />
|
||||||
<AMenuItem @click="logout">
|
<AMenuItem @click="logout">
|
||||||
<div class="flex-center gap-8px">
|
<div class="flex-center gap-8px">
|
||||||
<SvgIcon icon="ph:sign-out" class="text-icon" />
|
<SvgIcon icon="ph:sign-out" class="text-icon" />
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ const local: any = {
|
|||||||
columnSetting: 'Column Setting',
|
columnSetting: 'Column Setting',
|
||||||
config: 'Config',
|
config: 'Config',
|
||||||
confirm: 'Confirm',
|
confirm: 'Confirm',
|
||||||
|
submit:'Confirm',
|
||||||
delete: 'Delete',
|
delete: 'Delete',
|
||||||
view: 'View',
|
view: 'View',
|
||||||
exportOk: "Export Completed",
|
exportOk: "Export Completed",
|
||||||
@@ -52,6 +53,8 @@ const local: any = {
|
|||||||
update: 'Update',
|
update: 'Update',
|
||||||
updateSuccess: 'Update Success',
|
updateSuccess: 'Update Success',
|
||||||
userCenter: 'User Center',
|
userCenter: 'User Center',
|
||||||
|
setemail:'Bind Email',
|
||||||
|
resetpwd:'Reset Password',
|
||||||
yesOrNo: {
|
yesOrNo: {
|
||||||
yes: 'Yes',
|
yes: 'Yes',
|
||||||
no: 'No'
|
no: 'No'
|
||||||
@@ -670,6 +673,24 @@ const local: any = {
|
|||||||
clients:'CLIENTS',
|
clients:'CLIENTS',
|
||||||
search:'Search site name',
|
search:'Search site name',
|
||||||
total:'Total',
|
total:'Total',
|
||||||
|
addsite:'Add New Site',
|
||||||
|
region:'Country/Region',
|
||||||
|
timezone:'TimeZone',
|
||||||
|
scenario:'Scenario',
|
||||||
|
username:'Username',
|
||||||
|
password:'Password',
|
||||||
|
deleteConfirmTitle:'Are you sure to delete',
|
||||||
|
deleteConfirmContent:'Are you sure to delete {name}?',
|
||||||
|
confirm:'Confirm',
|
||||||
|
cancel:'Cancel',
|
||||||
|
deleteSuccess:'Delete Success',
|
||||||
|
editsite:'Edit Site',
|
||||||
|
office:'Office',
|
||||||
|
hotel:'Hotel',
|
||||||
|
education:'Education',
|
||||||
|
retail:'Retail',
|
||||||
|
other:'Other',
|
||||||
|
updateSuccess:'Update Success',
|
||||||
},
|
},
|
||||||
headerbanner:{
|
headerbanner:{
|
||||||
controller:'Controller Overview',
|
controller:'Controller Overview',
|
||||||
@@ -1105,7 +1126,42 @@ const local: any = {
|
|||||||
confirm:'Determine',
|
confirm:'Determine',
|
||||||
close:'Cancel',
|
close:'Cancel',
|
||||||
nozero:'The sort must be greater than or equal to 0'
|
nozero:'The sort must be greater than or equal to 0'
|
||||||
}
|
},
|
||||||
|
resetPwd:{
|
||||||
|
title:'Change your password',
|
||||||
|
byEmail:'Change by email',
|
||||||
|
byPassword:'Change by old password',
|
||||||
|
email:'Email',
|
||||||
|
getCode:'Get code',
|
||||||
|
code:'Code',
|
||||||
|
oldPassword:'Old password',
|
||||||
|
newPassword:'New password',
|
||||||
|
confirmPassword:'confirm password',
|
||||||
|
emailPlaceholder:'Please enter the email',
|
||||||
|
codePlaceholder:'Please enter the code',
|
||||||
|
passwordPlaceholder:'Please enter new password',
|
||||||
|
oldPasswordPlaceholder:'Please enter old password',
|
||||||
|
confirmPasswordPlaceholder:'Please enter again',
|
||||||
|
submit:'Confirm',
|
||||||
|
emailRequired:'Email can not be empty',
|
||||||
|
codeSent:'Code enter',
|
||||||
|
success:'Reset Success',
|
||||||
|
},
|
||||||
|
email:{
|
||||||
|
title:'Bind Email',
|
||||||
|
currentEmail:'Current Email',
|
||||||
|
email:'Email',
|
||||||
|
code:'Code',
|
||||||
|
getCode:'Get Code',
|
||||||
|
submit:'Submit',
|
||||||
|
codeSent:'Code Sent',
|
||||||
|
codeRequired:'Code can not be empty',
|
||||||
|
updateSuccess:'Update Success',
|
||||||
|
updateFailed:'Update Failed',
|
||||||
|
emailRequired:'Email can not be empty',
|
||||||
|
emailInvalid:'Email Invalid',
|
||||||
|
codeLength:'Code Invalid',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
required: 'Cannot be empty',
|
required: 'Cannot be empty',
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ const local:any = {
|
|||||||
columnSetting: '列设置',
|
columnSetting: '列设置',
|
||||||
config: '配置',
|
config: '配置',
|
||||||
confirm: '确认',
|
confirm: '确认',
|
||||||
|
submit:'确定',
|
||||||
delete: '删除',
|
delete: '删除',
|
||||||
view:'查看',
|
view:'查看',
|
||||||
exportOk: "已完成导出",
|
exportOk: "已完成导出",
|
||||||
@@ -52,6 +53,8 @@ const local:any = {
|
|||||||
update: '更新',
|
update: '更新',
|
||||||
updateSuccess: '更新成功',
|
updateSuccess: '更新成功',
|
||||||
userCenter: '个人中心',
|
userCenter: '个人中心',
|
||||||
|
setemail:'绑定邮箱',
|
||||||
|
resetpwd:'修改密码',
|
||||||
yesOrNo: {
|
yesOrNo: {
|
||||||
yes: '是',
|
yes: '是',
|
||||||
no: '否'
|
no: '否'
|
||||||
@@ -670,6 +673,24 @@ const local:any = {
|
|||||||
clients:'装置',
|
clients:'装置',
|
||||||
search:'输入站点名称',
|
search:'输入站点名称',
|
||||||
total:'共',
|
total:'共',
|
||||||
|
addsite:'添加站点',
|
||||||
|
region:'国家/地区',
|
||||||
|
timezone:'时区',
|
||||||
|
scenario:'场景',
|
||||||
|
username:'用户名',
|
||||||
|
password:'密码',
|
||||||
|
deleteConfirmTitle:'确定要删除吗',
|
||||||
|
deleteConfirmContent:'确定要删除站点{name}吗?',
|
||||||
|
confirm:'确定',
|
||||||
|
cancel:'取消',
|
||||||
|
deleteSuccess:'删除成功',
|
||||||
|
editsite:'修改配置',
|
||||||
|
office:'办公室',
|
||||||
|
hotel:'医院',
|
||||||
|
education:'教育',
|
||||||
|
retail:'零售业',
|
||||||
|
other:'其他',
|
||||||
|
updateSuccess:'更新成功',
|
||||||
},
|
},
|
||||||
headerbanner:{
|
headerbanner:{
|
||||||
controller:'控制仪表盘',
|
controller:'控制仪表盘',
|
||||||
@@ -1106,7 +1127,42 @@ const local:any = {
|
|||||||
confirm:'确定',
|
confirm:'确定',
|
||||||
close:'取消',
|
close:'取消',
|
||||||
nozero:'排序必须大于等于0'
|
nozero:'排序必须大于等于0'
|
||||||
}
|
},
|
||||||
|
resetPwd:{
|
||||||
|
title:'修改密码',
|
||||||
|
byEmail:'通过邮箱修改密码',
|
||||||
|
byPassword:'通过原密码修改密码',
|
||||||
|
email:'邮箱',
|
||||||
|
getCode:'获取验证码',
|
||||||
|
code:'验证码',
|
||||||
|
oldPassword:'原密码',
|
||||||
|
newPassword:'新密码',
|
||||||
|
confirmPassword:'确认密码',
|
||||||
|
emailPlaceholder:'请输入邮箱',
|
||||||
|
codePlaceholder:'请输入验证码',
|
||||||
|
passwordPlaceholder:'请输入新密码',
|
||||||
|
oldPasswordPlaceholder:'请输入旧密码',
|
||||||
|
confirmPasswordPlaceholder:'请再次输入新密码',
|
||||||
|
submit:'确认',
|
||||||
|
emailRequired:'邮箱不能为空',
|
||||||
|
codeSent:'验证码发送',
|
||||||
|
success:'修改成功',
|
||||||
|
},
|
||||||
|
email:{
|
||||||
|
title:'绑定邮箱',
|
||||||
|
currentEmail:'当前邮箱',
|
||||||
|
email:'新邮箱',
|
||||||
|
code:'验证码',
|
||||||
|
getCode:'获取验证码',
|
||||||
|
submit:'确定',
|
||||||
|
codeSent:'验证码发送',
|
||||||
|
codeRequired:'验证码不能为空',
|
||||||
|
updateSuccess:'修改成功',
|
||||||
|
updateFailed:'修改失败',
|
||||||
|
emailRequired:'邮箱不能为空',
|
||||||
|
emailInvalid:'邮箱格式错误',
|
||||||
|
codeLength:'验证码长度错误',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
required: '不能为空',
|
required: '不能为空',
|
||||||
|
|||||||
@@ -200,7 +200,9 @@ const routeMap: RouteMap = {
|
|||||||
'function_toggle-auth': '/function/toggle-auth',
|
'function_toggle-auth': '/function/toggle-auth',
|
||||||
'dashboard': '/dashboard',
|
'dashboard': '/dashboard',
|
||||||
'login': '/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?',
|
'login': '/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?',
|
||||||
'user-center': '/user-center'
|
'user-center': '/user-center',
|
||||||
|
'reset-pwd':'/reset-pwd',
|
||||||
|
'forgot-pwd':'/user-center/resetpwd'
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -407,12 +407,6 @@ export function deletePortal(siteId: string, portalId: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** 首页邮箱重置密码 */
|
/** 首页邮箱重置密码 */
|
||||||
export function fetcodeReset(data:any) {
|
export function fetcodeReset(data:any) {
|
||||||
return request({
|
return request({
|
||||||
@@ -421,6 +415,81 @@ export function fetcodeReset(data:any) {
|
|||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/** 获取邮箱验证码 */
|
||||||
|
export function getEmailCode(email: string) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/email/code`,
|
||||||
|
method: 'get',
|
||||||
|
params: { email }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置密码 */
|
||||||
|
export function resetPassword(data: { email: string; code: string; password: string }) {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/user/profile/forgotPwd',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 通过原密码修改密码 */
|
||||||
|
export function updatePasswordByOld(data: { oldPassword: string; newPassword: string }) {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/user/profile/updatePwd',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 添加站点 */
|
||||||
|
export function addSite(data: Api.Site.AddSiteParams) {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/site',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除站点 */
|
||||||
|
export function deleteSite(siteId: string) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/site/${siteId}`,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取站点配置 */
|
||||||
|
export function getSiteConfig(siteId: string) {
|
||||||
|
return request<Api.Site.SiteConfig>({
|
||||||
|
url: `/system/site/${siteId}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 更新站点配置 */
|
||||||
|
export function updateSite(siteId: string, data: Api.Site.UpdateSiteParams) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/site/${siteId}`,
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取用户信息 */
|
||||||
|
export function getUserProfile() {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/user/profile',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新用户信息 */
|
||||||
|
export function updateUserProfile(data: { email: string; code: string }) {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/user/profile',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
24
src/typings/api.d.ts
vendored
24
src/typings/api.d.ts
vendored
@@ -788,6 +788,30 @@ declare namespace Api {
|
|||||||
supportL2: boolean;
|
supportL2: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface AddSiteParams {
|
||||||
|
name: string;
|
||||||
|
region: string;
|
||||||
|
timeZone: string;
|
||||||
|
scenario: string;
|
||||||
|
deviceAccountSetting: {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
interface SiteConfig {
|
||||||
|
name: string;
|
||||||
|
region: string;
|
||||||
|
timeZone: string;
|
||||||
|
scenario: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateSiteParams {
|
||||||
|
name: string;
|
||||||
|
region: string;
|
||||||
|
timeZone: string;
|
||||||
|
scenario: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface SiteParams {
|
interface SiteParams {
|
||||||
pageNum: number;
|
pageNum: number;
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
|
|||||||
9
src/typings/auto-imports.d.ts
vendored
9
src/typings/auto-imports.d.ts
vendored
@@ -16,6 +16,7 @@ declare global {
|
|||||||
const addPackage: typeof import('../service/api/auth')['addPackage']
|
const addPackage: typeof import('../service/api/auth')['addPackage']
|
||||||
const addPortal: typeof import('../service/api/auth')['addPortal']
|
const addPortal: typeof import('../service/api/auth')['addPortal']
|
||||||
const addRateLimit: typeof import('../service/api/auth')['addRateLimit']
|
const addRateLimit: typeof import('../service/api/auth')['addRateLimit']
|
||||||
|
const addSite: typeof import('../service/api/auth')['addSite']
|
||||||
const addThemeVarsToHtml: typeof import('../store/modules/theme/shared')['addThemeVarsToHtml']
|
const addThemeVarsToHtml: typeof import('../store/modules/theme/shared')['addThemeVarsToHtml']
|
||||||
const addWlanSsid: typeof import('../service/api/auth')['addWlanSsid']
|
const addWlanSsid: typeof import('../service/api/auth')['addWlanSsid']
|
||||||
const adoptApDevice: typeof import('../service/api/auth')['adoptApDevice']
|
const adoptApDevice: typeof import('../service/api/auth')['adoptApDevice']
|
||||||
@@ -68,6 +69,7 @@ declare global {
|
|||||||
const deleteApDevices: typeof import('../service/api/auth')['deleteApDevices']
|
const deleteApDevices: typeof import('../service/api/auth')['deleteApDevices']
|
||||||
const deletePackage: typeof import('../service/api/auth')['deletePackage']
|
const deletePackage: typeof import('../service/api/auth')['deletePackage']
|
||||||
const deletePortal: typeof import('../service/api/auth')['deletePortal']
|
const deletePortal: typeof import('../service/api/auth')['deletePortal']
|
||||||
|
const deleteSite: typeof import('../service/api/auth')['deleteSite']
|
||||||
const deleteWlanSsid: typeof import('../service/api/auth')['deleteWlanSsid']
|
const deleteWlanSsid: typeof import('../service/api/auth')['deleteWlanSsid']
|
||||||
const describe: typeof import('vitest')['describe']
|
const describe: typeof import('vitest')['describe']
|
||||||
const dict: typeof import('../store/modules/dict/index')['default']
|
const dict: typeof import('../store/modules/dict/index')['default']
|
||||||
@@ -176,6 +178,7 @@ declare global {
|
|||||||
const getDefaultHomeTab: typeof import('../store/modules/tab/shared')['getDefaultHomeTab']
|
const getDefaultHomeTab: typeof import('../store/modules/tab/shared')['getDefaultHomeTab']
|
||||||
const getDictDataType: typeof import('../service/api/dict')['getDictDataType']
|
const getDictDataType: typeof import('../service/api/dict')['getDictDataType']
|
||||||
const getDictOptionselect: typeof import('../service/api/dict')['getDictOptionselect']
|
const getDictOptionselect: typeof import('../service/api/dict')['getDictOptionselect']
|
||||||
|
const getEmailCode: typeof import('../service/api/auth')['getEmailCode']
|
||||||
const getFixedTabIds: typeof import('../store/modules/tab/shared')['getFixedTabIds']
|
const getFixedTabIds: typeof import('../store/modules/tab/shared')['getFixedTabIds']
|
||||||
const getFixedTabs: typeof import('../store/modules/tab/shared')['getFixedTabs']
|
const getFixedTabs: typeof import('../store/modules/tab/shared')['getFixedTabs']
|
||||||
const getGlobalMenusByAuthRoutes: typeof import('../store/modules/route/shared')['getGlobalMenusByAuthRoutes']
|
const getGlobalMenusByAuthRoutes: typeof import('../store/modules/route/shared')['getGlobalMenusByAuthRoutes']
|
||||||
@@ -184,9 +187,11 @@ declare global {
|
|||||||
const getRouteIcons: typeof import('../store/modules/tab/shared')['getRouteIcons']
|
const getRouteIcons: typeof import('../store/modules/tab/shared')['getRouteIcons']
|
||||||
const getSelectedMenuKeyPathByKey: typeof import('../store/modules/route/shared')['getSelectedMenuKeyPathByKey']
|
const getSelectedMenuKeyPathByKey: typeof import('../store/modules/route/shared')['getSelectedMenuKeyPathByKey']
|
||||||
const getServiceBaseURL: typeof import('../utils/service')['getServiceBaseURL']
|
const getServiceBaseURL: typeof import('../utils/service')['getServiceBaseURL']
|
||||||
|
const getSiteConfig: typeof import('../service/api/auth')['getSiteConfig']
|
||||||
const getTabByRoute: typeof import('../store/modules/tab/shared')['getTabByRoute']
|
const getTabByRoute: typeof import('../store/modules/tab/shared')['getTabByRoute']
|
||||||
const getTabIdByRoute: typeof import('../store/modules/tab/shared')['getTabIdByRoute']
|
const getTabIdByRoute: typeof import('../store/modules/tab/shared')['getTabIdByRoute']
|
||||||
const getToken: typeof import('../store/modules/auth/shared')['getToken']
|
const getToken: typeof import('../store/modules/auth/shared')['getToken']
|
||||||
|
const getUserProfile: typeof import('../service/api/auth')['getUserProfile']
|
||||||
const getWlanSsidConfig: typeof import('../service/api/auth')['getWlanSsidConfig']
|
const getWlanSsidConfig: typeof import('../service/api/auth')['getWlanSsidConfig']
|
||||||
const h: typeof import('vue')['h']
|
const h: typeof import('vue')['h']
|
||||||
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
|
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
|
||||||
@@ -255,6 +260,7 @@ declare global {
|
|||||||
const rejectKyc: typeof import('../service/api/auth')['rejectKyc']
|
const rejectKyc: typeof import('../service/api/auth')['rejectKyc']
|
||||||
const removeEmptyChildren: typeof import('../utils/menu')['removeEmptyChildren']
|
const removeEmptyChildren: typeof import('../utils/menu')['removeEmptyChildren']
|
||||||
const removeRateLimit: typeof import('../service/api/auth')['removeRateLimit']
|
const removeRateLimit: typeof import('../service/api/auth')['removeRateLimit']
|
||||||
|
const resetPassword: typeof import('../service/api/auth')['resetPassword']
|
||||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||||
const resolveRef: typeof import('@vueuse/core')['resolveRef']
|
const resolveRef: typeof import('@vueuse/core')['resolveRef']
|
||||||
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
|
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
|
||||||
@@ -306,9 +312,12 @@ declare global {
|
|||||||
const updateJob: typeof import('../service/api/job')['updateJob']
|
const updateJob: typeof import('../service/api/job')['updateJob']
|
||||||
const updateLocaleOfGlobalMenus: typeof import('../store/modules/route/shared')['updateLocaleOfGlobalMenus']
|
const updateLocaleOfGlobalMenus: typeof import('../store/modules/route/shared')['updateLocaleOfGlobalMenus']
|
||||||
const updatePackage: typeof import('../service/api/auth')['updatePackage']
|
const updatePackage: typeof import('../service/api/auth')['updatePackage']
|
||||||
|
const updatePasswordByOld: typeof import('../service/api/auth')['updatePasswordByOld']
|
||||||
const updatePortalConfig: typeof import('../service/api/auth')['updatePortalConfig']
|
const updatePortalConfig: typeof import('../service/api/auth')['updatePortalConfig']
|
||||||
|
const updateSite: typeof import('../service/api/auth')['updateSite']
|
||||||
const updateTabByI18nKey: typeof import('../store/modules/tab/shared')['updateTabByI18nKey']
|
const updateTabByI18nKey: typeof import('../store/modules/tab/shared')['updateTabByI18nKey']
|
||||||
const updateTabsByI18nKey: typeof import('../store/modules/tab/shared')['updateTabsByI18nKey']
|
const updateTabsByI18nKey: typeof import('../store/modules/tab/shared')['updateTabsByI18nKey']
|
||||||
|
const updateUserProfile: typeof import('../service/api/auth')['updateUserProfile']
|
||||||
const updateWlanSsid: typeof import('../service/api/auth')['updateWlanSsid']
|
const updateWlanSsid: typeof import('../service/api/auth')['updateWlanSsid']
|
||||||
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
|
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
|
||||||
const useAnimate: typeof import('@vueuse/core')['useAnimate']
|
const useAnimate: typeof import('@vueuse/core')['useAnimate']
|
||||||
|
|||||||
@@ -4,15 +4,107 @@ import type { TableColumnType } from 'ant-design-vue';
|
|||||||
import {
|
import {
|
||||||
EnvironmentOutlined,
|
EnvironmentOutlined,
|
||||||
SearchOutlined,
|
SearchOutlined,
|
||||||
|
PlusOutlined,
|
||||||
|
EditOutlined,
|
||||||
|
DeleteOutlined
|
||||||
} from '@ant-design/icons-vue';
|
} from '@ant-design/icons-vue';
|
||||||
import { getDashboardSiteList } from '@/service/api/auth';
|
import { getDashboardSiteList, addSite, deleteSite, getSiteConfig, updateSite } from '@/service/api/auth';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { Form, Modal } from 'ant-design-vue';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import { regionOptions, timeZoneOptions } from '@/constants/site-options';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'CardData'
|
name: 'CardData'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 表单实例
|
||||||
|
const formRef = ref();
|
||||||
|
const useForm = Form.useForm;
|
||||||
|
|
||||||
|
// 弹窗控制
|
||||||
|
const showAddDialog = ref(false);
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const formData = ref({
|
||||||
|
name: '',
|
||||||
|
region: '',
|
||||||
|
timeZone: '',
|
||||||
|
scenario: '',
|
||||||
|
deviceAccountSetting: {
|
||||||
|
username: '',
|
||||||
|
password: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const { validate, validateInfos } = useForm(formData, {
|
||||||
|
name: [
|
||||||
|
{ required: true, message: t('page.carddata.nameRequired') },
|
||||||
|
{
|
||||||
|
pattern: /^[^ \+\-\@\=]$|^[^ \+\-\@\=].{0,62}[^ ]$/,
|
||||||
|
message: t('page.carddata.nameInvalid')
|
||||||
|
}
|
||||||
|
],
|
||||||
|
region: [{ required: true, message: t('page.carddata.regionRequired') }],
|
||||||
|
timeZone: [{ required: true, message: t('page.carddata.timeZoneRequired') }],
|
||||||
|
scenario: [{ required: true, message: t('page.carddata.scenarioRequired') }],
|
||||||
|
'deviceAccountSetting.username': [
|
||||||
|
{ required: true, message: t('page.carddata.usernameRequired') },
|
||||||
|
{
|
||||||
|
pattern: /^[\x21-\x7E]{1,64}$/,
|
||||||
|
message: t('page.carddata.usernameInvalid')
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'deviceAccountSetting.password': [
|
||||||
|
{ required: true, message: t('page.carddata.passwordRequired') },
|
||||||
|
{
|
||||||
|
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\!\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\@\[\\\]\^\_\`\{\|\}\~])(?!.*[\00-\040\042\077\0177]).{8,64}$/,
|
||||||
|
message: t('page.carddata.passwordInvalid')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// 使用场景选项
|
||||||
|
const scenarioOptions = [
|
||||||
|
{ label: t('page.carddata.office'), value: 'office' },
|
||||||
|
{ label: t('page.carddata.hotel'), value: 'hotel' },
|
||||||
|
{ label: t('page.carddata.education'), value: 'education' },
|
||||||
|
{ label: t('page.carddata.retail'), value: 'retail' },
|
||||||
|
{ label: t('page.carddata.other'), value: 'other' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 处理添加站点
|
||||||
|
const handleAddSite = async () => {
|
||||||
|
try {
|
||||||
|
await validate();
|
||||||
|
const response = await addSite(formData.value);
|
||||||
|
if (response) {
|
||||||
|
message.success(t('page.carddata.addSuccess'));
|
||||||
|
showAddDialog.value = false;
|
||||||
|
fetchSiteList(); // 刷新列表
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Add site failed:', error);
|
||||||
|
message.error(t('page.carddata.addFailed'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开添加对话框
|
||||||
|
const openAddDialog = () => {
|
||||||
|
formData.value = {
|
||||||
|
name: '',
|
||||||
|
region: '',
|
||||||
|
timeZone: '',
|
||||||
|
scenario: '',
|
||||||
|
deviceAccountSetting: {
|
||||||
|
username: '',
|
||||||
|
password: ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
showAddDialog.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
// 搜索和分页状态
|
// 搜索和分页状态
|
||||||
const searchValue = ref('');
|
const searchValue = ref('');
|
||||||
@@ -100,25 +192,37 @@ const columns: TableColumnType<Api.DashboardSite>[] = [
|
|||||||
key: 'clients',
|
key: 'clients',
|
||||||
width: 150
|
width: 150
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// title: 'ACTION',
|
title: 'ACTION',
|
||||||
// key: 'action',
|
key: 'action',
|
||||||
// width: 150,
|
width: 100,
|
||||||
// fixed: 'right'
|
fixed: 'right'
|
||||||
// }
|
}
|
||||||
];
|
];
|
||||||
// 按钮操作处理函数
|
// 按钮操作处理函数
|
||||||
// const handleEdit = (record: Api.DashboardSite) => {
|
|
||||||
// console.log('Edit:', record);
|
|
||||||
// };
|
|
||||||
//
|
//
|
||||||
// const handleCopy = (record: Api.DashboardSite) => {
|
// const handleCopy = (record: Api.DashboardSite) => {
|
||||||
// console.log('Copy:', record);
|
// console.log('Copy:', record);
|
||||||
// };
|
// };
|
||||||
//
|
//
|
||||||
// const handleDelete = (record: Api.DashboardSite) => {
|
const handleDelete = (record: Api.DashboardSite) => {
|
||||||
// console.log('Delete:', record);
|
Modal.confirm({
|
||||||
// };
|
title: t('page.carddata.deleteConfirmTitle'),
|
||||||
|
content: t('page.carddata.deleteConfirmContent', { name: record.name }),
|
||||||
|
okText: t('page.carddata.confirm'),
|
||||||
|
cancelText: t('page.carddata.cancel'),
|
||||||
|
okType: 'danger',
|
||||||
|
async onOk() {
|
||||||
|
try {
|
||||||
|
await deleteSite(record.siteId);
|
||||||
|
message.success(t('page.carddata.deleteSuccess'));
|
||||||
|
fetchSiteList(); // 刷新列表
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
//
|
//
|
||||||
// const handleHome = (record: Api.DashboardSite) => {
|
// const handleHome = (record: Api.DashboardSite) => {
|
||||||
// console.log('Home:', record);
|
// console.log('Home:', record);
|
||||||
@@ -136,6 +240,68 @@ const handlePageSizeChange = (size: number) => {
|
|||||||
pageSize.value = size;
|
pageSize.value = size;
|
||||||
currentPage.value = 1;
|
currentPage.value = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 编辑弹窗控制
|
||||||
|
const showEditDialog = ref(false);
|
||||||
|
|
||||||
|
// 编辑表单数据
|
||||||
|
const editFormData = ref({
|
||||||
|
name: '',
|
||||||
|
region: '',
|
||||||
|
timeZone: '',
|
||||||
|
scenario: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
// 当前编辑的站点ID
|
||||||
|
const currentEditSiteId = ref('');
|
||||||
|
|
||||||
|
// 编辑表单验证规则
|
||||||
|
const { validate: validateEdit, validateInfos: validateEditInfos } = useForm(editFormData, {
|
||||||
|
name: [
|
||||||
|
{ required: true, message: t('page.carddata.nameRequired') },
|
||||||
|
{
|
||||||
|
pattern: /^[^ \+\-\@\=]$|^[^ \+\-\@\=].{0,62}[^ ]$/,
|
||||||
|
message: t('page.carddata.nameInvalid')
|
||||||
|
}
|
||||||
|
],
|
||||||
|
region: [{ required: true, message: t('page.carddata.regionRequired') }],
|
||||||
|
timeZone: [{ required: true, message: t('page.carddata.timeZoneRequired') }],
|
||||||
|
scenario: [{ required: true, message: t('page.carddata.scenarioRequired') }]
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理编辑按钮点击
|
||||||
|
const handleEdit = async (record: Api.DashboardSite) => {
|
||||||
|
try {
|
||||||
|
currentEditSiteId.value = record.siteId;
|
||||||
|
const response = await getSiteConfig(record.siteId);
|
||||||
|
if (response.data) {
|
||||||
|
editFormData.value = {
|
||||||
|
name: response.data.name,
|
||||||
|
region: response.data.region,
|
||||||
|
timeZone: response.data.timeZone,
|
||||||
|
scenario: response.data.scenario
|
||||||
|
};
|
||||||
|
showEditDialog.value = true;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Get site config failed:', error);
|
||||||
|
message.error(t('page.carddata.getConfigFailed'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理更新站点
|
||||||
|
const handleUpdateSite = async () => {
|
||||||
|
try {
|
||||||
|
await validateEdit();
|
||||||
|
await updateSite(currentEditSiteId.value, editFormData.value);
|
||||||
|
message.success(t('page.carddata.updateSuccess'));
|
||||||
|
showEditDialog.value = false;
|
||||||
|
fetchSiteList(); // 刷新列表
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Update site failed:', error);
|
||||||
|
message.error(t('page.carddata.updateFailed'));
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -155,18 +321,12 @@ const handlePageSizeChange = (size: number) => {
|
|||||||
<search-outlined />
|
<search-outlined />
|
||||||
</template>
|
</template>
|
||||||
</AInput>
|
</AInput>
|
||||||
<!-- <AButton type="primary">-->
|
<AButton type="primary" @click="openAddDialog">
|
||||||
<!-- <template #icon>-->
|
<template #icon>
|
||||||
<!-- <plus-outlined />-->
|
<plus-outlined />
|
||||||
<!-- </template>-->
|
</template>
|
||||||
<!-- Import Site-->
|
{{ t('page.carddata.addsite') }}
|
||||||
<!-- </AButton>-->
|
</AButton>
|
||||||
<!-- <AButton type="primary">-->
|
|
||||||
<!-- <template #icon>-->
|
|
||||||
<!-- <plus-outlined />-->
|
|
||||||
<!-- </template>-->
|
|
||||||
<!-- Add New Site-->
|
|
||||||
<!-- </AButton>-->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -221,16 +381,157 @@ const handlePageSizeChange = (size: number) => {
|
|||||||
<template v-else-if="column.key === 'clients'">
|
<template v-else-if="column.key === 'clients'">
|
||||||
<span>{{ record.wiredClientNum }}/{{ record.wirelessClientNum }}/{{ record.guestNum }}</span>
|
<span>{{ record.wiredClientNum }}/{{ record.wirelessClientNum }}/{{ record.guestNum }}</span>
|
||||||
</template>
|
</template>
|
||||||
<!-- <template v-else-if="column.key === 'action'">-->
|
<template v-else-if="column.key === 'action'">
|
||||||
<!-- <div class="flex items-center gap-8px">-->
|
<div class="flex items-center gap-8px">
|
||||||
<!-- <edit-outlined class="cursor-pointer text-primary" @click="handleEdit(record)" />-->
|
<edit-outlined class="cursor-pointer text-primary" @click="handleEdit(record)" />
|
||||||
<!-- <copy-outlined class="cursor-pointer text-primary" @click="handleCopy(record)" />-->
|
<!-- <copy-outlined class="cursor-pointer text-primary" @click="handleCopy(record)" />-->
|
||||||
<!-- <delete-outlined class="cursor-pointer text-red-500" @click="handleDelete(record)" />-->
|
<delete-outlined class="cursor-pointer text-red-500" @click="handleDelete(record)" />
|
||||||
<!-- <home-outlined class="cursor-pointer text-primary" @click="handleHome(record)" />-->
|
<!-- <home-outlined class="cursor-pointer text-primary" @click="handleHome(record)" />-->
|
||||||
<!-- </div>-->
|
</div>
|
||||||
<!-- </template>-->
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</ATable>
|
</ATable>
|
||||||
|
|
||||||
|
<!-- 添加站点对话框 -->
|
||||||
|
<AModal
|
||||||
|
v-model:visible="showAddDialog"
|
||||||
|
:title="t('page.carddata.addsite')"
|
||||||
|
@ok="handleAddSite"
|
||||||
|
@cancel="showAddDialog = false"
|
||||||
|
:maskClosable="false"
|
||||||
|
>
|
||||||
|
<AForm
|
||||||
|
ref="formRef"
|
||||||
|
:model="formData"
|
||||||
|
:label-col="{ span: 6 }"
|
||||||
|
:wrapper-col="{ span: 18 }"
|
||||||
|
>
|
||||||
|
<AFormItem
|
||||||
|
name="name"
|
||||||
|
:label="t('page.carddata.sitename')"
|
||||||
|
v-bind="validateInfos.name"
|
||||||
|
>
|
||||||
|
<AInput v-model:value="formData.name" />
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="region"
|
||||||
|
:label="t('page.carddata.region')"
|
||||||
|
v-bind="validateInfos.region"
|
||||||
|
>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="formData.region"
|
||||||
|
:options="regionOptions"
|
||||||
|
show-search
|
||||||
|
:filter-option="(input, option) =>
|
||||||
|
option?.label?.toLowerCase().includes(input.toLowerCase())"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="timeZone"
|
||||||
|
:label="t('page.carddata.timezone')"
|
||||||
|
v-bind="validateInfos.timeZone"
|
||||||
|
>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="formData.timeZone"
|
||||||
|
:options="timeZoneOptions"
|
||||||
|
show-search
|
||||||
|
:filter-option="(input, option) =>
|
||||||
|
option?.label?.toLowerCase().includes(input.toLowerCase())"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="scenario"
|
||||||
|
:label="t('page.carddata.scenario')"
|
||||||
|
v-bind="validateInfos.scenario"
|
||||||
|
>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="formData.scenario"
|
||||||
|
:options="scenarioOptions"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="deviceAccountSetting.username"
|
||||||
|
:label="t('page.carddata.username')"
|
||||||
|
v-bind="validateInfos['deviceAccountSetting.username']"
|
||||||
|
>
|
||||||
|
<AInput v-model:value="formData.deviceAccountSetting.username" />
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="deviceAccountSetting.password"
|
||||||
|
:label="t('page.carddata.password')"
|
||||||
|
v-bind="validateInfos['deviceAccountSetting.password']"
|
||||||
|
>
|
||||||
|
<AInputPassword v-model:value="formData.deviceAccountSetting.password" />
|
||||||
|
</AFormItem>
|
||||||
|
</AForm>
|
||||||
|
</AModal>
|
||||||
|
|
||||||
|
<!-- 编辑站点对话框 -->
|
||||||
|
<AModal
|
||||||
|
v-model:visible="showEditDialog"
|
||||||
|
:title="t('page.carddata.editsite')"
|
||||||
|
@ok="handleUpdateSite"
|
||||||
|
@cancel="showEditDialog = false"
|
||||||
|
:maskClosable="false"
|
||||||
|
>
|
||||||
|
<AForm
|
||||||
|
:model="editFormData"
|
||||||
|
:label-col="{ span: 6 }"
|
||||||
|
:wrapper-col="{ span: 18 }"
|
||||||
|
>
|
||||||
|
<AFormItem
|
||||||
|
name="name"
|
||||||
|
:label="t('page.carddata.sitename')"
|
||||||
|
v-bind="validateEditInfos.name"
|
||||||
|
>
|
||||||
|
<AInput v-model:value="editFormData.name" />
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="region"
|
||||||
|
:label="t('page.carddata.region')"
|
||||||
|
v-bind="validateEditInfos.region"
|
||||||
|
>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="editFormData.region"
|
||||||
|
:options="regionOptions"
|
||||||
|
show-search
|
||||||
|
:filter-option="(input, option) =>
|
||||||
|
option?.label?.toLowerCase().includes(input.toLowerCase())"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="timeZone"
|
||||||
|
:label="t('page.carddata.timezone')"
|
||||||
|
v-bind="validateEditInfos.timeZone"
|
||||||
|
>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="editFormData.timeZone"
|
||||||
|
:options="timeZoneOptions"
|
||||||
|
show-search
|
||||||
|
:filter-option="(input, option) =>
|
||||||
|
option?.label?.toLowerCase().includes(input.toLowerCase())"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="scenario"
|
||||||
|
:label="t('page.carddata.scenario')"
|
||||||
|
v-bind="validateEditInfos.scenario"
|
||||||
|
>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="editFormData.scenario"
|
||||||
|
:options="scenarioOptions"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
</AForm>
|
||||||
|
</AModal>
|
||||||
</ACard>
|
</ACard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
211
src/views/user-center/email/index.vue
Normal file
211
src/views/user-center/email/index.vue
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import { Form, message } from 'ant-design-vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { getEmailCode, getUserProfile, updateUserProfile } from '@/service/api/auth';
|
||||||
|
import request from '@/service/request';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const useForm = Form.useForm;
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const formData = ref({
|
||||||
|
email: '',
|
||||||
|
code: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
// 当前邮箱
|
||||||
|
const currentEmail = ref('');
|
||||||
|
|
||||||
|
// 倒计时
|
||||||
|
const countdown = ref(0);
|
||||||
|
const timer = ref<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const { validate, validateInfos } = useForm(formData, {
|
||||||
|
email: [
|
||||||
|
{ required: true, message: t('page.email.emailRequired') },
|
||||||
|
{ type: 'email', message: t('page.email.emailInvalid') }
|
||||||
|
],
|
||||||
|
code: [
|
||||||
|
{ required: true, message: t('page.email.codeRequired') },
|
||||||
|
{ len: 4, message: t('page.email.codeLength') }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取当前用户邮箱
|
||||||
|
const getCurrentEmail = async () => {
|
||||||
|
try {
|
||||||
|
const response = await getUserProfile();
|
||||||
|
if (response.data) {
|
||||||
|
currentEmail.value = response.data.email || '';
|
||||||
|
if (currentEmail.value) {
|
||||||
|
formData.value.email = currentEmail.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 开始倒计时
|
||||||
|
const startCountdown = () => {
|
||||||
|
countdown.value = 60;
|
||||||
|
timer.value = setInterval(() => {
|
||||||
|
if (countdown.value > 0) {
|
||||||
|
countdown.value--;
|
||||||
|
} else {
|
||||||
|
if (timer.value) {
|
||||||
|
clearInterval(timer.value);
|
||||||
|
timer.value = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取验证码
|
||||||
|
const handleGetCode = async () => {
|
||||||
|
try {
|
||||||
|
// 验证邮箱
|
||||||
|
await validate(['email']);
|
||||||
|
|
||||||
|
// 发送获取验证码请求
|
||||||
|
await getEmailCode(formData.value.email);
|
||||||
|
message.success(t('page.email.codeSent'));
|
||||||
|
startCountdown();
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交表单
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
try {
|
||||||
|
await validate();
|
||||||
|
await updateUserProfile({
|
||||||
|
email: formData.value.email,
|
||||||
|
code: formData.value.code
|
||||||
|
});
|
||||||
|
message.success(t('page.email.updateSuccess'));
|
||||||
|
formData.value.code = ''; // 清空验证码
|
||||||
|
setTimeout(async () => {
|
||||||
|
await getCurrentEmail(); // 刷新当前邮箱
|
||||||
|
}, 500);
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 组件挂载时获取当前邮箱
|
||||||
|
onMounted(() => {
|
||||||
|
getCurrentEmail();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 组件卸载时清除定时器
|
||||||
|
const onUnmounted = () => {
|
||||||
|
if (timer.value) {
|
||||||
|
clearInterval(timer.value);
|
||||||
|
timer.value = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="email-binding">
|
||||||
|
<ACard :bordered="false">
|
||||||
|
<h2 class="mb-4">{{ t('page.email.title') }}</h2>
|
||||||
|
|
||||||
|
<div v-if="currentEmail" class="mb-4">
|
||||||
|
{{ t('page.email.currentEmail') }}: {{ currentEmail }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<AForm
|
||||||
|
:model="formData"
|
||||||
|
:label-col="{ span: 4 }"
|
||||||
|
:wrapper-col="{ span: 16 }"
|
||||||
|
>
|
||||||
|
<AFormItem
|
||||||
|
name="email"
|
||||||
|
:label="t('page.email.email')"
|
||||||
|
v-bind="validateInfos.email"
|
||||||
|
class="form-item-gap"
|
||||||
|
>
|
||||||
|
<AInput v-model:value="formData.email" />
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="code"
|
||||||
|
:label="t('page.email.code')"
|
||||||
|
v-bind="validateInfos.code"
|
||||||
|
class="form-item-gap"
|
||||||
|
>
|
||||||
|
<div class="verification-code-wrapper">
|
||||||
|
<AInput v-model:value="formData.code" class="verification-input" />
|
||||||
|
<AButton
|
||||||
|
type="primary"
|
||||||
|
:disabled="countdown > 0"
|
||||||
|
@click="handleGetCode"
|
||||||
|
class="verification-button"
|
||||||
|
>
|
||||||
|
{{ countdown > 0 ? `${countdown}s` : t('page.email.getCode') }}
|
||||||
|
</AButton>
|
||||||
|
</div>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem :wrapper-col="{ offset: 4, span: 16 }">
|
||||||
|
<AButton type="primary" @click="handleSubmit">
|
||||||
|
{{ t('page.email.submit') }}
|
||||||
|
</AButton>
|
||||||
|
</AFormItem>
|
||||||
|
</AForm>
|
||||||
|
</ACard>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.email-binding {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-4 {
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-4 {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item-gap {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-form-item-label) {
|
||||||
|
padding-right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verification-code-wrapper {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verification-input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verification-button {
|
||||||
|
width: 120px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-form-item) {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-input-affix-wrapper) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
219
src/views/user-center/resetpwd/index.vue
Normal file
219
src/views/user-center/resetpwd/index.vue
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, computed } from 'vue';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { getEmailCode, resetPassword, updatePasswordByOld } from '@/service/api/auth';
|
||||||
|
import { useRouterPush } from '@/hooks/common/router';
|
||||||
|
import { useFormRules } from '@/hooks/common/form';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { routerPushByKey } = useRouterPush();
|
||||||
|
|
||||||
|
// 修改方式
|
||||||
|
const resetType = ref('email'); // 'email' | 'password'
|
||||||
|
|
||||||
|
// 邮箱验证表单数据
|
||||||
|
const emailFormData = reactive({
|
||||||
|
email: '',
|
||||||
|
code: '',
|
||||||
|
password: '',
|
||||||
|
confirmPassword: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
// 原密码表单数据
|
||||||
|
const pwdFormData = reactive({
|
||||||
|
oldPassword: '',
|
||||||
|
newPassword: '',
|
||||||
|
confirmPassword: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
// 验证码按钮状态
|
||||||
|
const codeButtonLoading = ref(false);
|
||||||
|
const countdown = ref(0);
|
||||||
|
const timer = ref<NodeJS.Timeout>();
|
||||||
|
|
||||||
|
// 邮箱验证表单规则
|
||||||
|
const emailRules = computed(() => {
|
||||||
|
const { formRules, createConfirmPwdRule } = useFormRules();
|
||||||
|
|
||||||
|
return {
|
||||||
|
email: formRules.email,
|
||||||
|
code: formRules.code,
|
||||||
|
password: formRules.pwd,
|
||||||
|
confirmPassword: createConfirmPwdRule(emailFormData.password)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 原密码表单规则
|
||||||
|
const pwdRules = computed(() => {
|
||||||
|
const { formRules, createConfirmPwdRule } = useFormRules();
|
||||||
|
|
||||||
|
return {
|
||||||
|
oldPassword: formRules.pwd,
|
||||||
|
newPassword: formRules.pwd,
|
||||||
|
confirmPassword: createConfirmPwdRule(pwdFormData.newPassword)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取验证码
|
||||||
|
const handleGetCode = async () => {
|
||||||
|
try {
|
||||||
|
if (!emailFormData.email) {
|
||||||
|
message.error(t('page.resetPwd.emailRequired'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
codeButtonLoading.value = true;
|
||||||
|
await getEmailCode(emailFormData.email);
|
||||||
|
message.success(t('page.resetPwd.codeSent'));
|
||||||
|
|
||||||
|
// 开始倒计时
|
||||||
|
countdown.value = 60;
|
||||||
|
timer.value = setInterval(() => {
|
||||||
|
if (countdown.value > 0) {
|
||||||
|
countdown.value--;
|
||||||
|
} else {
|
||||||
|
clearInterval(timer.value);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to get code:', error);
|
||||||
|
} finally {
|
||||||
|
codeButtonLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交表单
|
||||||
|
const emailFormRef = ref();
|
||||||
|
const pwdFormRef = ref();
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
try {
|
||||||
|
if (resetType.value === 'email') {
|
||||||
|
await emailFormRef.value?.validate();
|
||||||
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
|
await resetPassword({
|
||||||
|
email: emailFormData.email,
|
||||||
|
code: emailFormData.code,
|
||||||
|
password: emailFormData.password
|
||||||
|
});
|
||||||
|
hide();
|
||||||
|
} else {
|
||||||
|
await pwdFormRef.value?.validate();
|
||||||
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
|
await updatePasswordByOld({
|
||||||
|
oldPassword: pwdFormData.oldPassword,
|
||||||
|
newPassword: pwdFormData.newPassword
|
||||||
|
});
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
message.success(t('page.resetPwd.success'));
|
||||||
|
routerPushByKey('login');
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex-col-stretch items-center justify-center min-h-500px p-24px">
|
||||||
|
<div class="w-full max-w-400px">
|
||||||
|
<h2 class="text-24px font-bold mb-24px text-center">{{ t('page.resetPwd.title') }}</h2>
|
||||||
|
|
||||||
|
<!-- 修改方式选择 -->
|
||||||
|
<a-radio-group v-model:value="resetType" class="mb-16px">
|
||||||
|
<a-radio value="email">{{ t('page.resetPwd.byEmail') }}</a-radio>
|
||||||
|
<a-radio value="password">{{ t('page.resetPwd.byPassword') }}</a-radio>
|
||||||
|
</a-radio-group>
|
||||||
|
|
||||||
|
<!-- 邮箱验证表单 -->
|
||||||
|
<a-form
|
||||||
|
v-if="resetType === 'email'"
|
||||||
|
ref="emailFormRef"
|
||||||
|
:model="emailFormData"
|
||||||
|
:rules="emailRules"
|
||||||
|
layout="vertical"
|
||||||
|
>
|
||||||
|
<a-form-item name="email" :label="t('page.resetPwd.email')">
|
||||||
|
<div class="flex gap-8px">
|
||||||
|
<a-input
|
||||||
|
v-model:value="emailFormData.email"
|
||||||
|
:placeholder="t('page.resetPwd.emailPlaceholder')"
|
||||||
|
/>
|
||||||
|
<a-button
|
||||||
|
:loading="codeButtonLoading"
|
||||||
|
:disabled="countdown > 0"
|
||||||
|
@click="handleGetCode"
|
||||||
|
>
|
||||||
|
{{ countdown > 0 ? `${countdown}s` : t('page.resetPwd.getCode') }}
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item name="code" :label="t('page.resetPwd.code')">
|
||||||
|
<a-input
|
||||||
|
v-model:value="emailFormData.code"
|
||||||
|
:placeholder="t('page.resetPwd.codePlaceholder')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item name="password" :label="t('page.resetPwd.newPassword')">
|
||||||
|
<a-input-password
|
||||||
|
v-model:value="emailFormData.password"
|
||||||
|
:placeholder="t('page.resetPwd.passwordPlaceholder')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item name="confirmPassword" :label="t('page.resetPwd.confirmPassword')">
|
||||||
|
<a-input-password
|
||||||
|
v-model:value="emailFormData.confirmPassword"
|
||||||
|
:placeholder="t('page.resetPwd.confirmPasswordPlaceholder')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
|
||||||
|
<!-- 原密码表单 -->
|
||||||
|
<a-form
|
||||||
|
v-else
|
||||||
|
ref="pwdFormRef"
|
||||||
|
:model="pwdFormData"
|
||||||
|
:rules="pwdRules"
|
||||||
|
layout="vertical"
|
||||||
|
>
|
||||||
|
<a-form-item name="oldPassword" :label="t('page.resetPwd.oldPassword')">
|
||||||
|
<a-input-password
|
||||||
|
v-model:value="pwdFormData.oldPassword"
|
||||||
|
:placeholder="t('page.resetPwd.oldPasswordPlaceholder')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item name="newPassword" :label="t('page.resetPwd.newPassword')">
|
||||||
|
<a-input-password
|
||||||
|
v-model:value="pwdFormData.newPassword"
|
||||||
|
:placeholder="t('page.resetPwd.passwordPlaceholder')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item name="confirmPassword" :label="t('page.resetPwd.confirmPassword')">
|
||||||
|
<a-input-password
|
||||||
|
v-model:value="pwdFormData.confirmPassword"
|
||||||
|
:placeholder="t('page.resetPwd.confirmPasswordPlaceholder')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
|
||||||
|
<!-- 提交按钮 -->
|
||||||
|
<a-form-item>
|
||||||
|
<a-button type="primary" block @click="handleSubmit">
|
||||||
|
{{ t('common.submit') }}
|
||||||
|
</a-button>
|
||||||
|
</a-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.max-w-400px {
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user