Compare commits
No commits in common. "2b4b9a2e9c78d71b2b8d9a35ab9a0bed540b3b79" and "ac705ecfcb3e77974788c9b4a85beb7c42d37f02" have entirely different histories.
2b4b9a2e9c
...
ac705ecfcb
@ -327,7 +327,7 @@ async def _extract_calculation_params_b1(data: UserValuationCreate) -> Dict[str,
|
|||||||
|
|
||||||
# 流量因子B12相关参数
|
# 流量因子B12相关参数
|
||||||
# 近30天搜索指数S1 - 从社交媒体数据计算 TODO 需要使用第三方API
|
# 近30天搜索指数S1 - 从社交媒体数据计算 TODO 需要使用第三方API
|
||||||
baidu_index = 1
|
baidu_index = 0
|
||||||
|
|
||||||
# 获取微信指数并计算近30天平均值
|
# 获取微信指数并计算近30天平均值
|
||||||
try:
|
try:
|
||||||
@ -336,9 +336,9 @@ async def _extract_calculation_params_b1(data: UserValuationCreate) -> Dict[str,
|
|||||||
logger.info(f"资产 '{data.asset_name}' 的微信指数近30天平均值: {wechat_index}")
|
logger.info(f"资产 '{data.asset_name}' 的微信指数近30天平均值: {wechat_index}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取微信指数失败: {e}")
|
logger.error(f"获取微信指数失败: {e}")
|
||||||
wechat_index = 1
|
wechat_index = 0
|
||||||
|
|
||||||
weibo_index = 1
|
weibo_index = 0
|
||||||
search_index_s1 = calculate_search_index_s1(baidu_index, wechat_index, weibo_index) # 默认值,实际应从API获取
|
search_index_s1 = calculate_search_index_s1(baidu_index, wechat_index, weibo_index) # 默认值,实际应从API获取
|
||||||
|
|
||||||
# 行业均值S2 - 从数据库查询行业数据计算
|
# 行业均值S2 - 从数据库查询行业数据计算
|
||||||
@ -433,7 +433,6 @@ async def _extract_calculation_params_b2(data: UserValuationCreate) -> Dict[str,
|
|||||||
# 纹样基因值B22相关参数
|
# 纹样基因值B22相关参数
|
||||||
|
|
||||||
# 以下三项需由后续模型/服务计算;此处提供默认可计算占位
|
# 以下三项需由后续模型/服务计算;此处提供默认可计算占位
|
||||||
#
|
|
||||||
# 历史传承度HI(用户填写)
|
# 历史传承度HI(用户填写)
|
||||||
historical_inheritance = sum([safe_float(i) for i in data.historical_evidence])
|
historical_inheritance = sum([safe_float(i) for i in data.historical_evidence])
|
||||||
structure_complexity = 1.5 # 默认值 纹样基因熵值B22(系统计算)
|
structure_complexity = 1.5 # 默认值 纹样基因熵值B22(系统计算)
|
||||||
|
|||||||
@ -113,9 +113,12 @@ class MarketValueCCalculator:
|
|||||||
return:
|
return:
|
||||||
Dict: 包含所有中间计算结果和最终结果的字典
|
Dict: 包含所有中间计算结果和最终结果的字典
|
||||||
"""
|
"""
|
||||||
|
# 获取动态默认值
|
||||||
|
default_price = await self._get_dynamic_default_price(input_data)
|
||||||
|
|
||||||
# 计算市场竞价C1
|
# 计算市场竞价C1
|
||||||
market_bidding_c1 = self.market_bidding_calculator.calculate_market_bidding_c1(
|
market_bidding_c1 = self.market_bidding_calculator.calculate_market_bidding_c1(
|
||||||
transaction_data={'weighted_average_price': input_data.get('weighted_average_price', 0)},
|
transaction_data={'weighted_average_price': input_data.get('weighted_average_price', default_price)},
|
||||||
manual_bids=input_data.get('manual_bids', []),
|
manual_bids=input_data.get('manual_bids', []),
|
||||||
expert_valuations=input_data.get('expert_valuations', [])
|
expert_valuations=input_data.get('expert_valuations', [])
|
||||||
)
|
)
|
||||||
|
|||||||
@ -23,7 +23,7 @@ class HeatCoefficientC2Calculator:
|
|||||||
"""
|
"""
|
||||||
# 计算浏览热度分
|
# 计算浏览热度分
|
||||||
browse_heat_score = self.calculate_browse_heat_score(daily_browse_volume, collection_count)
|
browse_heat_score = self.calculate_browse_heat_score(daily_browse_volume, collection_count)
|
||||||
print("浏览热度分: ")
|
|
||||||
|
|
||||||
heat_coefficient = 1 + browse_heat_score
|
heat_coefficient = 1 + browse_heat_score
|
||||||
|
|
||||||
|
|||||||
@ -70,7 +70,7 @@ if __name__ == "__main__":
|
|||||||
manual_bids = [950.0, 1000.0, 1050.0, 1100.0] # 用户填写
|
manual_bids = [950.0, 1000.0, 1050.0, 1100.0] # 用户填写
|
||||||
|
|
||||||
# 优先级3:专家估值
|
# 优先级3:专家估值
|
||||||
expert_valuations = [0.0, 0.0, 0.0] # 系统配置
|
expert_valuations = [980.0, 1020.0, 990.0] # 系统配置
|
||||||
|
|
||||||
# 计算市场竞价C1
|
# 计算市场竞价C1
|
||||||
market_bidding_c1 = calculator.calculate_market_bidding_c1(
|
market_bidding_c1 = calculator.calculate_market_bidding_c1(
|
||||||
|
|||||||
@ -4,8 +4,6 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Optional, Dict, Any
|
from typing import Optional, Dict, Any
|
||||||
from app.models.industry import Industry
|
from app.models.industry import Industry
|
||||||
from app.models.index import Index
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -46,7 +44,6 @@ async def get_industry_data_by_name(industry_name: str) -> Optional[Dict[str, An
|
|||||||
|
|
||||||
|
|
||||||
async def calculate_industry_average_s2(industry_name: str) -> float:
|
async def calculate_industry_average_s2(industry_name: str) -> float:
|
||||||
# todo : 使用index 搜索的数据
|
|
||||||
"""
|
"""
|
||||||
计算行业均值S2
|
计算行业均值S2
|
||||||
|
|
||||||
@ -56,13 +53,21 @@ async def calculate_industry_average_s2(industry_name: str) -> float:
|
|||||||
Returns:
|
Returns:
|
||||||
行业均值S2,如果查询失败则返回0.0
|
行业均值S2,如果查询失败则返回0.0
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
index_data = await Index.filter(name=industry_name).first()
|
industry_data = await get_industry_data_by_name(industry_name)
|
||||||
if index_data:
|
if industry_data:
|
||||||
# S2 = ROE * 修正系数
|
# S2 = ROE * 修正系数
|
||||||
logger.info(f"行业 {industry_name} S2计算: S2={index_data.search_num}")
|
roe = industry_data.get('roe', 0.0)
|
||||||
return index_data.search_num
|
fix_num = industry_data.get('fix_num', 0.0)
|
||||||
|
s2_value = roe * fix_num
|
||||||
|
|
||||||
|
# 确保S2值为正数,避免对数计算错误
|
||||||
|
if s2_value <= 0:
|
||||||
|
logger.warning(f"行业 {industry_name} S2计算值为负数或零: ROE={roe}, 修正系数={fix_num}, S2={s2_value},使用默认值0.01")
|
||||||
|
s2_value = 0.01 # 使用小的正数避免对数计算错误
|
||||||
|
|
||||||
|
logger.info(f"行业 {industry_name} S2计算: ROE={roe}, 修正系数={fix_num}, S2={s2_value}")
|
||||||
|
return s2_value
|
||||||
else:
|
else:
|
||||||
logger.warning(f"未找到行业 {industry_name} 的数据,返回默认值0.01")
|
logger.warning(f"未找到行业 {industry_name} 的数据,返回默认值0.01")
|
||||||
return 0.01 # 返回小的正数而不是0.0
|
return 0.01 # 返回小的正数而不是0.0
|
||||||
|
|||||||
3
node_modules/.vite/deps_temp_e96670e1/package.json
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "module"
|
|
||||||
}
|
|
||||||
2
web/.env
@ -1,3 +1,3 @@
|
|||||||
VITE_TITLE = 'Vue FastAPI Admin'
|
VITE_TITLE = '成都文化产权交易所'
|
||||||
|
|
||||||
VITE_PORT = 3100
|
VITE_PORT = 3100
|
||||||
@ -5,4 +5,4 @@ VITE_PUBLIC_PATH = '/'
|
|||||||
VITE_USE_PROXY = true
|
VITE_USE_PROXY = true
|
||||||
|
|
||||||
# base api
|
# base api
|
||||||
VITE_BASE_API = '/api/v1'
|
VITE_BASE_API = 'https://value.cdcee.net/api/v1'
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
VITE_PUBLIC_PATH = '/'
|
VITE_PUBLIC_PATH = '/'
|
||||||
|
|
||||||
# base api
|
# base api
|
||||||
VITE_BASE_API = '/api/v1'
|
VITE_BASE_API = 'https://value.cdcee.net/api/v1'
|
||||||
|
|
||||||
# 是否启用压缩
|
# 是否启用压缩
|
||||||
VITE_USE_COMPRESS = true
|
VITE_USE_COMPRESS = true
|
||||||
|
|||||||
@ -17,7 +17,7 @@ export const PROXY_CONFIG = {
|
|||||||
* @转发路径 http://localhost:9999/api/v1/user
|
* @转发路径 http://localhost:9999/api/v1/user
|
||||||
*/
|
*/
|
||||||
'/api/v1': {
|
'/api/v1': {
|
||||||
target: 'http://127.0.0.1:9999',
|
target: 'http://124.222.245.240:8080',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import vue from '@vitejs/plugin-vue'
|
|||||||
import Unocss from 'unocss/vite'
|
import Unocss from 'unocss/vite'
|
||||||
|
|
||||||
// rollup打包分析插件
|
// rollup打包分析插件
|
||||||
import visualizer from 'rollup-plugin-visualizer'
|
import { visualizer } from 'rollup-plugin-visualizer'
|
||||||
// 压缩
|
// 压缩
|
||||||
import viteCompression from 'vite-plugin-compression'
|
import viteCompression from 'vite-plugin-compression'
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@
|
|||||||
<div class="right-0 bottom-0 loading-spin-item loading-delay-1500"></div>
|
<div class="right-0 bottom-0 loading-spin-item loading-delay-1500"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="loading-title"><%= title %></div>
|
<!-- <div class="loading-title"><%= title %></div> -->
|
||||||
</div>
|
</div>
|
||||||
<script src="/resource/loading.js"></script>
|
<script src="/resource/loading.js"></script>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
"name": "vue-fastapi-admin-web",
|
"name": "vue-fastapi-admin-web",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
@ -15,11 +16,13 @@
|
|||||||
"@iconify/json": "^2.2.228",
|
"@iconify/json": "^2.2.228",
|
||||||
"@iconify/vue": "^4.1.1",
|
"@iconify/vue": "^4.1.1",
|
||||||
"@unocss/eslint-config": "^0.55.0",
|
"@unocss/eslint-config": "^0.55.0",
|
||||||
|
"@vicons/ionicons5": "^0.13.0",
|
||||||
"@vueuse/core": "^10.3.0",
|
"@vueuse/core": "^10.3.0",
|
||||||
"@zclzone/eslint-config": "^0.0.4",
|
"@zclzone/eslint-config": "^0.0.4",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"dayjs": "^1.11.9",
|
"dayjs": "^1.11.9",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
|
"echarts": "^5.4.3",
|
||||||
"eslint": "^8.46.0",
|
"eslint": "^8.46.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"naive-ui": "^2.34.4",
|
"naive-ui": "^2.34.4",
|
||||||
|
|||||||
8
web/pnpm-lock.yaml
generated
@ -17,6 +17,9 @@ importers:
|
|||||||
'@unocss/eslint-config':
|
'@unocss/eslint-config':
|
||||||
specifier: ^0.55.0
|
specifier: ^0.55.0
|
||||||
version: 0.55.7(eslint@8.57.0)(typescript@5.5.4)
|
version: 0.55.7(eslint@8.57.0)(typescript@5.5.4)
|
||||||
|
'@vicons/ionicons5':
|
||||||
|
specifier: ^0.13.0
|
||||||
|
version: 0.13.0
|
||||||
'@vueuse/core':
|
'@vueuse/core':
|
||||||
specifier: ^10.3.0
|
specifier: ^10.3.0
|
||||||
version: 10.11.0(vue@3.4.34(typescript@5.5.4))
|
version: 10.11.0(vue@3.4.34(typescript@5.5.4))
|
||||||
@ -533,6 +536,9 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0
|
vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0
|
||||||
|
|
||||||
|
'@vicons/ionicons5@0.13.0':
|
||||||
|
resolution: {integrity: sha512-zvZKBPjEXKN7AXNo2Na2uy+nvuv6SP4KAMQxpKL2vfHMj0fSvuw7JZcOPCjQC3e7ayssKnaoFVAhbYcW6v41qQ==}
|
||||||
|
|
||||||
'@vitejs/plugin-vue@4.6.2':
|
'@vitejs/plugin-vue@4.6.2':
|
||||||
resolution: {integrity: sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==}
|
resolution: {integrity: sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==}
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
@ -2987,6 +2993,8 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- rollup
|
- rollup
|
||||||
|
|
||||||
|
'@vicons/ionicons5@0.13.0': {}
|
||||||
|
|
||||||
'@vitejs/plugin-vue@4.6.2(vite@4.5.3(@types/node@22.0.0)(sass@1.77.8)(terser@5.31.3))(vue@3.4.34(typescript@5.5.4))':
|
'@vitejs/plugin-vue@4.6.2(vite@4.5.3(@types/node@22.0.0)(sass@1.77.8)(terser@5.31.3))(vue@3.4.34(typescript@5.5.4))':
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 4.5.3(@types/node@22.0.0)(sass@1.77.8)(terser@5.31.3)
|
vite: 4.5.3(@types/node@22.0.0)(sass@1.77.8)(terser@5.31.3)
|
||||||
|
|||||||
@ -5,6 +5,14 @@ export default {
|
|||||||
getUserInfo: () => request.get('/base/userinfo'),
|
getUserInfo: () => request.get('/base/userinfo'),
|
||||||
getUserMenu: () => request.get('/base/usermenu'),
|
getUserMenu: () => request.get('/base/usermenu'),
|
||||||
getUserApi: () => request.get('/base/userapi'),
|
getUserApi: () => request.get('/base/userapi'),
|
||||||
|
// 手机号
|
||||||
|
registerPhone: (data) => request.post('/app-user/register', data, { noNeedToken: true }),
|
||||||
|
loginPhone: (data) => request.post('/app-user/login', data, { noNeedToken: true }),
|
||||||
|
// pages
|
||||||
|
getIndustryList: () => request.get('/industry/list'),
|
||||||
|
getHistoryList: (params) => request.get('/app-valuations/', { params }),
|
||||||
|
valuations: (data = {}) => request.post('/app-valuations/', data),
|
||||||
|
deleteValuations: (params = {}) => request.delete(`/app-valuations/${params.id}`),
|
||||||
// profile
|
// profile
|
||||||
updatePassword: (data = {}) => request.post('/base/update_password', data),
|
updatePassword: (data = {}) => request.post('/base/update_password', data),
|
||||||
// users
|
// users
|
||||||
@ -39,4 +47,28 @@ export default {
|
|||||||
deleteDept: (params = {}) => request.delete('/dept/delete', { params }),
|
deleteDept: (params = {}) => request.delete('/dept/delete', { params }),
|
||||||
// auditlog
|
// auditlog
|
||||||
getAuditLogList: (params = {}) => request.get('/auditlog/list', { params }),
|
getAuditLogList: (params = {}) => request.get('/auditlog/list', { params }),
|
||||||
|
// esg
|
||||||
|
getESGList: (params = {}) => request.get('/esg/list', { params }),
|
||||||
|
getESGById: (params = {}) => request.get('/esg/get', { params }),
|
||||||
|
createESG: (data = {}) => request.post('/esg/create', data),
|
||||||
|
updateESG: (data = {}) => request.post('/esg/update', data),
|
||||||
|
deleteESG: (params = {}) => request.delete('/esg/delete', { params }),
|
||||||
|
// index
|
||||||
|
getIndexList: (params = {}) => request.get('/index/list', { params }),
|
||||||
|
getIndexById: (params = {}) => request.get('/index/get', { params }),
|
||||||
|
createIndex: (data = {}) => request.post('/index/create', data),
|
||||||
|
updateIndex: (data = {}) => request.post('/index/update', data),
|
||||||
|
deleteIndex: (params = {}) => request.delete('/index/delete', { params }),
|
||||||
|
// industry
|
||||||
|
getIndustryList: (params = {}) => request.get('/industry/list', { params }),
|
||||||
|
getIndustryById: (params = {}) => request.get('/industry/get', { params }),
|
||||||
|
createIndustry: (data = {}) => request.post('/industry/create', data),
|
||||||
|
updateIndustry: (data = {}) => request.post('/industry/update', data),
|
||||||
|
deleteIndustry: (params = {}) => request.delete('/industry/delete', { params }),
|
||||||
|
// policy
|
||||||
|
getPolicyList: (params = {}) => request.get('/policy/list', { params }),
|
||||||
|
getPolicyById: (params = {}) => request.get('/policy/get', { params }),
|
||||||
|
createPolicy: (data = {}) => request.post('/policy/create', data),
|
||||||
|
updatePolicy: (data = {}) => request.post('/policy/update', data),
|
||||||
|
deletePolicy: (params = {}) => request.delete('/policy/delete', { params }),
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 642 B After Width: | Height: | Size: 642 B |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 472 B After Width: | Height: | Size: 472 B |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 662 B After Width: | Height: | Size: 662 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@ -6,7 +6,7 @@ const Layout = () => import('@/layout/index.vue')
|
|||||||
export const basicRoutes = [
|
export const basicRoutes = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
redirect: '/workbench', // 默认跳转到首页
|
redirect: '/pages', // 默认跳转到首页
|
||||||
meta: { order: 0 },
|
meta: { order: 0 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -95,6 +95,12 @@ export const basicRoutes = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'pages',
|
||||||
|
path: '/pages',
|
||||||
|
component: () => import('@/views/pages/index.vue'),
|
||||||
|
isHidden: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: '403',
|
name: '403',
|
||||||
path: '/403',
|
path: '/403',
|
||||||
|
|||||||
@ -77,13 +77,13 @@ export const usePermissionStore = defineStore('permission', {
|
|||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async generateRoutes() {
|
async generateRoutes() {
|
||||||
const res = await api.getUserMenu() // 调用接口获取后端传来的菜单路由
|
// const res = await api.getUserMenu() // 调用接口获取后端传来的菜单路由
|
||||||
this.accessRoutes = buildRoutes(res.data) // 处理成前端路由格式
|
// this.accessRoutes = buildRoutes(res.data) // 处理成前端路由格式
|
||||||
return this.accessRoutes
|
return this.accessRoutes
|
||||||
},
|
},
|
||||||
async getAccessApis() {
|
async getAccessApis() {
|
||||||
const res = await api.getUserApi()
|
// const res = await api.getUserApi()
|
||||||
this.accessApis = res.data
|
// this.accessApis = res.data
|
||||||
return this.accessApis
|
return this.accessApis
|
||||||
},
|
},
|
||||||
resetPermission() {
|
resetPermission() {
|
||||||
|
|||||||
@ -36,14 +36,15 @@ export const useUserStore = defineStore('user', {
|
|||||||
actions: {
|
actions: {
|
||||||
async getUserInfo() {
|
async getUserInfo() {
|
||||||
try {
|
try {
|
||||||
const res = await api.getUserInfo()
|
// const res = await api.getUserInfo()
|
||||||
if (res.code === 401) {
|
// if (res.code === 401) {
|
||||||
this.logout()
|
// this.logout()
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
const { id, username, email, avatar, roles, is_superuser, is_active } = res.data
|
// const { id, username, email, avatar, roles, is_superuser, is_active } = res.data
|
||||||
this.userInfo = { id, username, email, avatar, roles, is_superuser, is_active }
|
// this.userInfo = { id, username, email, avatar, roles, is_superuser, is_active }
|
||||||
return res.data
|
// return res.data
|
||||||
|
return {}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return error
|
return error
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,4 +16,5 @@ export function createAxios(options = {}) {
|
|||||||
|
|
||||||
export const request = createAxios({
|
export const request = createAxios({
|
||||||
baseURL: import.meta.env.VITE_BASE_API,
|
baseURL: import.meta.env.VITE_BASE_API,
|
||||||
|
Authorization: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxOCwicGhvbmUiOiIxNTg1MDIwMTEzOSIsImV4cCI6MTc2MDYzNTc0NX0.Z-2oCgVYlLo4JVuFLwNWqhj2iYyAvkZxWQp0h6AlhuI'
|
||||||
})
|
})
|
||||||
|
|||||||
@ -26,7 +26,10 @@ export function resResolve(response) {
|
|||||||
const code = data?.code ?? status
|
const code = data?.code ?? status
|
||||||
/** 根据code处理对应的操作,并返回处理后的message */
|
/** 根据code处理对应的操作,并返回处理后的message */
|
||||||
const message = resolveResError(code, data?.msg ?? statusText)
|
const message = resolveResError(code, data?.msg ?? statusText)
|
||||||
|
console.log(message,'message')
|
||||||
|
if(message){
|
||||||
window.$message?.error(message, { keepAliveOnHover: true })
|
window.$message?.error(message, { keepAliveOnHover: true })
|
||||||
|
}
|
||||||
return Promise.reject({ code, message, error: data || response })
|
return Promise.reject({ code, message, error: data || response })
|
||||||
}
|
}
|
||||||
return Promise.resolve(data)
|
return Promise.resolve(data)
|
||||||
@ -37,7 +40,10 @@ export async function resReject(error) {
|
|||||||
const code = error?.code
|
const code = error?.code
|
||||||
/** 根据code处理对应的操作,并返回处理后的message */
|
/** 根据code处理对应的操作,并返回处理后的message */
|
||||||
const message = resolveResError(code, error.message)
|
const message = resolveResError(code, error.message)
|
||||||
|
console.log(message,'message')
|
||||||
|
if(message){
|
||||||
window.$message?.error(message)
|
window.$message?.error(message)
|
||||||
|
}
|
||||||
return Promise.reject({ code, message, error })
|
return Promise.reject({ code, message, error })
|
||||||
}
|
}
|
||||||
const { data, status } = error.response
|
const { data, status } = error.response
|
||||||
@ -54,6 +60,9 @@ export async function resReject(error) {
|
|||||||
// 后端返回的response数据
|
// 后端返回的response数据
|
||||||
const code = data?.code ?? status
|
const code = data?.code ?? status
|
||||||
const message = resolveResError(code, data?.msg ?? error.message)
|
const message = resolveResError(code, data?.msg ?? error.message)
|
||||||
|
console.log(message,'message')
|
||||||
|
if(message){
|
||||||
window.$message?.error(message, { keepAliveOnHover: true })
|
window.$message?.error(message, { keepAliveOnHover: true })
|
||||||
|
}
|
||||||
return Promise.reject({ code, message, error: error.response?.data || error.response })
|
return Promise.reject({ code, message, error: error.response?.data || error.response })
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,49 +2,40 @@
|
|||||||
<AppPage :show-footer="true" bg-cover :style="{ backgroundImage: `url(${bgImg})` }">
|
<AppPage :show-footer="true" bg-cover :style="{ backgroundImage: `url(${bgImg})` }">
|
||||||
<div
|
<div
|
||||||
style="transform: translateY(25px)"
|
style="transform: translateY(25px)"
|
||||||
class="m-auto max-w-1500 min-w-345 f-c-c rounded-10 bg-white bg-opacity-60 p-15 card-shadow"
|
class="m-auto max-w-1500 min-w-750 f-c-c rounded-12 bg-white bg-opacity-80"
|
||||||
dark:bg-dark
|
dark:bg-dark
|
||||||
>
|
>
|
||||||
<div hidden w-380 px-20 py-35 md:block>
|
<div w-750 px-20 style="height: 400px; padding-top: 50px; text-align: center;">
|
||||||
<icon-custom-front-page pt-10 text-300 color-primary></icon-custom-front-page>
|
<img style="width: 371px; height: 60px; margin: auto;" src="@/assets/images/logo.png" alt="">
|
||||||
|
<div mt-50 style="text-align: center; font-size: 48px; color: #303133; line-height: 48px; font-weight: 600; ">
|
||||||
|
非遗IP价值评估系统
|
||||||
</div>
|
</div>
|
||||||
|
<div style="text-align: center; margin-top: 16px; color: #606266;">
|
||||||
<div w-320 flex-col px-20 py-35>
|
基于深度学习算法的智能评估系统,为您的知识产权和非物质文化遗产提供专业的价值评估服务
|
||||||
<h5 f-c-c text-24 font-normal color="#6a6a6a">
|
|
||||||
<icon-custom-logo mr-10 text-50 color-primary />{{ $t('app_name') }}
|
|
||||||
</h5>
|
|
||||||
<div mt-30>
|
|
||||||
<n-input
|
|
||||||
v-model:value="loginInfo.username"
|
|
||||||
autofocus
|
|
||||||
class="h-50 items-center pl-10 text-16"
|
|
||||||
placeholder="admin"
|
|
||||||
:maxlength="20"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div mt-30>
|
<div mt-30>
|
||||||
<n-input
|
<n-input
|
||||||
v-model:value="loginInfo.password"
|
v-model:value="loginInfo.phone"
|
||||||
class="h-50 items-center pl-10 text-16"
|
style="display: inline-block; width: 260px; height: 42px; text-align: left; line-height: 42px;"
|
||||||
type="password"
|
placeholder="请输入手机号"
|
||||||
show-password-on="mousedown"
|
|
||||||
placeholder="123456"
|
|
||||||
:maxlength="20"
|
:maxlength="20"
|
||||||
@keypress.enter="handleLogin"
|
@keypress.enter="handleRegister"
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div mt-20>
|
|
||||||
<n-button
|
|
||||||
h-50
|
|
||||||
w-full
|
|
||||||
rounded-5
|
|
||||||
text-16
|
|
||||||
type="primary"
|
|
||||||
:loading="loading"
|
|
||||||
@click="handleLogin"
|
|
||||||
>
|
>
|
||||||
{{ $t('views.login.text_login') }}
|
<template #prefix>
|
||||||
|
<img style="width: 18px; height: 18px; margin-right: 8px;" src="@/assets/images/phone.png" alt="">
|
||||||
|
</template>
|
||||||
|
</n-input>
|
||||||
|
|
||||||
|
<n-button
|
||||||
|
w-126
|
||||||
|
h-42
|
||||||
|
rounded-5
|
||||||
|
type="primary"
|
||||||
|
style="background: linear-gradient( 93deg, #880C22 0%, #A30113 100%); margin-left: 20px; font-size: 16px; border: none !important;"
|
||||||
|
@click="handleRegister"
|
||||||
|
>
|
||||||
|
立即登录
|
||||||
|
<img style="width: 18px; height: 18px; margin-left: 2px;" src="@/assets/images/go.png" alt="">
|
||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -54,7 +45,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { lStorage, setToken } from '@/utils'
|
import { lStorage, setToken } from '@/utils'
|
||||||
import bgImg from '@/assets/images/login_bg.webp'
|
import bgImg from '@/assets/images/login_bg.png'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { addDynamicRoutes } from '@/router'
|
import { addDynamicRoutes } from '@/router'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
@ -64,45 +55,55 @@ const { query } = useRoute()
|
|||||||
const { t } = useI18n({ useScope: 'global' })
|
const { t } = useI18n({ useScope: 'global' })
|
||||||
|
|
||||||
const loginInfo = ref({
|
const loginInfo = ref({
|
||||||
username: '',
|
phone: '',
|
||||||
password: '',
|
|
||||||
})
|
})
|
||||||
|
|
||||||
initLoginInfo()
|
initLoginInfo()
|
||||||
|
|
||||||
function initLoginInfo() {
|
function initLoginInfo() {
|
||||||
const localLoginInfo = lStorage.get('loginInfo')
|
if(localStorage.getItem('phone')){
|
||||||
if (localLoginInfo) {
|
loginInfo.value.phone = localStorage.getItem('phone')
|
||||||
loginInfo.value.username = localLoginInfo.username || ''
|
|
||||||
loginInfo.value.password = localLoginInfo.password || ''
|
|
||||||
}
|
}
|
||||||
|
// const localLoginInfo = lStorage.get('loginInfo')
|
||||||
|
// if (localLoginInfo) {
|
||||||
|
// loginInfo.value.phone = localLoginInfo.phone || ''
|
||||||
|
// loginInfo.value.password = localLoginInfo.password || ''
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
async function handleLogin() {
|
|
||||||
const { username, password } = loginInfo.value
|
async function handleRegister() {
|
||||||
if (!username || !password) {
|
const { phone } = loginInfo.value
|
||||||
$message.warning(t('views.login.message_input_username_password'))
|
if (!phone) {
|
||||||
|
$message.warning('请输入手机号')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
loading.value = true
|
loading.value = true
|
||||||
$message.loading(t('views.login.message_verifying'))
|
await api.registerPhone({ phone })
|
||||||
const res = await api.login({ username, password: password.toString() })
|
.then(res=>{
|
||||||
$message.success(t('views.login.message_login_success'))
|
handleLogin()
|
||||||
setToken(res.data.access_token)
|
})
|
||||||
await addDynamicRoutes()
|
.catch(res=>{
|
||||||
|
handleLogin()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleLogin() {
|
||||||
|
const { phone } = loginInfo.value
|
||||||
|
loading.value = true
|
||||||
|
await api.loginPhone({ phone, password: phone.slice(5,11) }).catch(res=>{
|
||||||
|
setToken(res.error.access_token)
|
||||||
if (query.redirect) {
|
if (query.redirect) {
|
||||||
const path = query.redirect
|
const path = query.redirect
|
||||||
console.log('path', { path, query })
|
localStorage.setItem('phone', phone)
|
||||||
Reflect.deleteProperty(query, 'redirect')
|
Reflect.deleteProperty(query, 'redirect')
|
||||||
router.push({ path, query })
|
router.push({ path, query })
|
||||||
} else {
|
} else {
|
||||||
router.push('/')
|
router.push('/')
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
console.error('login error', e.error)
|
|
||||||
}
|
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
:key="i"
|
:key="i"
|
||||||
class="mb-10 mt-10 w-300 cursor-pointer"
|
class="mb-10 mt-10 w-300 cursor-pointer"
|
||||||
hover:card-shadow
|
hover:card-shadow
|
||||||
title="Vue FastAPI Admin"
|
title=""
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
<p op-60>{{ dummyText }}</p>
|
<p op-60>{{ dummyText }}</p>
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
# 资源公共路径,需要以 /开头和结尾
|
|
||||||
VITE_PUBLIC_PATH = '/'
|
|
||||||
|
|
||||||
# 是否启用代理
|
|
||||||
VITE_USE_PROXY = true
|
|
||||||
|
|
||||||
# base api
|
|
||||||
VITE_BASE_API = 'https://value.cdcee.net/api/v1'
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
# 资源公共路径,需要以 /开头和结尾
|
|
||||||
VITE_PUBLIC_PATH = '/'
|
|
||||||
|
|
||||||
# base api
|
|
||||||
VITE_BASE_API = 'https://value.cdcee.net/api/v1'
|
|
||||||
|
|
||||||
# 是否启用压缩
|
|
||||||
VITE_USE_COMPRESS = true
|
|
||||||
|
|
||||||
# 压缩类型
|
|
||||||
VITE_COMPRESS_TYPE = gzip
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
{
|
|
||||||
"globals": {
|
|
||||||
"$loadingBar": true,
|
|
||||||
"$message": true,
|
|
||||||
"defineOptions": true,
|
|
||||||
"$dialog": true,
|
|
||||||
"$notification": true,
|
|
||||||
"EffectScope": true,
|
|
||||||
"computed": true,
|
|
||||||
"createApp": true,
|
|
||||||
"customRef": true,
|
|
||||||
"defineAsyncComponent": true,
|
|
||||||
"defineComponent": true,
|
|
||||||
"effectScope": true,
|
|
||||||
"getCurrentInstance": true,
|
|
||||||
"getCurrentScope": true,
|
|
||||||
"h": true,
|
|
||||||
"inject": true,
|
|
||||||
"isProxy": true,
|
|
||||||
"isReactive": true,
|
|
||||||
"isReadonly": true,
|
|
||||||
"isRef": true,
|
|
||||||
"markRaw": true,
|
|
||||||
"nextTick": true,
|
|
||||||
"onActivated": true,
|
|
||||||
"onBeforeMount": true,
|
|
||||||
"onBeforeUnmount": true,
|
|
||||||
"onBeforeUpdate": true,
|
|
||||||
"onDeactivated": true,
|
|
||||||
"onErrorCaptured": true,
|
|
||||||
"onMounted": true,
|
|
||||||
"onRenderTracked": true,
|
|
||||||
"onRenderTriggered": true,
|
|
||||||
"onScopeDispose": true,
|
|
||||||
"onServerPrefetch": true,
|
|
||||||
"onUnmounted": true,
|
|
||||||
"onUpdated": true,
|
|
||||||
"provide": true,
|
|
||||||
"reactive": true,
|
|
||||||
"readonly": true,
|
|
||||||
"ref": true,
|
|
||||||
"resolveComponent": true,
|
|
||||||
"shallowReactive": true,
|
|
||||||
"shallowReadonly": true,
|
|
||||||
"shallowRef": true,
|
|
||||||
"toRaw": true,
|
|
||||||
"toRef": true,
|
|
||||||
"toRefs": true,
|
|
||||||
"triggerRef": true,
|
|
||||||
"unref": true,
|
|
||||||
"useAttrs": true,
|
|
||||||
"useCssModule": true,
|
|
||||||
"useCssVars": true,
|
|
||||||
"useRoute": true,
|
|
||||||
"useRouter": true,
|
|
||||||
"useSlots": true,
|
|
||||||
"watch": true,
|
|
||||||
"watchEffect": true,
|
|
||||||
"watchPostEffect": true,
|
|
||||||
"watchSyncEffect": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
node_modules
|
|
||||||
dist
|
|
||||||
public
|
|
||||||
package.json
|
|
||||||
26
web1/.gitignore
vendored
@ -1,26 +0,0 @@
|
|||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
pnpm-debug.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
|
|
||||||
node_modules
|
|
||||||
.DS_Store
|
|
||||||
dist
|
|
||||||
dist-ssr
|
|
||||||
coverage
|
|
||||||
*.local
|
|
||||||
stats.html
|
|
||||||
|
|
||||||
# Editor directories and files
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/extensions.json
|
|
||||||
.idea
|
|
||||||
*.suo
|
|
||||||
*.ntvs*
|
|
||||||
*.njsproj
|
|
||||||
*.sln
|
|
||||||
*.sw?
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
/node_modules/**
|
|
||||||
/dist/*
|
|
||||||
/public/*
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"printWidth": 100,
|
|
||||||
"singleQuote": true,
|
|
||||||
"semi": false,
|
|
||||||
"endOfLine": "lf"
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
## 快速开始
|
|
||||||
|
|
||||||
进入前端目录
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cd web
|
|
||||||
```
|
|
||||||
|
|
||||||
安装依赖(建议使用pnpm: https://pnpm.io/zh/installation)
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm i -g pnpm # 已安装可忽略
|
|
||||||
pnpm i # 或者 npm i
|
|
||||||
```
|
|
||||||
|
|
||||||
启动
|
|
||||||
|
|
||||||
```sh
|
|
||||||
pnpm dev
|
|
||||||
```
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
import dayjs from 'dayjs'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 此处定义的是全局常量,启动或打包后将添加到window中
|
|
||||||
* https://vitejs.cn/config/#define
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 项目构建时间
|
|
||||||
const _BUILD_TIME_ = JSON.stringify(dayjs().format('YYYY-MM-DD HH:mm:ss'))
|
|
||||||
|
|
||||||
export const viteDefine = {
|
|
||||||
_BUILD_TIME_,
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export * from './define'
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
export const OUTPUT_DIR = 'dist'
|
|
||||||
|
|
||||||
export const PROXY_CONFIG = {
|
|
||||||
// /**
|
|
||||||
// * @desc 替换匹配值
|
|
||||||
// * @请求路径 http://localhost:3100/api/user
|
|
||||||
// * @转发路径 http://localhost:9999/api/v1 +/user
|
|
||||||
// */
|
|
||||||
// '/api': {
|
|
||||||
// target: 'http://localhost:9999/api/v1',
|
|
||||||
// changeOrigin: true,
|
|
||||||
// rewrite: (path) => path.replace(new RegExp('^/api'), ''),
|
|
||||||
// },
|
|
||||||
/**
|
|
||||||
* @desc 不替换匹配值
|
|
||||||
* @请求路径 http://localhost:3100/api/v1/user
|
|
||||||
* @转发路径 http://localhost:9999/api/v1/user
|
|
||||||
*/
|
|
||||||
'/api/v1': {
|
|
||||||
target: 'http://124.222.245.240:8080',
|
|
||||||
changeOrigin: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
import { createHtmlPlugin } from 'vite-plugin-html'
|
|
||||||
|
|
||||||
export function configHtmlPlugin(viteEnv, isBuild) {
|
|
||||||
const { VITE_TITLE } = viteEnv
|
|
||||||
|
|
||||||
const htmlPlugin = createHtmlPlugin({
|
|
||||||
minify: isBuild,
|
|
||||||
inject: {
|
|
||||||
data: {
|
|
||||||
title: VITE_TITLE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return htmlPlugin
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
import vue from '@vitejs/plugin-vue'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * unocss插件,原子css
|
|
||||||
* https://github.com/antfu/unocss
|
|
||||||
*/
|
|
||||||
import Unocss from 'unocss/vite'
|
|
||||||
|
|
||||||
// rollup打包分析插件
|
|
||||||
import { visualizer } from 'rollup-plugin-visualizer'
|
|
||||||
// 压缩
|
|
||||||
import viteCompression from 'vite-plugin-compression'
|
|
||||||
|
|
||||||
import { configHtmlPlugin } from './html'
|
|
||||||
import unplugin from './unplugin'
|
|
||||||
|
|
||||||
export function createVitePlugins(viteEnv, isBuild) {
|
|
||||||
const plugins = [vue(), ...unplugin, configHtmlPlugin(viteEnv, isBuild), Unocss()]
|
|
||||||
|
|
||||||
if (viteEnv.VITE_USE_COMPRESS) {
|
|
||||||
plugins.push(viteCompression({ algorithm: viteEnv.VITE_COMPRESS_TYPE || 'gzip' }))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBuild) {
|
|
||||||
plugins.push(
|
|
||||||
visualizer({
|
|
||||||
open: true,
|
|
||||||
gzipSize: true,
|
|
||||||
brotliSize: true,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return plugins
|
|
||||||
}
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
import { resolve } from 'path'
|
|
||||||
import AutoImport from 'unplugin-auto-import/vite'
|
|
||||||
import Components from 'unplugin-vue-components/vite'
|
|
||||||
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
|
|
||||||
import { FileSystemIconLoader } from 'unplugin-icons/loaders'
|
|
||||||
import IconsResolver from 'unplugin-icons/resolver'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * unplugin-icons插件,自动引入iconify图标
|
|
||||||
* usage: https://github.com/antfu/unplugin-icons
|
|
||||||
* 图标库: https://icones.js.org/
|
|
||||||
*/
|
|
||||||
import Icons from 'unplugin-icons/vite'
|
|
||||||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
|
||||||
|
|
||||||
import { getSrcPath } from '../utils'
|
|
||||||
|
|
||||||
const customIconPath = resolve(getSrcPath(), 'assets/svg')
|
|
||||||
|
|
||||||
export default [
|
|
||||||
AutoImport({
|
|
||||||
imports: ['vue', 'vue-router'],
|
|
||||||
dts: false,
|
|
||||||
}),
|
|
||||||
Icons({
|
|
||||||
compiler: 'vue3',
|
|
||||||
customCollections: {
|
|
||||||
custom: FileSystemIconLoader(customIconPath),
|
|
||||||
},
|
|
||||||
scale: 1,
|
|
||||||
defaultClass: 'inline-block',
|
|
||||||
}),
|
|
||||||
Components({
|
|
||||||
resolvers: [
|
|
||||||
NaiveUiResolver(),
|
|
||||||
IconsResolver({ customCollections: ['custom'], componentPrefix: 'icon' }),
|
|
||||||
],
|
|
||||||
dts: false,
|
|
||||||
}),
|
|
||||||
createSvgIconsPlugin({
|
|
||||||
iconDirs: [customIconPath],
|
|
||||||
symbolId: 'icon-custom-[dir]-[name]',
|
|
||||||
inject: 'body-last',
|
|
||||||
customDomId: '__CUSTOM_SVG_ICON__',
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
import { resolve } from 'path'
|
|
||||||
import chalk from 'chalk'
|
|
||||||
import { writeFileSync } from 'fs-extra'
|
|
||||||
import { OUTPUT_DIR } from '../constant'
|
|
||||||
import { getEnvConfig, getRootPath } from '../utils'
|
|
||||||
|
|
||||||
export function runBuildCNAME() {
|
|
||||||
const { VITE_CNAME } = getEnvConfig()
|
|
||||||
if (!VITE_CNAME) return
|
|
||||||
try {
|
|
||||||
writeFileSync(resolve(getRootPath(), `${OUTPUT_DIR}/CNAME`), VITE_CNAME)
|
|
||||||
} catch (error) {
|
|
||||||
console.log(chalk.red('CNAME file failed to package:\n' + error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
import chalk from 'chalk'
|
|
||||||
import { runBuildCNAME } from './build-cname'
|
|
||||||
|
|
||||||
export const runBuild = async () => {
|
|
||||||
try {
|
|
||||||
runBuildCNAME()
|
|
||||||
console.log(`✨ ${chalk.cyan('build successfully!')}`)
|
|
||||||
} catch (error) {
|
|
||||||
console.log(chalk.red('vite build error:\n' + error))
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runBuild()
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
import fs from 'fs'
|
|
||||||
import path from 'path'
|
|
||||||
import dotenv from 'dotenv'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 项目根路径
|
|
||||||
* @descrition 结尾不带/
|
|
||||||
*/
|
|
||||||
export function getRootPath() {
|
|
||||||
return path.resolve(process.cwd())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 项目src路径
|
|
||||||
* @param srcName src目录名称(默认: "src")
|
|
||||||
* @descrition 结尾不带斜杠
|
|
||||||
*/
|
|
||||||
export function getSrcPath(srcName = 'src') {
|
|
||||||
return path.resolve(getRootPath(), srcName)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function convertEnv(envOptions) {
|
|
||||||
const result = {}
|
|
||||||
if (!envOptions) return result
|
|
||||||
|
|
||||||
for (const envKey in envOptions) {
|
|
||||||
let envVal = envOptions[envKey]
|
|
||||||
if (['true', 'false'].includes(envVal)) envVal = envVal === 'true'
|
|
||||||
|
|
||||||
if (['VITE_PORT'].includes(envKey)) envVal = +envVal
|
|
||||||
|
|
||||||
result[envKey] = envVal
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前环境下生效的配置文件名
|
|
||||||
*/
|
|
||||||
function getConfFiles() {
|
|
||||||
const script = process.env.npm_lifecycle_script
|
|
||||||
const reg = new RegExp('--mode ([a-z_\\d]+)')
|
|
||||||
const result = reg.exec(script)
|
|
||||||
if (result) {
|
|
||||||
const mode = result[1]
|
|
||||||
return ['.env', '.env.local', `.env.${mode}`]
|
|
||||||
}
|
|
||||||
return ['.env', '.env.local', '.env.production']
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getEnvConfig(match = 'VITE_', confFiles = getConfFiles()) {
|
|
||||||
let envConfig = {}
|
|
||||||
confFiles.forEach((item) => {
|
|
||||||
try {
|
|
||||||
if (fs.existsSync(path.resolve(process.cwd(), item))) {
|
|
||||||
const env = dotenv.parse(fs.readFileSync(path.resolve(process.cwd(), item)))
|
|
||||||
envConfig = { ...envConfig, ...env }
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Error in parsing ${item}`, e)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const reg = new RegExp(`^(${match})`)
|
|
||||||
Object.keys(envConfig).forEach((key) => {
|
|
||||||
if (!reg.test(key)) {
|
|
||||||
Reflect.deleteProperty(envConfig, key)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return envConfig
|
|
||||||
}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
import { createI18n } from 'vue-i18n'
|
|
||||||
import { lStorage } from '@/utils'
|
|
||||||
|
|
||||||
import messages from './messages'
|
|
||||||
|
|
||||||
const currentLocale = lStorage.get('locale')
|
|
||||||
|
|
||||||
const i18n = createI18n({
|
|
||||||
legacy: false,
|
|
||||||
globalInjection: true,
|
|
||||||
locale: currentLocale || 'cn',
|
|
||||||
fallbackLocale: 'cn',
|
|
||||||
messages: messages,
|
|
||||||
})
|
|
||||||
|
|
||||||
export default i18n
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
{
|
|
||||||
"lang": "中文",
|
|
||||||
"app_name": "Vue FastAPI Admin",
|
|
||||||
"header": {
|
|
||||||
"label_profile": "个人信息",
|
|
||||||
"label_logout": "退出登录",
|
|
||||||
"label_logout_dialog_title": "提示",
|
|
||||||
"text_logout_confirm": "确认退出?",
|
|
||||||
"text_logout_success": "已退出登录"
|
|
||||||
},
|
|
||||||
"views": {
|
|
||||||
"login": {
|
|
||||||
"text_login": "登录",
|
|
||||||
"message_input_username_password": "请输入用户名和密码",
|
|
||||||
"message_verifying": "正在验证...",
|
|
||||||
"message_login_success": "登录成功"
|
|
||||||
},
|
|
||||||
"workbench": {
|
|
||||||
"label_workbench": "工作台",
|
|
||||||
"text_hello": "hello, {username}",
|
|
||||||
"text_welcome": "今天又是元气满满的一天!",
|
|
||||||
"label_number_of_items": "项目数",
|
|
||||||
"label_upcoming": "待办",
|
|
||||||
"label_information": "消息",
|
|
||||||
"label_project": "项目",
|
|
||||||
"label_more": "更多"
|
|
||||||
},
|
|
||||||
"profile": {
|
|
||||||
"label_profile": "个人中心",
|
|
||||||
"label_modify_information": "修改信息",
|
|
||||||
"label_change_password": "修改密码",
|
|
||||||
"label_avatar": "头像",
|
|
||||||
"label_username": "用户姓名",
|
|
||||||
"label_email": "邮箱",
|
|
||||||
"label_old_password": "旧密码",
|
|
||||||
"label_new_password": "新密码",
|
|
||||||
"label_confirm_password": "确认密码",
|
|
||||||
"placeholder_username": "请填写姓名",
|
|
||||||
"placeholder_email": "请填写邮箱",
|
|
||||||
"placeholder_old_password": "请输入旧密码",
|
|
||||||
"placeholder_new_password": "请输入新密码",
|
|
||||||
"placeholder_confirm_password": "请再次输入新密码",
|
|
||||||
"message_username_required": "请输入昵称",
|
|
||||||
"message_old_password_required": "请输入旧密码",
|
|
||||||
"message_new_password_required": "请输入新密码",
|
|
||||||
"message_password_confirmation_required": "请再次输入密码",
|
|
||||||
"message_password_confirmation_diff": "两次密码输入不一致"
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"label_error": "错误页",
|
|
||||||
"text_back_to_home": "返回首页"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"common": {
|
|
||||||
"text": {
|
|
||||||
"update_success": "修改成功"
|
|
||||||
},
|
|
||||||
"buttons": {
|
|
||||||
"update": "修改"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
{
|
|
||||||
"lang": "English",
|
|
||||||
"app_name": "Vue FastAPI Admin",
|
|
||||||
"header": {
|
|
||||||
"label_profile": "Profile",
|
|
||||||
"label_logout": "Logout",
|
|
||||||
"label_logout_dialog_title": "Hint",
|
|
||||||
"text_logout_confirm": "Logout confirm",
|
|
||||||
"text_logout_success": "Logout success"
|
|
||||||
},
|
|
||||||
"views": {
|
|
||||||
"login": {
|
|
||||||
"text_login": "Login",
|
|
||||||
"message_input_username_password": "Please enter username and password",
|
|
||||||
"message_verifying": "Verifying...",
|
|
||||||
"message_login_success": "Login successful"
|
|
||||||
},
|
|
||||||
"workbench": {
|
|
||||||
"label_workbench": "Workbench",
|
|
||||||
"text_hello": "hello, {username}",
|
|
||||||
"text_welcome": "Today is another day full of energy!",
|
|
||||||
"label_number_of_items": "Number of items",
|
|
||||||
"label_upcoming": "Upcoming",
|
|
||||||
"label_information": "Information",
|
|
||||||
"label_project": "Project",
|
|
||||||
"label_more": "More"
|
|
||||||
},
|
|
||||||
"profile": {
|
|
||||||
"label_profile": "Profile",
|
|
||||||
"label_modify_information": "Modify your information",
|
|
||||||
"label_change_password": "Change password",
|
|
||||||
"label_avatar": "Avatar",
|
|
||||||
"label_username": "Username",
|
|
||||||
"label_email": "Email",
|
|
||||||
"label_old_password": "Old password",
|
|
||||||
"label_new_password": "New password",
|
|
||||||
"label_confirm_password": "Password confirmation",
|
|
||||||
"placeholder_username": "Please fill in your name",
|
|
||||||
"placeholder_email": "Please fill in your email address",
|
|
||||||
"placeholder_old_password": "Please enter the old password",
|
|
||||||
"placeholder_new_password": "Please enter a new password",
|
|
||||||
"placeholder_confirm_password": "Please enter the confirm password",
|
|
||||||
"message_username_required": "Please enter username",
|
|
||||||
"message_old_password_required": "Please enter the old password",
|
|
||||||
"message_new_password_required": "Please enter a new password",
|
|
||||||
"message_password_confirmation_required": "Please enter confirm password",
|
|
||||||
"message_password_confirmation_diff": "Two password inputs are inconsistent"
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"label_error": "Error",
|
|
||||||
"text_back_to_home": "Back to home"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"common": {
|
|
||||||
"text": {
|
|
||||||
"update_success": "Update success"
|
|
||||||
},
|
|
||||||
"buttons": {
|
|
||||||
"update": "Update"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import * as en from './en.json'
|
|
||||||
import * as cn from './cn.json'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
en,
|
|
||||||
cn,
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="cn">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta http-equiv="Expires" content="0" />
|
|
||||||
<meta http-equiv="Pragma" content="no-cache" />
|
|
||||||
<meta http-equiv="Cache-control" content="no-cache" />
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<link rel="icon" href="/favicon.svg" />
|
|
||||||
<link rel="stylesheet" href="/resource/loading.css" />
|
|
||||||
|
|
||||||
<title><%= title %></title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="app">
|
|
||||||
<!-- 白屏时的loading效果 -->
|
|
||||||
<div class="loading-container">
|
|
||||||
<div id="loadingLogo" class="loading-svg"></div>
|
|
||||||
<div class="loading-spin__container">
|
|
||||||
<div class="loading-spin">
|
|
||||||
<div class="left-0 top-0 loading-spin-item"></div>
|
|
||||||
<div class="left-0 bottom-0 loading-spin-item loading-delay-500"></div>
|
|
||||||
<div class="right-0 top-0 loading-spin-item loading-delay-1000"></div>
|
|
||||||
<div class="right-0 bottom-0 loading-spin-item loading-delay-1500"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- <div class="loading-title"><%= title %></div> -->
|
|
||||||
</div>
|
|
||||||
<script src="/resource/loading.js"></script>
|
|
||||||
</div>
|
|
||||||
<script type="module" src="/src/main.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "ESNext",
|
|
||||||
"baseUrl": "./",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"paths": {
|
|
||||||
"~/*": ["./*"],
|
|
||||||
"@/*": ["src/*"]
|
|
||||||
},
|
|
||||||
"jsx": "preserve",
|
|
||||||
"allowJs": true
|
|
||||||
},
|
|
||||||
"exclude": ["node_modules", "dist"]
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "vue-fastapi-admin-web",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "vite",
|
|
||||||
"build": "vite build",
|
|
||||||
"preview": "vite preview",
|
|
||||||
"lint": "eslint --ext .js,.vue .",
|
|
||||||
"lint:fix": "eslint --fix --ext .js,.vue .",
|
|
||||||
"lint:staged": "lint-staged",
|
|
||||||
"prettier": "npx prettier --write ."
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@iconify/json": "^2.2.228",
|
|
||||||
"@iconify/vue": "^4.1.1",
|
|
||||||
"@unocss/eslint-config": "^0.55.0",
|
|
||||||
"@vicons/ionicons5": "^0.13.0",
|
|
||||||
"@vueuse/core": "^10.3.0",
|
|
||||||
"@zclzone/eslint-config": "^0.0.4",
|
|
||||||
"axios": "^1.4.0",
|
|
||||||
"dayjs": "^1.11.9",
|
|
||||||
"dotenv": "^16.3.1",
|
|
||||||
"echarts": "^5.4.3",
|
|
||||||
"eslint": "^8.46.0",
|
|
||||||
"lodash-es": "^4.17.21",
|
|
||||||
"naive-ui": "^2.34.4",
|
|
||||||
"pinia": "^2.1.6",
|
|
||||||
"rollup-plugin-visualizer": "^5.9.2",
|
|
||||||
"sass": "^1.65.1",
|
|
||||||
"typescript": "^5.1.6",
|
|
||||||
"unocss": "^0.55.0",
|
|
||||||
"unplugin-auto-import": "^0.16.6",
|
|
||||||
"unplugin-icons": "^0.16.5",
|
|
||||||
"unplugin-vue-components": "^0.25.1",
|
|
||||||
"vite-plugin-compression": "^0.5.1",
|
|
||||||
"vite-plugin-html": "^3.2.0",
|
|
||||||
"vite-plugin-svg-icons": "^2.0.1",
|
|
||||||
"vue": "^3.3.4",
|
|
||||||
"vue-i18n": "9",
|
|
||||||
"vue-router": "^4.2.4"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@vitejs/plugin-vue": "^4.2.3",
|
|
||||||
"vite": "^4.4.6"
|
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"*.{js,vue}": [
|
|
||||||
"eslint --ext .js,.vue ."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"eslintConfig": {
|
|
||||||
"extends": [
|
|
||||||
"@zclzone",
|
|
||||||
"@unocss",
|
|
||||||
".eslint-global-variables.json"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
5290
web1/pnpm-lock.yaml
generated
|
Before Width: | Height: | Size: 10 KiB |
@ -1,91 +0,0 @@
|
|||||||
.loading-container {
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-svg {
|
|
||||||
width: 128px;
|
|
||||||
height: 128px;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-spin__container {
|
|
||||||
width: 56px;
|
|
||||||
height: 56px;
|
|
||||||
margin: 36px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-spin {
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
animation: loadingSpin 1s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-0 {
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
.right-0 {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
.top-0 {
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
.bottom-0 {
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-spin-item {
|
|
||||||
position: absolute;
|
|
||||||
height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
background-color: var(--primary-color);
|
|
||||||
border-radius: 8px;
|
|
||||||
-webkit-animation: loadingPulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
||||||
animation: loadingPulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes loadingSpin {
|
|
||||||
from {
|
|
||||||
-webkit-transform: rotate(0deg);
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
-webkit-transform: rotate(360deg);
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes loadingPulse {
|
|
||||||
0%, 100% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
opacity: .5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-delay-500 {
|
|
||||||
-webkit-animation-delay: 500ms;
|
|
||||||
animation-delay: 500ms;
|
|
||||||
}
|
|
||||||
.loading-delay-1000 {
|
|
||||||
-webkit-animation-delay: 1000ms;
|
|
||||||
animation-delay: 1000ms;
|
|
||||||
}
|
|
||||||
.loading-delay-1500 {
|
|
||||||
-webkit-animation-delay: 1500ms;
|
|
||||||
animation-delay: 1500ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-title {
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #6a6a6a;
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export * from './theme.json'
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"header": {
|
|
||||||
"height": 60
|
|
||||||
},
|
|
||||||
"tags": {
|
|
||||||
"visible": true,
|
|
||||||
"height": 50
|
|
||||||
},
|
|
||||||
"naiveThemeOverrides": {
|
|
||||||
"common": {
|
|
||||||
"primaryColor": "#F4511E",
|
|
||||||
"primaryColorHover": "#F4511E",
|
|
||||||
"primaryColorPressed": "#2B4C59FF",
|
|
||||||
"primaryColorSuppl": "#F4511E",
|
|
||||||
|
|
||||||
"infoColor": "#2080F0FF",
|
|
||||||
"infoColorHover": "#4098FCFF",
|
|
||||||
"infoColorPressed": "#1060C9FF",
|
|
||||||
"infoColorSuppl": "#4098FCFF",
|
|
||||||
|
|
||||||
"successColor": "#18A058FF",
|
|
||||||
"successColorHover": "#F4511E",
|
|
||||||
"successColorPressed": "#0C7A43FF",
|
|
||||||
"successColorSuppl": "#F4511E",
|
|
||||||
|
|
||||||
"warningColor": "#F0A020FF",
|
|
||||||
"warningColorHover": "#FCB040FF",
|
|
||||||
"warningColorPressed": "#C97C10FF",
|
|
||||||
"warningColorSuppl": "#FCB040FF",
|
|
||||||
|
|
||||||
"errorColor": "#D03050FF",
|
|
||||||
"errorColorHover": "#DE576DFF",
|
|
||||||
"errorColorPressed": "#AB1F3FFF",
|
|
||||||
"errorColorSuppl": "#DE576DFF"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
<template>
|
|
||||||
<AppProvider>
|
|
||||||
<router-view v-slot="{ Component }">
|
|
||||||
<component :is="Component" />
|
|
||||||
</router-view>
|
|
||||||
</AppProvider>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import AppProvider from '@/components/common/AppProvider.vue'
|
|
||||||
</script>
|
|
||||||
@ -1,74 +0,0 @@
|
|||||||
import { request } from '@/utils'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
login: (data) => request.post('/base/access_token', data, { noNeedToken: true }),
|
|
||||||
getUserInfo: () => request.get('/base/userinfo'),
|
|
||||||
getUserMenu: () => request.get('/base/usermenu'),
|
|
||||||
getUserApi: () => request.get('/base/userapi'),
|
|
||||||
// 手机号
|
|
||||||
registerPhone: (data) => request.post('/app-user/register', data, { noNeedToken: true }),
|
|
||||||
loginPhone: (data) => request.post('/app-user/login', data, { noNeedToken: true }),
|
|
||||||
// pages
|
|
||||||
getIndustryList: () => request.get('/industry/list'),
|
|
||||||
getHistoryList: (params) => request.get('/app-valuations/', { params }),
|
|
||||||
valuations: (data = {}) => request.post('/app-valuations/', data),
|
|
||||||
deleteValuations: (params = {}) => request.delete(`/app-valuations/${params.id}`),
|
|
||||||
// profile
|
|
||||||
updatePassword: (data = {}) => request.post('/base/update_password', data),
|
|
||||||
// users
|
|
||||||
getUserList: (params = {}) => request.get('/user/list', { params }),
|
|
||||||
getUserById: (params = {}) => request.get('/user/get', { params }),
|
|
||||||
createUser: (data = {}) => request.post('/user/create', data),
|
|
||||||
updateUser: (data = {}) => request.post('/user/update', data),
|
|
||||||
deleteUser: (params = {}) => request.delete(`/user/delete`, { params }),
|
|
||||||
resetPassword: (data = {}) => request.post(`/user/reset_password`, data),
|
|
||||||
// role
|
|
||||||
getRoleList: (params = {}) => request.get('/role/list', { params }),
|
|
||||||
createRole: (data = {}) => request.post('/role/create', data),
|
|
||||||
updateRole: (data = {}) => request.post('/role/update', data),
|
|
||||||
deleteRole: (params = {}) => request.delete('/role/delete', { params }),
|
|
||||||
updateRoleAuthorized: (data = {}) => request.post('/role/authorized', data),
|
|
||||||
getRoleAuthorized: (params = {}) => request.get('/role/authorized', { params }),
|
|
||||||
// menus
|
|
||||||
getMenus: (params = {}) => request.get('/menu/list', { params }),
|
|
||||||
createMenu: (data = {}) => request.post('/menu/create', data),
|
|
||||||
updateMenu: (data = {}) => request.post('/menu/update', data),
|
|
||||||
deleteMenu: (params = {}) => request.delete('/menu/delete', { params }),
|
|
||||||
// apis
|
|
||||||
getApis: (params = {}) => request.get('/api/list', { params }),
|
|
||||||
createApi: (data = {}) => request.post('/api/create', data),
|
|
||||||
updateApi: (data = {}) => request.post('/api/update', data),
|
|
||||||
deleteApi: (params = {}) => request.delete('/api/delete', { params }),
|
|
||||||
refreshApi: (data = {}) => request.post('/api/refresh', data),
|
|
||||||
// depts
|
|
||||||
getDepts: (params = {}) => request.get('/dept/list', { params }),
|
|
||||||
createDept: (data = {}) => request.post('/dept/create', data),
|
|
||||||
updateDept: (data = {}) => request.post('/dept/update', data),
|
|
||||||
deleteDept: (params = {}) => request.delete('/dept/delete', { params }),
|
|
||||||
// auditlog
|
|
||||||
getAuditLogList: (params = {}) => request.get('/auditlog/list', { params }),
|
|
||||||
// esg
|
|
||||||
getESGList: (params = {}) => request.get('/esg/list', { params }),
|
|
||||||
getESGById: (params = {}) => request.get('/esg/get', { params }),
|
|
||||||
createESG: (data = {}) => request.post('/esg/create', data),
|
|
||||||
updateESG: (data = {}) => request.post('/esg/update', data),
|
|
||||||
deleteESG: (params = {}) => request.delete('/esg/delete', { params }),
|
|
||||||
// index
|
|
||||||
getIndexList: (params = {}) => request.get('/index/list', { params }),
|
|
||||||
getIndexById: (params = {}) => request.get('/index/get', { params }),
|
|
||||||
createIndex: (data = {}) => request.post('/index/create', data),
|
|
||||||
updateIndex: (data = {}) => request.post('/index/update', data),
|
|
||||||
deleteIndex: (params = {}) => request.delete('/index/delete', { params }),
|
|
||||||
// industry
|
|
||||||
getIndustryList: (params = {}) => request.get('/industry/list', { params }),
|
|
||||||
getIndustryById: (params = {}) => request.get('/industry/get', { params }),
|
|
||||||
createIndustry: (data = {}) => request.post('/industry/create', data),
|
|
||||||
updateIndustry: (data = {}) => request.post('/industry/update', data),
|
|
||||||
deleteIndustry: (params = {}) => request.delete('/industry/delete', { params }),
|
|
||||||
// policy
|
|
||||||
getPolicyList: (params = {}) => request.get('/policy/list', { params }),
|
|
||||||
getPolicyById: (params = {}) => request.get('/policy/get', { params }),
|
|
||||||
createPolicy: (data = {}) => request.post('/policy/create', data),
|
|
||||||
updatePolicy: (data = {}) => request.post('/policy/update', data),
|
|
||||||
deletePolicy: (params = {}) => request.delete('/policy/delete', { params }),
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 6.8 KiB |
@ -1,230 +0,0 @@
|
|||||||
export default [
|
|
||||||
'mdi-air-humidifier-off',
|
|
||||||
'mdi-chili-off',
|
|
||||||
'mdi-cigar-off',
|
|
||||||
'mdi-clock-time-eight',
|
|
||||||
'mdi-clock-time-eight-outline',
|
|
||||||
'mdi-clock-time-eleven',
|
|
||||||
'mdi-clock-time-eleven-outline',
|
|
||||||
'mdi-clock-time-five',
|
|
||||||
'mdi-clock-time-five-outline',
|
|
||||||
'mdi-clock-time-four',
|
|
||||||
'mdi-clock-time-four-outline',
|
|
||||||
'mdi-clock-time-nine',
|
|
||||||
'mdi-clock-time-nine-outline',
|
|
||||||
'mdi-clock-time-one',
|
|
||||||
'mdi-clock-time-one-outline',
|
|
||||||
'mdi-clock-time-seven',
|
|
||||||
'mdi-clock-time-seven-outline',
|
|
||||||
'mdi-clock-time-six',
|
|
||||||
'mdi-clock-time-six-outline',
|
|
||||||
'mdi-clock-time-ten',
|
|
||||||
'mdi-clock-time-ten-outline',
|
|
||||||
'mdi-clock-time-three',
|
|
||||||
'mdi-clock-time-three-outline',
|
|
||||||
'mdi-clock-time-twelve',
|
|
||||||
'mdi-clock-time-twelve-outline',
|
|
||||||
'mdi-clock-time-two',
|
|
||||||
'mdi-clock-time-two-outline',
|
|
||||||
'mdi-cog-refresh',
|
|
||||||
'mdi-cog-refresh-outline',
|
|
||||||
'mdi-cog-sync',
|
|
||||||
'mdi-cog-sync-outline',
|
|
||||||
'mdi-content-save-cog',
|
|
||||||
'mdi-content-save-cog-outline',
|
|
||||||
'mdi-cosine-wave',
|
|
||||||
'mdi-cube-off',
|
|
||||||
'mdi-cube-off-outline',
|
|
||||||
'mdi-dome-light',
|
|
||||||
'mdi-download-box',
|
|
||||||
'mdi-download-box-outline',
|
|
||||||
'mdi-download-circle',
|
|
||||||
'mdi-download-circle-outline',
|
|
||||||
'mdi-fan-alert',
|
|
||||||
'mdi-fan-chevron-down',
|
|
||||||
'mdi-fan-chevron-up',
|
|
||||||
'mdi-fan-minus',
|
|
||||||
'mdi-fan-plus',
|
|
||||||
'mdi-fan-remove',
|
|
||||||
'mdi-fan-speed-1',
|
|
||||||
'mdi-fan-speed-2',
|
|
||||||
'mdi-fan-speed-3',
|
|
||||||
'mdi-food-drumstick',
|
|
||||||
'mdi-food-drumstick-off',
|
|
||||||
'mdi-food-drumstick-off-outline',
|
|
||||||
'mdi-food-drumstick-outline',
|
|
||||||
'mdi-food-steak',
|
|
||||||
'mdi-food-steak-off',
|
|
||||||
'mdi-fuse-alert',
|
|
||||||
'mdi-fuse-off',
|
|
||||||
'mdi-heart-minus',
|
|
||||||
'mdi-heart-minus-outline',
|
|
||||||
'mdi-heart-off-outline',
|
|
||||||
'mdi-heart-plus',
|
|
||||||
'mdi-heart-plus-outline',
|
|
||||||
'mdi-heart-remove',
|
|
||||||
'mdi-heart-remove-outline',
|
|
||||||
'mdi-hours-24',
|
|
||||||
'mdi-incognito-circle',
|
|
||||||
'mdi-incognito-circle-off',
|
|
||||||
'mdi-lingerie',
|
|
||||||
'mdi-microwave-off',
|
|
||||||
'mdi-minus-circle-off',
|
|
||||||
'mdi-minus-circle-off-outline',
|
|
||||||
'mdi-motion-sensor-off',
|
|
||||||
'mdi-pail-minus',
|
|
||||||
'mdi-pail-minus-outline',
|
|
||||||
'mdi-pail-off',
|
|
||||||
'mdi-pail-off-outline',
|
|
||||||
'mdi-pail-outline',
|
|
||||||
'mdi-pail-plus',
|
|
||||||
'mdi-pail-plus-outline',
|
|
||||||
'mdi-pail-remove',
|
|
||||||
'mdi-pail-remove-outline',
|
|
||||||
'mdi-pine-tree-fire',
|
|
||||||
'mdi-power-plug-off-outline',
|
|
||||||
'mdi-power-plug-outline',
|
|
||||||
'mdi-printer-eye',
|
|
||||||
'mdi-printer-search',
|
|
||||||
'mdi-puzzle-check',
|
|
||||||
'mdi-puzzle-check-outline',
|
|
||||||
'mdi-rug',
|
|
||||||
'mdi-sawtooth-wave',
|
|
||||||
'mdi-set-square',
|
|
||||||
'mdi-smoking-pipe-off',
|
|
||||||
'mdi-spoon-sugar',
|
|
||||||
'mdi-square-wave',
|
|
||||||
'mdi-table-split-cell',
|
|
||||||
'mdi-ticket-percent-outline',
|
|
||||||
'mdi-triangle-wave',
|
|
||||||
'mdi-waveform',
|
|
||||||
'mdi-wizard-hat',
|
|
||||||
'mdi-ab-testing',
|
|
||||||
'mdi-abjad-arabic',
|
|
||||||
'mdi-abjad-hebrew',
|
|
||||||
'mdi-abugida-devanagari',
|
|
||||||
'mdi-abugida-thai',
|
|
||||||
'mdi-access-point',
|
|
||||||
'mdi-access-point-network',
|
|
||||||
'mdi-access-point-network-off',
|
|
||||||
'mdi-account',
|
|
||||||
'mdi-account-alert',
|
|
||||||
'mdi-account-alert-outline',
|
|
||||||
'mdi-account-arrow-left',
|
|
||||||
'mdi-account-arrow-left-outline',
|
|
||||||
'mdi-account-arrow-right',
|
|
||||||
'mdi-account-arrow-right-outline',
|
|
||||||
'mdi-account-box',
|
|
||||||
'mdi-account-box-multiple',
|
|
||||||
'mdi-account-box-multiple-outline',
|
|
||||||
'mdi-account-box-outline',
|
|
||||||
'mdi-account-cancel',
|
|
||||||
'mdi-account-cancel-outline',
|
|
||||||
'mdi-account-cash',
|
|
||||||
'mdi-account-cash-outline',
|
|
||||||
'mdi-account-check',
|
|
||||||
'mdi-account-check-outline',
|
|
||||||
'mdi-account-child',
|
|
||||||
'mdi-account-child-circle',
|
|
||||||
'mdi-account-child-outline',
|
|
||||||
'mdi-account-circle',
|
|
||||||
'mdi-account-circle-outline',
|
|
||||||
'mdi-account-clock',
|
|
||||||
'mdi-account-clock-outline',
|
|
||||||
'mdi-account-cog',
|
|
||||||
'mdi-account-cog-outline',
|
|
||||||
'mdi-account-convert',
|
|
||||||
'mdi-account-convert-outline',
|
|
||||||
'mdi-account-cowboy-hat',
|
|
||||||
'mdi-account-details',
|
|
||||||
'mdi-account-details-outline',
|
|
||||||
'mdi-account-edit',
|
|
||||||
'mdi-account-edit-outline',
|
|
||||||
'mdi-account-group',
|
|
||||||
'mdi-account-group-outline',
|
|
||||||
'mdi-account-hard-hat',
|
|
||||||
'mdi-account-heart',
|
|
||||||
'mdi-account-heart-outline',
|
|
||||||
'mdi-account-key',
|
|
||||||
'mdi-account-key-outline',
|
|
||||||
'mdi-account-lock',
|
|
||||||
'mdi-account-lock-outline',
|
|
||||||
'mdi-account-minus',
|
|
||||||
'mdi-account-minus-outline',
|
|
||||||
'mdi-account-multiple',
|
|
||||||
'mdi-account-multiple-check',
|
|
||||||
'mdi-account-multiple-check-outline',
|
|
||||||
'mdi-account-multiple-minus',
|
|
||||||
'mdi-account-multiple-minus-outline',
|
|
||||||
'mdi-account-multiple-outline',
|
|
||||||
'mdi-account-multiple-plus',
|
|
||||||
'mdi-account-multiple-plus-outline',
|
|
||||||
'mdi-account-multiple-remove',
|
|
||||||
'mdi-account-multiple-remove-outline',
|
|
||||||
'mdi-account-music',
|
|
||||||
'mdi-account-music-outline',
|
|
||||||
'mdi-account-network',
|
|
||||||
'mdi-account-network-outline',
|
|
||||||
'mdi-account-off',
|
|
||||||
'mdi-account-off-outline',
|
|
||||||
'mdi-account-outline',
|
|
||||||
'mdi-account-plus',
|
|
||||||
'mdi-account-plus-outline',
|
|
||||||
'mdi-account-question',
|
|
||||||
'mdi-account-question-outline',
|
|
||||||
'mdi-account-remove',
|
|
||||||
'mdi-account-remove-outline',
|
|
||||||
'mdi-account-search',
|
|
||||||
'mdi-account-search-outline',
|
|
||||||
'mdi-account-settings',
|
|
||||||
'mdi-account-settings-outline',
|
|
||||||
'mdi-account-star',
|
|
||||||
'mdi-account-star-outline',
|
|
||||||
'mdi-account-supervisor',
|
|
||||||
'mdi-account-supervisor-circle',
|
|
||||||
'mdi-account-supervisor-outline',
|
|
||||||
'mdi-account-switch',
|
|
||||||
'mdi-account-switch-outline',
|
|
||||||
'mdi-account-tie',
|
|
||||||
'mdi-account-tie-outline',
|
|
||||||
'mdi-account-tie-voice',
|
|
||||||
'mdi-account-tie-voice-off',
|
|
||||||
'mdi-account-tie-voice-off-outline',
|
|
||||||
'mdi-account-tie-voice-outline',
|
|
||||||
'mdi-account-voice',
|
|
||||||
'mdi-adjust',
|
|
||||||
'mdi-adobe',
|
|
||||||
'mdi-adobe-acrobat',
|
|
||||||
'mdi-air-conditioner',
|
|
||||||
'mdi-air-filter',
|
|
||||||
'mdi-air-horn',
|
|
||||||
'mdi-air-humidifier',
|
|
||||||
'mdi-air-purifier',
|
|
||||||
'mdi-airbag',
|
|
||||||
'mdi-airballoon',
|
|
||||||
'mdi-airballoon-outline',
|
|
||||||
'mdi-airplane',
|
|
||||||
'mdi-airplane-landing',
|
|
||||||
'mdi-airplane-off',
|
|
||||||
'mdi-airplane-takeoff',
|
|
||||||
'mdi-airport',
|
|
||||||
'mdi-alarm',
|
|
||||||
'mdi-alarm-bell',
|
|
||||||
'mdi-alarm-check',
|
|
||||||
'mdi-alarm-light',
|
|
||||||
'mdi-alarm-light-outline',
|
|
||||||
'mdi-alarm-multiple',
|
|
||||||
'mdi-alarm-note',
|
|
||||||
'mdi-alarm-note-off',
|
|
||||||
'mdi-alarm-off',
|
|
||||||
'mdi-alarm-plus',
|
|
||||||
'mdi-alarm-snooze',
|
|
||||||
'mdi-album',
|
|
||||||
'mdi-alert',
|
|
||||||
'mdi-alert-box',
|
|
||||||
'mdi-alert-box-outline',
|
|
||||||
'mdi-alert-circle',
|
|
||||||
'mdi-alert-circle-check',
|
|
||||||
'mdi-alert-circle-check-outline',
|
|
||||||
'mdi-alert-circle-outline',
|
|
||||||
]
|
|
||||||
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 60 KiB |
@ -1,3 +0,0 @@
|
|||||||
<template>
|
|
||||||
<footer f-c-c flex-col text-14 color="#6a6a6a"></footer>
|
|
||||||
</template>
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
<template>
|
|
||||||
<n-config-provider
|
|
||||||
wh-full
|
|
||||||
:locale="zhCN"
|
|
||||||
:date-locale="dateZhCN"
|
|
||||||
:theme="appStore.isDark ? darkTheme : undefined"
|
|
||||||
:theme-overrides="naiveThemeOverrides"
|
|
||||||
>
|
|
||||||
<n-loading-bar-provider>
|
|
||||||
<n-dialog-provider>
|
|
||||||
<n-notification-provider>
|
|
||||||
<n-message-provider>
|
|
||||||
<slot></slot>
|
|
||||||
<NaiveProviderContent />
|
|
||||||
</n-message-provider>
|
|
||||||
</n-notification-provider>
|
|
||||||
</n-dialog-provider>
|
|
||||||
</n-loading-bar-provider>
|
|
||||||
</n-config-provider>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { defineComponent, h } from 'vue'
|
|
||||||
import {
|
|
||||||
zhCN,
|
|
||||||
dateZhCN,
|
|
||||||
darkTheme,
|
|
||||||
useLoadingBar,
|
|
||||||
useDialog,
|
|
||||||
useMessage,
|
|
||||||
useNotification,
|
|
||||||
} from 'naive-ui'
|
|
||||||
import { useCssVar } from '@vueuse/core'
|
|
||||||
import { kebabCase } from 'lodash-es'
|
|
||||||
import { setupMessage, setupDialog } from '@/utils'
|
|
||||||
import { naiveThemeOverrides } from '~/settings'
|
|
||||||
import { useAppStore } from '@/store'
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
|
||||||
|
|
||||||
function setupCssVar() {
|
|
||||||
const common = naiveThemeOverrides.common
|
|
||||||
for (const key in common) {
|
|
||||||
useCssVar(`--${kebabCase(key)}`, document.documentElement).value = common[key] || ''
|
|
||||||
if (key === 'primaryColor') window.localStorage.setItem('__THEME_COLOR__', common[key] || '')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 挂载naive组件的方法至window, 以便在全局使用
|
|
||||||
function setupNaiveTools() {
|
|
||||||
window.$loadingBar = useLoadingBar()
|
|
||||||
window.$notification = useNotification()
|
|
||||||
|
|
||||||
window.$message = setupMessage(useMessage())
|
|
||||||
window.$dialog = setupDialog(useDialog())
|
|
||||||
}
|
|
||||||
|
|
||||||
const NaiveProviderContent = defineComponent({
|
|
||||||
setup() {
|
|
||||||
setupCssVar()
|
|
||||||
setupNaiveTools()
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
return h('div')
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@ -1,82 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div v-if="reloadFlag" class="relative">
|
|
||||||
<slot></slot>
|
|
||||||
<div v-show="showPlaceholder" class="absolute-lt h-full w-full" :class="placeholderClass">
|
|
||||||
<div v-show="loading" class="absolute-center">
|
|
||||||
<n-spin :show="true" :size="loadingSize" />
|
|
||||||
</div>
|
|
||||||
<div v-show="isEmpty" class="absolute-center">
|
|
||||||
<div class="relative">
|
|
||||||
<icon-custom-no-data :class="iconClass" />
|
|
||||||
<p class="absolute-lb w-full text-center" :class="descClass">{{ emptyDesc }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-show="!network" class="absolute-center">
|
|
||||||
<div
|
|
||||||
class="relative"
|
|
||||||
:class="{ 'cursor-pointer': showNetworkReload }"
|
|
||||||
@click="handleReload"
|
|
||||||
>
|
|
||||||
<icon-custom-network-error :class="iconClass" />
|
|
||||||
<p class="absolute-lb w-full text-center" :class="descClass">{{ networkErrorDesc }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, computed, nextTick, watch, onUnmounted } from 'vue'
|
|
||||||
|
|
||||||
defineOptions({ name: 'LoadingEmptyWrapper' })
|
|
||||||
|
|
||||||
const NETWORK_ERROR_MSG = '网络似乎开了小差~'
|
|
||||||
|
|
||||||
const props = {
|
|
||||||
loading: false,
|
|
||||||
empty: false,
|
|
||||||
loadingSize: 'medium',
|
|
||||||
placeholderClass: 'bg-white dark:bg-dark transition-background-color duration-300 ease-in-out',
|
|
||||||
emptyDesc: '暂无数据',
|
|
||||||
iconClass: 'text-320px text-primary',
|
|
||||||
descClass: 'text-16px text-#666',
|
|
||||||
showNetworkReload: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 网络状态
|
|
||||||
const network = ref(window.navigator.onLine)
|
|
||||||
const reloadFlag = ref(true)
|
|
||||||
|
|
||||||
// 数据是否为空
|
|
||||||
const isEmpty = computed(() => props.empty && !props.loading && network.value)
|
|
||||||
|
|
||||||
const showPlaceholder = computed(() => props.loading || isEmpty.value || !network.value)
|
|
||||||
|
|
||||||
const networkErrorDesc = computed(() =>
|
|
||||||
props.showNetworkReload ? `${NETWORK_ERROR_MSG}, 点击重试` : NETWORK_ERROR_MSG,
|
|
||||||
)
|
|
||||||
|
|
||||||
function handleReload() {
|
|
||||||
if (!props.showNetworkReload) return
|
|
||||||
reloadFlag.value = false
|
|
||||||
nextTick(() => {
|
|
||||||
reloadFlag.value = true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const stopHandle = watch(
|
|
||||||
() => props.loading,
|
|
||||||
(newValue) => {
|
|
||||||
// 结束加载判断一下网络状态
|
|
||||||
if (!newValue) {
|
|
||||||
network.value = window.navigator.onLine
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
stopHandle()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
||||||
@ -1,160 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div ref="wrapper" class="wrapper" @mousewheel.prevent="handleMouseWheel">
|
|
||||||
<template v-if="showArrow && isOverflow">
|
|
||||||
<div class="left" @click="handleMouseWheel({ wheelDelta: 120 })">
|
|
||||||
<icon-ic:baseline-keyboard-arrow-left />
|
|
||||||
</div>
|
|
||||||
<div class="right" @click="handleMouseWheel({ wheelDelta: -120 })">
|
|
||||||
<icon-ic:baseline-keyboard-arrow-right />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div
|
|
||||||
ref="content"
|
|
||||||
v-resize="refreshIsOverflow"
|
|
||||||
class="content"
|
|
||||||
:class="{ overflow: isOverflow && showArrow }"
|
|
||||||
:style="{
|
|
||||||
transform: `translateX(${translateX}px)`,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { debounce, useResize } from '@/utils'
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
showArrow: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const translateX = ref(0)
|
|
||||||
const content = ref(null)
|
|
||||||
const wrapper = ref(null)
|
|
||||||
const isOverflow = ref(false)
|
|
||||||
|
|
||||||
const refreshIsOverflow = debounce(() => {
|
|
||||||
const wrapperWidth = wrapper.value?.offsetWidth
|
|
||||||
const contentWidth = content.value?.offsetWidth
|
|
||||||
isOverflow.value = contentWidth > wrapperWidth
|
|
||||||
resetTranslateX(wrapperWidth, contentWidth)
|
|
||||||
}, 200)
|
|
||||||
|
|
||||||
function handleMouseWheel(e) {
|
|
||||||
const { wheelDelta } = e
|
|
||||||
const wrapperWidth = wrapper.value?.offsetWidth
|
|
||||||
const contentWidth = content.value?.offsetWidth
|
|
||||||
/**
|
|
||||||
* @wheelDelta 平行滚动的值 >0: 右移 <0: 左移
|
|
||||||
* @translateX 内容translateX的值
|
|
||||||
* @wrapperWidth 容器的宽度
|
|
||||||
* @contentWidth 内容的宽度
|
|
||||||
*/
|
|
||||||
if (wheelDelta < 0) {
|
|
||||||
if (wrapperWidth > contentWidth && translateX.value < -10) return
|
|
||||||
if (wrapperWidth <= contentWidth && contentWidth + translateX.value - wrapperWidth < -10) return
|
|
||||||
}
|
|
||||||
if (wheelDelta > 0 && translateX.value > 10) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
translateX.value += wheelDelta
|
|
||||||
resetTranslateX(wrapperWidth, contentWidth)
|
|
||||||
}
|
|
||||||
|
|
||||||
const resetTranslateX = debounce(function (wrapperWidth, contentWidth) {
|
|
||||||
if (!isOverflow.value) {
|
|
||||||
translateX.value = 0
|
|
||||||
} else if (-translateX.value > contentWidth - wrapperWidth) {
|
|
||||||
translateX.value = wrapperWidth - contentWidth
|
|
||||||
} else if (translateX.value > 0) {
|
|
||||||
translateX.value = 0
|
|
||||||
}
|
|
||||||
}, 200)
|
|
||||||
|
|
||||||
const observer = ref(null)
|
|
||||||
onMounted(() => {
|
|
||||||
refreshIsOverflow()
|
|
||||||
|
|
||||||
observer.value = useResize(document.body, refreshIsOverflow)
|
|
||||||
})
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
observer.value?.disconnect()
|
|
||||||
})
|
|
||||||
|
|
||||||
function handleScroll(x, width) {
|
|
||||||
const wrapperWidth = wrapper.value?.offsetWidth
|
|
||||||
const contentWidth = content.value?.offsetWidth
|
|
||||||
if (contentWidth <= wrapperWidth) return
|
|
||||||
|
|
||||||
// 当 x 小于可视范围的最小值时
|
|
||||||
if (x < -translateX.value + 150) {
|
|
||||||
translateX.value = -(x - 150)
|
|
||||||
resetTranslateX(wrapperWidth, contentWidth)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 当 x 大于可视范围的最大值时
|
|
||||||
if (x + width > -translateX.value + wrapperWidth) {
|
|
||||||
translateX.value = wrapperWidth - (x + width)
|
|
||||||
resetTranslateX(wrapperWidth, contentWidth)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
defineExpose({
|
|
||||||
handleScroll,
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.wrapper {
|
|
||||||
display: flex;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
z-index: 9;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
.content {
|
|
||||||
padding: 0 10px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
transition: transform 0.5s;
|
|
||||||
&.overflow {
|
|
||||||
padding-left: 30px;
|
|
||||||
padding-right: 30px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.left,
|
|
||||||
.right {
|
|
||||||
background-color: #fff;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
margin: auto;
|
|
||||||
|
|
||||||
width: 20px;
|
|
||||||
height: 35px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
font-size: 18px;
|
|
||||||
border: 1px solid #e0e0e6;
|
|
||||||
border-radius: 2px;
|
|
||||||
|
|
||||||
z-index: 2;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.left {
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
.right {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
/** 自定义图标 */
|
|
||||||
const props = defineProps({
|
|
||||||
/** 图标名称(assets/svg下的文件名) */
|
|
||||||
icon: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
type: Number,
|
|
||||||
default: 14,
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
type: String,
|
|
||||||
default: undefined,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<TheIcon type="custom" v-bind="props" />
|
|
||||||
</template>
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { watchDebounced } from '@vueuse/core'
|
|
||||||
import { NInput, NPopover } from 'naive-ui'
|
|
||||||
|
|
||||||
import TheIcon from './TheIcon.vue'
|
|
||||||
import iconData from '@/assets/js/icons'
|
|
||||||
|
|
||||||
const props = defineProps({ value: String })
|
|
||||||
const emit = defineEmits(['update:value'])
|
|
||||||
|
|
||||||
const choosed = ref(props.value) // 选中值
|
|
||||||
const icons = ref(iconData)
|
|
||||||
// const icons = ref(iconData.filter((icon) => icon.includes(choosed.value))) // 可选图标列表
|
|
||||||
|
|
||||||
function filterIcons() {
|
|
||||||
icons.value = iconData.filter((item) => item.includes(choosed.value))
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectIcon(icon) {
|
|
||||||
choosed.value = icon
|
|
||||||
emit('update:value', choosed.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
watchDebounced(
|
|
||||||
choosed,
|
|
||||||
() => {
|
|
||||||
filterIcons()
|
|
||||||
emit('update:value', choosed.value)
|
|
||||||
},
|
|
||||||
{ debounce: 200 },
|
|
||||||
)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="w-full">
|
|
||||||
<NPopover trigger="click" placement="bottom-start">
|
|
||||||
<template #trigger>
|
|
||||||
<NInput v-model:value="choosed" placeholder="请输入图标名称" @update:value="filterIcons">
|
|
||||||
<template #prefix>
|
|
||||||
<span class="i-mdi:magnify text-18" />
|
|
||||||
</template>
|
|
||||||
<template #suffix>
|
|
||||||
<TheIcon :icon="choosed" :size="18" />
|
|
||||||
</template>
|
|
||||||
</NInput>
|
|
||||||
</template>
|
|
||||||
<template #footer>
|
|
||||||
更多图标去
|
|
||||||
<a class="text-blue" target="_blank" href="https://icones.js.org/collection/all">
|
|
||||||
Icones
|
|
||||||
</a>
|
|
||||||
查看
|
|
||||||
</template>
|
|
||||||
<ul v-if="icons.length" class="h-150 w-300 overflow-y-scroll">
|
|
||||||
<li
|
|
||||||
v-for="(icon, index) in icons"
|
|
||||||
:key="index"
|
|
||||||
class="mx-5 inline-block cursor-pointer hover:text-cyan"
|
|
||||||
@click="selectIcon(icon)"
|
|
||||||
>
|
|
||||||
<TheIcon :icon="icon" :size="18" />
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div v-else>
|
|
||||||
<TheIcon :icon="choosed" :size="18" />
|
|
||||||
</div>
|
|
||||||
</NPopover>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||