Compare commits

..

62 Commits

Author SHA1 Message Date
lz-ui
ab1ed07333 fix:修改获取时间 2025-11-05 17:16:38 +08:00
lz-ui
3460626c94 fix:修改短视频脚本列表按钮状态 2025-11-05 13:01:54 +08:00
lz-ui
0149754b2a fix:添加热门足球 2025-11-04 16:04:03 +08:00
lz-ui
5621932809 fix:修改短视频脚本篮球 2025-10-30 16:08:34 +08:00
lz-ui
47c9ecd08e fix:比赛开始时间 2025-10-30 10:44:22 +08:00
lz-ui
9f62b9e8c1 fix:修改 2025-10-29 16:52:32 +08:00
lz-ui
61205bd973 fix:添加finyx 2025-10-29 15:46:29 +08:00
lz-ui
2438a83bb7 fix:添加finyx 2025-10-29 15:17:26 +08:00
lz-ui
4360ee9416 fix:修改名称 2025-10-29 14:16:16 +08:00
lz-ui
96981fc32f fix:添加主队客队 2025-10-29 10:20:07 +08:00
lz-ui
00f2ccce95 fix:修改球的颜色 2025-10-29 09:44:57 +08:00
lz-ui
1a456b2b51 fix:添加D3预测结果 2025-10-28 14:36:46 +08:00
lz-ui
a0799da57f fix:修改 2025-10-27 17:10:52 +08:00
lz-ui
c4e688a944 fix:添加标记 2025-10-27 14:06:56 +08:00
lz-ui
ff4dd7734b fix: 修改热门赛事列表 2025-10-24 17:43:32 +08:00
lz-ui
d932dcdf2b fix: 修改热门赛事列表 2025-10-24 17:35:02 +08:00
lz-ui
91b9e77132 fix:修改样式 2025-10-24 16:39:35 +08:00
lz-ui
36c19245ab fix:修改热门比赛 2025-10-24 14:33:27 +08:00
lz-ui
b09c812664 fix:修改热门比赛赛果跳转 2025-10-23 15:40:02 +08:00
lz-ui
228f2047df fix:修改篮球详情展示页面 2025-10-22 14:21:08 +08:00
lz-ui
abd5b1e854 fix:修改 2025-10-21 18:00:20 +08:00
lz-ui
0924402695 fix:修改 2025-10-21 17:17:02 +08:00
lz-ui
1fbec26287 fix:修改模型配置 2025-10-21 15:35:55 +08:00
lz-ui
9dca1a8ac2 fix:修改预测 2025-10-21 14:42:50 +08:00
lz-ui
2e50fff323 fix:修改体彩报告页面 2025-10-21 14:38:02 +08:00
lz-ui
938c737e60 fix:修改标记 2025-10-21 12:28:52 +08:00
lz-ui
66e9a60548 fix: 修改报告管理页面 2025-10-21 09:58:42 +08:00
lz-ui
e5ad27c262 fix:修改模型下拉接口 2025-10-21 09:37:00 +08:00
lz-ui
bbd3e99414 fix:修改底部版权 2025-10-17 15:42:19 +08:00
lz-ui
5a9ab352cd fix:修改 2025-10-17 14:09:55 +08:00
lz-ui
025d8b106b fix:修改模型下拉为空是重新请求 2025-10-16 15:59:32 +08:00
lz-ui
600fa0222f fix:修改详情页面表格宽度 2025-10-16 15:56:13 +08:00
lz-ui
c00bca445a fix:修改详情页面 2025-10-16 14:08:27 +08:00
lz-ui
bfc669d3e2 fix:修改d3模型 2025-10-16 11:46:35 +08:00
lz-ui
c6c35eca52 fix:修改提示文案 2025-10-16 10:43:09 +08:00
lz-ui
ca1113fc69 fix:修复系统主题色 2025-10-16 09:43:33 +08:00
lz-ui
21e96dec34 fix:修改优化 2025-10-15 17:03:48 +08:00
lz-ui
0809b505f9 fix:添加短视频脚本营销文案 2025-10-14 16:10:49 +08:00
lz-ui
3dab25b174 fix:添加模型配置页面 2025-10-13 16:55:59 +08:00
lz-ui
17121c94f1 fix:添加模型配置页面 2025-10-13 16:36:01 +08:00
lz-ui
dfff5b4dbf fix:修改短视频文案 2025-10-11 10:11:39 +08:00
lz-ui
2a81d298c5 fix:添加热门比赛列表 2025-10-11 09:32:19 +08:00
lz-ui
a0061c445e fix:修改查询条件 2025-10-11 09:21:34 +08:00
lz-ui
6cd567da14 fix:添加页面 2025-10-10 17:30:46 +08:00
lz-ui
338ca933b8 fix:添加页面 2025-10-10 16:31:49 +08:00
lz-ui
4c3103d67d fix:优化 2025-10-09 16:39:13 +08:00
lz-ui
19078a32ce feat:添加赛果赔率 2025-09-30 15:30:18 +08:00
lz-ui
7789db2f7d fix:修改联赛字段 2025-09-29 11:35:11 +08:00
lz-ui
2ce3bcae33 fix:打包后去掉调试代码 2025-09-28 16:16:43 +08:00
lz-ui
cab26cdc30 fix:取消新窗口打开 2025-09-28 15:21:40 +08:00
lz-ui
bf4d4e3b9e fix:添加页面缓存 2025-09-28 15:07:58 +08:00
lz-ui
ab4be9ad69 fix:添加loading 2025-09-28 12:53:33 +08:00
lz-ui
5347812bc3 fix:修改时间展示 2025-09-28 12:16:16 +08:00
lz-ui
327a176555 fix:修改 2025-09-28 11:53:00 +08:00
lz-ui
4761553029 fix:添加生成报告状态 2025-09-26 16:00:18 +08:00
lz-ui
ff18c04696 fix:优化界面 2025-09-26 11:39:39 +08:00
lz-ui
06c62a7a16 fix:修改筛选条件重置 2025-09-25 16:06:11 +08:00
lz-ui
8002a25815 fix:修改 2025-09-24 17:03:08 +08:00
lz-ui
1a2b13bd70 fix:修改分页参数 2025-09-23 10:54:42 +08:00
lz-ui
06dfa7c3a6 fix:修改列表参数 2025-09-23 10:27:36 +08:00
lz-ui
59e8da73eb fix:修改md 2025-09-22 19:05:57 +08:00
lz-ui
aaa6e169a0 fix:修改样式 2025-09-17 11:04:09 +08:00
52 changed files with 5493 additions and 305 deletions

View File

@ -54,4 +54,4 @@ yarn dev
Copyright ©2025 北京数维无穹科技有限公司 Copyright ©2025 北京数维无穹科技有限公司

View File

@ -17,20 +17,28 @@
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "2.3.1", "@element-plus/icons-vue": "2.3.1",
"@lzui/lzui-lib": "0.1.0-alpha7",
"@vavt/cm-extension": "^1.11.0",
"@vueup/vue-quill": "1.2.0", "@vueup/vue-quill": "1.2.0",
"@vueuse/core": "13.3.0", "@vueuse/core": "13.3.0",
"axios": "1.9.0", "axios": "1.9.0",
"clipboard": "2.0.11", "clipboard": "2.0.11",
"cropperjs": "^1.6.2",
"dayjs": "^1.11.18", "dayjs": "^1.11.18",
"echarts": "5.6.0", "echarts": "5.6.0",
"element-plus": "2.10.7", "element-plus": "2.10.7",
"file-saver": "2.0.5", "file-saver": "2.0.5",
"fuse.js": "6.6.2", "fuse.js": "6.6.2",
"highlight.js": "^11.9.0",
"js-beautify": "1.14.11", "js-beautify": "1.14.11",
"js-cookie": "3.0.5", "js-cookie": "3.0.5",
"jsencrypt": "3.3.2", "jsencrypt": "3.3.2",
"katex": "^0.16.22",
"md-editor-v3": "^5.8.4",
"mermaid": "^11.12.0",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"pinia": "3.0.2", "pinia": "3.0.2",
"screenfull": "^6.0.2",
"sortablejs": "^1.15.6", "sortablejs": "^1.15.6",
"splitpanes": "4.0.4", "splitpanes": "4.0.4",
"vue": "3.5.16", "vue": "3.5.16",

1613
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -20,9 +20,59 @@ export function Info(data) {
// 报告详情 // 报告详情
export function reportDetail(id) { export function reportDetail(id, modelType) {
return request({ return request({
url: `/tc/report/${id}`, url: `/tc/report/${id}?modelType=${modelType}`,
method: 'get' method: 'get'
}) })
} }
// 详情
export function detail(data) {
return request({
url: '/tc/report/detail',
method: 'post',
data: data
})
}
// 联赛类型-足球
export function infoSelectDistinctLeagueAbbNames(data) {
return request({
url: '/tc/info/selectDistinctLeagueAbbNames',
method: 'post',
data: data
})
}
// 联赛类型-篮球
export function bbInfoSelectDistinctLeagueAbbNames(data) {
return request({
url: '/tc/bbInfo/selectDistinctLeagueAbbNames',
method: 'post',
data: data
})
}
/** 报告更新 */
export function reportUpdate(data) {
return request({
url: '/tc/report/update',
method: 'post',
data: data
})
}
/** 报告更新 */
export function reportResultUpdate(data) {
return request({
url: '/tc/reportResult/update',
method: 'post',
data: data
})
}

11
src/api/tc/hot.js Normal file
View File

@ -0,0 +1,11 @@
import request from '@/utils/request'
// 热门足球列表
export function hotMatchList(data) {
return request({
url: '/hot/match/list',
method: 'post',
data: data
})
}

38
src/api/tc/model.js Normal file
View File

@ -0,0 +1,38 @@
import request from '@/utils/request'
/** 模型列表*/
export function modelList() {
return request({
url: `/model/config/modelList`,
method: 'get'
})
}
/** 模型配置列表*/
export function modelConfigList(data) {
return request({
url: '/model/config/list',
method: 'post',
data: data
})
}
/** 模型配置保存*/
export function modelConfigUpdate(data) {
return request({
url: '/model/config/update',
method: 'post',
data: data
})
}
export function modelConfigHistory(data) {
return request({
url: '/model/config/history',
method: 'post',
data: data
})
}

View File

@ -0,0 +1,134 @@
<svg width="312" height="298" viewBox="0 0 312 298" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="empty1">
<path id="Vector 478" d="M17 52V170L220 166.5V77H171V0H76.5V52H17Z" fill="url(#paint0_linear_93_4942)"/>
<path id="Vector 479" d="M235.5 52V164.5H274.5V52H235.5Z" fill="url(#paint1_linear_93_4942)"/>
<path id="&#60;Path&#62;" d="M156 298C242.156 298 312 263.302 312 220.5C312 177.698 242.156 143 156 143C69.8436 143 0 177.698 0 220.5C0 263.302 69.8436 298 156 298Z" fill="url(#paint2_linear_93_4942)"/>
<g id="Group 26648">
<path id="Path 25711" d="M156.838 179.689L152.7 180.155L151.174 170.771L155.312 170.305L156.838 179.689Z" fill="#FFC3BD"/>
<path id="Path 25712" d="M175.364 180.593H171.232L170.203 171.024H174.335L175.364 180.593Z" fill="#FFC3BD"/>
<path id="Path 25713" d="M170.892 180.112H175.929C176.011 180.112 176.09 180.14 176.154 180.191C176.218 180.242 176.263 180.314 176.281 180.394L177.097 184.067C177.116 184.156 177.115 184.249 177.093 184.338C177.071 184.427 177.03 184.51 176.972 184.58C176.914 184.651 176.84 184.708 176.757 184.746C176.674 184.784 176.583 184.803 176.492 184.802C174.871 184.774 173.692 184.679 171.648 184.679C170.392 184.679 166.604 184.809 164.87 184.809C163.17 184.809 162.909 183.094 163.619 182.939C166.803 182.239 169.202 181.282 170.219 180.366C170.404 180.201 170.644 180.11 170.892 180.112Z" fill="#263238"/>
<path id="Path 25714" d="M152.632 179.446L157.116 178.938C157.197 178.928 157.28 178.947 157.349 178.991C157.419 179.034 157.471 179.1 157.498 179.178L158.723 182.735C158.754 182.821 158.765 182.913 158.755 183.004C158.745 183.095 158.714 183.182 158.665 183.259C158.616 183.336 158.55 183.401 158.472 183.449C158.394 183.497 158.306 183.526 158.215 183.535C156.595 183.691 154.247 183.861 152.215 184.092C149.838 184.362 149.442 184.998 146.638 184.933C144.938 184.893 144.512 183.168 145.225 183.033C148.473 182.402 149.101 181.911 151.682 179.885C151.952 179.653 152.281 179.501 152.632 179.446V179.446Z" fill="#263238"/>
<path id="Path 25715" d="M156.282 59.177C154.894 60.323 153.528 61.319 152.115 62.339C150.702 63.359 149.259 64.306 147.774 65.225C146.289 66.144 144.765 67.025 143.167 67.825C141.533 68.6714 139.833 69.3811 138.082 69.947C137.619 70.095 137.168 70.217 136.648 70.347C136.14 70.4573 135.625 70.5397 135.108 70.594C134.177 70.694 133.301 70.739 132.428 70.779C130.688 70.859 128.981 70.857 127.276 70.845C123.866 70.804 120.485 70.64 117.089 70.34L117.038 67.24C120.373 66.811 123.723 66.44 127.038 66.067C128.695 65.887 130.348 65.685 131.963 65.474C132.763 65.365 133.563 65.237 134.301 65.1C134.618 65.044 134.932 64.9703 135.241 64.879C135.532 64.779 135.889 64.665 136.219 64.532C137.636 63.9567 139.012 63.2837 140.336 62.518C141.707 61.731 143.079 60.886 144.427 59.988C145.775 59.09 147.117 58.16 148.447 57.211C149.777 56.262 151.106 55.257 152.354 54.311L156.282 59.177Z" fill="#FFC3BD"/>
<path id="Path 25716" d="M160.321 55.6449C159.727 59.5509 151.503 65.5259 151.503 65.5259L145.603 58.2029C148.188 55.4446 150.928 52.8366 153.811 50.3919C156.466 48.2219 160.967 51.3949 160.321 55.6449Z" fill="#407BFF"/>
<path id="Path 25717" d="M118.176 67.567L115.83 65.897L115.573 71.173C115.928 71.1739 116.277 71.088 116.591 70.9227C116.905 70.7575 117.173 70.5179 117.373 70.225L118.176 67.567Z" fill="#FFC3BD"/>
<path id="Path 25718" d="M113.711 64.3608L113.231 69.5318L115.575 71.1728L115.832 65.8968L113.711 64.3608Z" fill="#FFC3BD"/>
<g id="Group 26641">
<path id="Path 25719" opacity="0.2" d="M151.176 170.774L151.962 175.611L156.101 175.145L155.315 170.308L151.176 170.774Z" fill="black"/>
<path id="Path 25720" opacity="0.2" d="M174.337 171.025H170.203L170.735 175.957H174.869L174.337 171.025Z" fill="black"/>
</g>
<path id="Path 25721" d="M174.396 50.5172C174.704 50.5862 174.995 50.716 175.251 50.8991C175.508 51.0822 175.726 51.3148 175.891 51.5833C176.057 51.8517 176.167 52.1506 176.216 52.4623C176.264 52.7739 176.249 53.0921 176.173 53.3981C175.276 57.1196 174.601 60.8909 174.149 64.6921C173.758 67.8921 173.524 70.9491 173.378 73.7201C173.035 80.2151 173.178 85.1661 172.984 86.8441C169.753 86.6201 157.577 85.7731 150.938 85.3091C148.697 67.7651 151.323 56.5691 152.798 52.0201C153.024 51.3113 153.446 50.6812 154.016 50.2032C154.587 49.7252 155.281 49.419 156.018 49.3201C156.864 49.2091 157.876 49.1021 158.944 49.0391C159.318 49.0151 159.697 49.0021 160.083 48.9941C163.217 49.0312 166.347 49.2489 169.456 49.6461C170.046 49.7161 170.642 49.8031 171.222 49.8961C172.381 50.0901 173.483 50.3132 174.396 50.5172Z" fill="#346AE1"/>
<path id="Path 25722" d="M169.265 39.0332C168.465 42.0072 167.487 47.4912 169.457 49.6512C164.347 53.0882 161.085 57.9272 160.144 56.8762C159.651 56.3262 159.437 49.9612 160.085 48.9972C163.504 48.4292 163.591 45.9282 163.169 43.5442L169.265 39.0332Z" fill="#FFC3BD"/>
<path id="Path 25723" d="M169.061 48.418C169.061 48.418 160.734 52.103 159.63 60.343C161.924 57.687 166.991 54.797 166.991 54.797L164.756 54.155C166.177 53.6155 167.649 53.2196 169.149 52.973C168.901 51.835 170.223 49.565 170.223 49.565L169.061 48.418Z" fill="#407BFF"/>
<path id="Path 25724" d="M161.548 48.2852C161.548 48.2852 162.658 52.9912 159.631 60.3432C159.034 57.7771 158.216 55.2677 157.185 52.8432L159.224 53.3982C159.224 53.3982 159.124 52.4492 157.473 51.1872C158.161 50.1879 159.019 49.317 160.008 48.6142L161.548 48.2852Z" fill="#407BFF"/>
<path id="Path 25725" opacity="0.2" d="M166.78 40.874L163.172 43.542C163.279 44.0972 163.337 44.6607 163.345 45.226C164.645 45.126 166.505 43.843 166.736 42.508C166.849 41.9705 166.864 41.4169 166.78 40.874V40.874Z" fill="black"/>
<path id="Path 25726" d="M158.684 30.421C156.669 30.508 155.557 33.982 157.602 36.843C159.647 39.704 161.399 30.304 158.684 30.421Z" fill="#263238"/>
<path id="Path 25727" d="M168.621 33.4779C168.86 37.5719 169.208 39.9549 167.406 42.2879C164.696 45.7969 159.456 44.5389 157.999 40.5989C156.688 37.0529 156.517 30.9539 160.299 28.8589C161.131 28.3925 162.068 28.1466 163.022 28.1445C163.976 28.1425 164.914 28.3844 165.748 28.8473C166.582 29.3101 167.284 29.9786 167.787 30.7891C168.29 31.5995 168.577 32.5251 168.621 33.4779V33.4779Z" fill="#FFC3BD"/>
<path id="Path 25728" d="M169.222 36.6241C168.127 35.9823 167.171 35.1292 166.41 34.1144C165.648 33.0996 165.096 31.9434 164.785 30.7131C163.585 30.9971 157.604 33.7491 155.765 30.7131C153.926 27.6771 156.24 25.8961 159.681 27.7651C158.159 25.0791 159.543 23.765 164.325 23.649C169.107 23.533 168.464 26.3051 168.464 26.3051C168.464 26.3051 172.084 24.7291 173.364 27.5051C174.847 30.6951 172.111 36.1421 169.222 36.6241Z" fill="#263238"/>
<path id="Path 25729" d="M167.646 25.5722C167.69 25.5722 169.457 25.9972 171.493 23.9482C171.128 25.6962 167.966 26.8602 167.966 26.8602L167.646 25.5722Z" fill="#263238"/>
<path id="Path 25730" d="M170.022 31.5609C168.115 30.9019 165.806 33.7269 166.659 37.1379C167.512 40.5489 172.591 32.4489 170.022 31.5609Z" fill="#263238"/>
<path id="Path 25731" d="M171.101 36.8829C170.926 37.8996 170.356 38.8057 169.515 39.4029C168.394 40.1849 167.384 39.2909 167.315 37.9969C167.257 36.8329 167.769 35.0229 169.076 34.7559C169.363 34.7023 169.659 34.7212 169.936 34.8109C170.214 34.9007 170.465 35.0584 170.666 35.2697C170.867 35.4811 171.012 35.7393 171.088 36.021C171.164 36.3028 171.169 36.599 171.101 36.8829V36.8829Z" fill="#FFC3BD"/>
<g id="Group 26642">
<path id="Path 25732" d="M157.152 131.863C158.145 119.777 165.429 86.3201 165.429 86.3201L150.935 85.3091C150.935 85.3091 145.346 118.52 144.918 131.124C144.472 144.229 149.743 173.355 149.743 173.355L156.694 172.564C156.694 172.564 156.155 143.999 157.152 131.863Z" fill="#407BFF"/>
<path id="Path 25733" opacity="0.5" d="M157.152 131.863C158.145 119.777 165.429 86.3201 165.429 86.3201L150.935 85.3091C150.935 85.3091 145.346 118.52 144.918 131.124C144.472 144.229 149.743 173.355 149.743 173.355L156.694 172.564C156.694 172.564 156.155 143.999 157.152 131.863Z" fill="white"/>
</g>
<path id="Path 25734" opacity="0.2" d="M159.969 97.6499C157.047 101.386 156.995 114.507 158.125 124.201C159.202 117.208 160.899 108.327 162.386 100.924L159.969 97.6499Z" fill="black"/>
<g id="Group 26643">
<path id="Path 25735" d="M158.756 85.854C158.756 85.854 160.32 121.229 162.065 133.209C163.975 146.328 168.826 175.001 168.826 175.001H176.394C176.394 175.001 175.149 147.995 174.15 135.106C173.013 120.425 172.982 86.846 172.982 86.846L158.756 85.854Z" fill="#407BFF"/>
<path id="Path 25736" opacity="0.5" d="M158.756 85.854C158.756 85.854 160.32 121.229 162.065 133.209C163.975 146.328 168.826 175.001 168.826 175.001H176.394C176.394 175.001 175.149 147.995 174.15 135.106C173.013 120.425 172.982 86.846 172.982 86.846L158.756 85.854Z" fill="white"/>
</g>
<path id="Path 25737" d="M167.916 175.162H176.827V172.5L166.866 172.327L167.916 175.162Z" fill="#407BFF"/>
<path id="Path 25738" d="M149.44 174.138L157.724 173.199L157.424 170.522L148.147 171.431L149.44 174.138Z" fill="#407BFF"/>
<path id="Path 25739" d="M162.593 35.3551C162.633 35.6861 162.493 35.9751 162.273 36.0011C162.053 36.0271 161.849 35.7801 161.81 35.4491C161.771 35.1181 161.91 34.8291 162.13 34.8031C162.35 34.7771 162.554 35.0241 162.593 35.3551Z" fill="#263238"/>
<path id="Path 25740" d="M158.854 35.8039C158.894 36.1349 158.754 36.4238 158.534 36.4498C158.314 36.4758 158.11 36.2289 158.07 35.8979C158.03 35.5669 158.17 35.2779 158.39 35.2519C158.61 35.2259 158.814 35.4769 158.854 35.8039Z" fill="#263238"/>
<path id="Path 25741" d="M160.062 35.8262C159.789 36.8849 159.372 37.9011 158.822 38.8462C159.067 38.9806 159.339 39.0598 159.618 39.0783C159.897 39.0968 160.177 39.0541 160.438 38.9532L160.062 35.8262Z" fill="#ED847E"/>
<path id="Path 25742" d="M163.61 34.0063C163.575 34.0168 163.538 34.0176 163.503 34.0086C163.468 33.9996 163.436 33.9812 163.41 33.9553C163.245 33.7734 163.039 33.6333 162.809 33.5464C162.579 33.4595 162.331 33.4283 162.087 33.4553C162.036 33.4639 161.984 33.4524 161.941 33.4234C161.898 33.3943 161.869 33.3498 161.858 33.2993C161.853 33.274 161.853 33.2479 161.858 33.2225C161.863 33.1972 161.873 33.1731 161.888 33.1518C161.902 33.1304 161.921 33.1122 161.943 33.0982C161.964 33.0842 161.989 33.0747 162.014 33.0703C162.322 33.0303 162.636 33.0651 162.928 33.1716C163.22 33.2781 163.483 33.4532 163.693 33.6823C163.729 33.7195 163.749 33.7692 163.749 33.8208C163.749 33.8724 163.729 33.922 163.693 33.9593C163.67 33.9817 163.641 33.9978 163.61 34.0063V34.0063Z" fill="#263238"/>
<path id="Path 25744" d="M157.095 34.7103C157.056 34.7234 157.013 34.7234 156.974 34.7103C156.926 34.6924 156.886 34.6565 156.863 34.6101C156.841 34.5637 156.837 34.5104 156.853 34.4613C156.947 34.1647 157.111 33.895 157.331 33.6753C157.551 33.4556 157.821 33.2923 158.118 33.1993C158.168 33.1879 158.221 33.1963 158.265 33.2228C158.309 33.2492 158.341 33.2917 158.355 33.3413C158.366 33.3913 158.358 33.4438 158.332 33.488C158.306 33.5321 158.263 33.5644 158.214 33.5783V33.5783C157.981 33.6561 157.769 33.7883 157.597 33.9639C157.424 34.1395 157.296 34.3535 157.223 34.5883C157.212 34.6171 157.195 34.643 157.173 34.6642C157.151 34.6853 157.124 34.7011 157.095 34.7103Z" fill="#263238"/>
<path id="Path 25745" d="M169.531 180.834C169.248 180.857 168.966 180.782 168.731 180.623C168.658 180.56 168.601 180.48 168.566 180.39C168.531 180.299 168.519 180.202 168.531 180.106C168.531 180.049 168.546 179.993 168.576 179.944C168.606 179.895 168.648 179.855 168.699 179.829C169.158 179.593 170.489 180.413 170.639 180.507C170.655 180.518 170.668 180.533 170.676 180.55C170.684 180.568 170.687 180.588 170.684 180.607C170.681 180.626 170.672 180.644 170.659 180.658C170.646 180.672 170.629 180.682 170.61 180.687C170.257 180.776 169.895 180.825 169.531 180.834V180.834ZM168.917 179.979C168.873 179.977 168.83 179.985 168.79 180.003C168.77 180.014 168.753 180.031 168.742 180.052C168.731 180.072 168.726 180.095 168.728 180.118C168.719 180.184 168.727 180.25 168.75 180.312C168.773 180.374 168.811 180.43 168.861 180.473C169.323 180.684 169.847 180.71 170.328 180.547C169.897 180.268 169.416 180.075 168.912 179.979H168.917Z" fill="#407BFF"/>
<path id="Path 25746" d="M170.584 180.689C170.568 180.689 170.551 180.685 170.537 180.677C170.11 180.445 169.283 179.539 169.37 179.077C169.384 179.005 169.423 178.94 169.48 178.893C169.536 178.846 169.607 178.82 169.681 178.82C169.755 178.811 169.831 178.817 169.903 178.839C169.975 178.861 170.041 178.897 170.098 178.946C170.578 179.339 170.677 180.531 170.68 180.581C170.681 180.598 170.678 180.616 170.67 180.632C170.662 180.648 170.651 180.661 170.636 180.671C170.621 180.682 170.603 180.688 170.584 180.689ZM169.75 179.014H169.705C169.578 179.03 169.567 179.088 169.562 179.114C169.51 179.386 170.037 180.07 170.462 180.393C170.434 179.92 170.264 179.467 169.974 179.093C169.911 179.041 169.832 179.013 169.75 179.014V179.014Z" fill="#407BFF"/>
<path id="Path 25747" d="M152.296 180.057L152.28 180.064C151.633 180.271 150.475 180.564 149.98 180.218C149.907 180.168 149.847 180.1 149.806 180.021C149.765 179.942 149.744 179.855 149.744 179.766C149.74 179.713 149.75 179.659 149.773 179.61C149.796 179.562 149.831 179.52 149.875 179.489C150.34 179.162 152.087 179.805 152.285 179.88C152.302 179.887 152.317 179.899 152.327 179.914C152.338 179.929 152.344 179.947 152.345 179.966C152.346 179.984 152.342 180.002 152.334 180.019C152.325 180.035 152.312 180.049 152.296 180.058V180.057ZM150.013 179.633L149.99 179.647C149.972 179.659 149.958 179.676 149.949 179.695C149.94 179.715 149.937 179.737 149.94 179.758C149.939 179.817 149.952 179.875 149.978 179.927C150.005 179.979 150.044 180.024 150.092 180.058C150.7 180.248 151.356 180.212 151.94 179.958C151.335 179.69 150.672 179.578 150.012 179.633H150.013Z" fill="#407BFF"/>
<path id="Path 25748" d="M152.296 180.057C152.272 180.069 152.245 180.071 152.22 180.063C151.7 179.897 150.62 179.12 150.64 178.648C150.645 178.537 150.708 178.392 150.972 178.335C151.067 178.314 151.166 178.312 151.262 178.33C151.358 178.349 151.449 178.386 151.53 178.441C151.954 178.846 152.239 179.375 152.346 179.951C152.349 179.968 152.348 179.985 152.343 180.001C152.338 180.018 152.329 180.032 152.316 180.044C152.31 180.049 152.303 180.053 152.296 180.057V180.057ZM150.905 178.567C150.838 178.603 150.836 178.645 150.835 178.661C150.821 178.945 151.567 179.567 152.108 179.813C152.008 179.352 151.769 178.933 151.423 178.613C151.364 178.572 151.297 178.544 151.226 178.53C151.156 178.517 151.083 178.518 151.013 178.534C150.976 178.54 150.939 178.551 150.905 178.567Z" fill="#407BFF"/>
<g id="Group 26647">
<path id="Path 25749" d="M177.882 56.4766C177.777 58.0906 177.587 59.5936 177.39 61.1456C177.193 62.6976 176.928 64.2186 176.637 65.7536C176.061 68.8888 175.211 71.9674 174.096 74.9536L173.605 76.1106L173.481 76.3996L173.45 76.4716L173.399 76.5816L173.255 76.8666C173.065 77.2129 172.836 77.5369 172.574 77.8326C172.143 78.3178 171.639 78.7327 171.08 79.0626C170.627 79.332 170.153 79.5625 169.661 79.7516C168.023 80.3425 166.31 80.7 164.573 80.8136C161.418 81.0493 158.247 80.9309 155.119 80.4606L155.232 77.3606L157.418 77.1136C158.151 77.0266 158.88 76.9136 159.605 76.8136C161.052 76.6006 162.484 76.3626 163.849 76.0456C165.112 75.7886 166.339 75.3817 167.505 74.8336C167.819 74.7015 168.095 74.4912 168.305 74.2226C168.318 74.1516 168.16 74.4626 168.346 73.9656L168.673 73.0096C169.474 70.269 170.087 67.4768 170.507 64.6526C170.742 63.2146 170.943 61.7636 171.137 60.3086C171.331 58.8536 171.491 57.3686 171.644 55.9736L177.882 56.4766Z" fill="#FFC3BD"/>
<path id="Path 25750" d="M178.242 53.4808C180.265 56.8738 178.542 67.5378 178.542 67.5378L167.942 65.5788C167.942 65.5788 167.368 59.4788 169.386 54.7848C171.577 49.6758 175.791 49.3698 178.242 53.4808Z" fill="#407BFF"/>
<g id="Group 26646">
<path id="Path 25751" d="M152.264 86.9518L146.639 60.7878C146.369 59.6705 145.743 58.6713 144.856 57.9408C143.968 57.2103 142.867 56.788 141.719 56.7378H120.166C121.315 56.7878 122.416 57.21 123.303 57.9405C124.191 58.671 124.817 59.6704 125.087 60.7878L130.712 86.9518C130.982 88.0691 131.608 89.0683 132.495 89.7988C133.383 90.5293 134.484 90.9515 135.632 91.0018H157.184C156.036 90.9515 154.935 90.5293 154.047 89.7988C153.16 89.0683 152.534 88.0691 152.264 86.9518V86.9518Z" fill="#263238"/>
<path id="Path 25752" opacity="0.7" d="M152.264 86.9518L146.639 60.7878C146.369 59.6705 145.743 58.6713 144.856 57.9408C143.968 57.2103 142.867 56.788 141.719 56.7378H120.166C121.315 56.7878 122.416 57.21 123.303 57.9405C124.191 58.671 124.817 59.6704 125.087 60.7878L130.712 86.9518C130.982 88.0691 131.608 89.0683 132.495 89.7988C133.383 90.5293 134.484 90.9515 135.632 91.0018H157.184C156.036 90.9515 154.935 90.5293 154.047 89.7988C153.16 89.0683 152.534 88.0691 152.264 86.9518V86.9518Z" fill="#407BFF"/>
<path id="Path 25753" d="M120.166 56.7378H141.718C140.615 56.7585 139.557 57.1814 138.743 57.9272C137.93 58.673 137.416 59.6903 137.3 60.7878L131.709 121.588C131.592 122.685 131.079 123.702 130.266 124.448C129.452 125.194 128.394 125.617 127.291 125.638H113.839C113.321 125.647 112.807 125.546 112.331 125.341C111.855 125.136 111.428 124.831 111.08 124.448C110.731 124.064 110.468 123.611 110.309 123.117C110.15 122.624 110.098 122.103 110.157 121.588L115.749 60.7878C115.865 59.6904 116.378 58.6733 117.192 57.9276C118.005 57.1818 119.063 56.7587 120.166 56.7378Z" fill="#407BFF"/>
<g id="Group 26644">
<path id="Path 25754" d="M123.609 121.587C123.55 122.102 123.602 122.623 123.761 123.117C123.92 123.61 124.183 124.063 124.532 124.447C124.88 124.83 125.307 125.135 125.783 125.34C126.259 125.545 126.773 125.647 127.291 125.637H105.739C105.221 125.647 104.706 125.546 104.231 125.34C103.755 125.135 103.328 124.831 102.979 124.447C102.631 124.064 102.368 123.61 102.209 123.117C102.05 122.623 101.998 122.102 102.057 121.587H123.609Z" fill="#263238"/>
<path id="Path 25755" opacity="0.7" d="M123.609 121.587C123.55 122.102 123.602 122.623 123.761 123.117C123.92 123.61 124.183 124.063 124.532 124.447C124.88 124.83 125.307 125.135 125.783 125.34C126.259 125.545 126.773 125.647 127.291 125.637H105.739C105.221 125.647 104.706 125.546 104.231 125.34C103.755 125.135 103.328 124.831 102.979 124.447C102.631 124.064 102.368 123.61 102.209 123.117C102.05 122.623 101.998 122.102 102.057 121.587H123.609Z" fill="#407BFF"/>
</g>
<g id="Group 26645" opacity="0.5">
<path id="Path 25756" opacity="0.5" d="M133.565 63.5497H118.981C118.868 63.5513 118.757 63.5288 118.653 63.4839C118.55 63.439 118.458 63.3726 118.382 63.2892C118.306 63.2058 118.249 63.1073 118.215 63.0001C118.18 62.8929 118.168 62.7796 118.181 62.6677V62.6677C118.207 62.429 118.319 62.2078 118.496 62.0455C118.673 61.8832 118.903 61.7909 119.143 61.7857H133.725C133.838 61.7842 133.949 61.8066 134.053 61.8515C134.156 61.8964 134.248 61.9628 134.324 62.0462C134.4 62.1296 134.457 62.2282 134.491 62.3353C134.526 62.4425 134.537 62.5558 134.525 62.6677V62.6677C134.499 62.9061 134.387 63.127 134.211 63.2893C134.034 63.4515 133.805 63.5441 133.565 63.5497V63.5497Z" fill="white"/>
<path id="Path 25757" opacity="0.5" d="M133.131 68.3207H118.547C118.434 68.3223 118.323 68.2998 118.219 68.2549C118.116 68.21 118.024 68.1436 117.948 68.0602C117.872 67.9768 117.815 67.8782 117.781 67.7711C117.746 67.6639 117.734 67.5506 117.747 67.4387C117.773 67.2 117.885 66.9788 118.062 66.8165C118.239 66.6542 118.469 66.5619 118.709 66.5567H133.293C133.406 66.5552 133.517 66.5776 133.621 66.6225C133.724 66.6674 133.816 66.7338 133.892 66.8172C133.968 66.9006 134.025 66.9992 134.059 67.1063C134.094 67.2135 134.105 67.3268 134.093 67.4387V67.4387C134.067 67.6775 133.955 67.8988 133.778 68.0612C133.601 68.2235 133.371 68.3158 133.131 68.3207V68.3207Z" fill="white"/>
<path id="Path 25758" opacity="0.5" d="M129.122 73.0917H118.113C118 73.0932 117.889 73.0708 117.785 73.0259C117.682 72.981 117.59 72.9146 117.514 72.8312C117.438 72.7478 117.381 72.6492 117.347 72.5421C117.312 72.4349 117.3 72.3216 117.313 72.2097V72.2097C117.339 71.9709 117.451 71.7498 117.628 71.5875C117.805 71.4252 118.035 71.3329 118.275 71.3277H129.284C129.397 71.3262 129.508 71.3486 129.611 71.3935C129.715 71.4384 129.807 71.5048 129.883 71.5882C129.959 71.6716 130.016 71.7702 130.05 71.8773C130.085 71.9845 130.096 72.0978 130.084 72.2097V72.2097C130.058 72.4485 129.946 72.6696 129.769 72.8319C129.592 72.9942 129.362 73.0866 129.122 73.0917V73.0917Z" fill="white"/>
<path id="Path 25759" opacity="0.5" d="M121.413 77.8617H117.68C117.567 77.8633 117.456 77.8409 117.352 77.7959C117.249 77.751 117.157 77.6847 117.081 77.6012C117.005 77.5178 116.948 77.4193 116.914 77.3121C116.879 77.205 116.867 77.0917 116.88 76.9797V76.9797C116.906 76.7411 117.017 76.5199 117.194 76.3576C117.371 76.1953 117.601 76.1029 117.841 76.0977H121.575C121.688 76.0962 121.799 76.1186 121.902 76.1635C122.006 76.2084 122.098 76.2748 122.174 76.3582C122.25 76.4416 122.307 76.5402 122.341 76.6474C122.376 76.7545 122.387 76.8678 122.375 76.9797V76.9797C122.349 77.2185 122.237 77.4396 122.06 77.6019C121.883 77.7642 121.653 77.8566 121.413 77.8617V77.8617Z" fill="white"/>
<path id="Path 25760" opacity="0.5" d="M131.829 82.6327H117.241C117.128 82.6343 117.017 82.6118 116.913 82.5669C116.81 82.522 116.718 82.4557 116.642 82.3722C116.566 82.2888 116.509 82.1903 116.475 82.0831C116.44 81.976 116.429 81.8627 116.441 81.7507V81.7507C116.467 81.512 116.579 81.2908 116.756 81.1285C116.933 80.9662 117.163 80.8739 117.403 80.8687H131.987C132.1 80.8672 132.211 80.8896 132.315 80.9345C132.418 80.9794 132.51 81.0458 132.586 81.1292C132.662 81.2126 132.719 81.3112 132.753 81.4183C132.788 81.5255 132.799 81.6388 132.787 81.7507V81.7507C132.761 81.9888 132.65 82.2094 132.474 82.3716C132.297 82.5338 132.068 82.6266 131.829 82.6327V82.6327Z" fill="white"/>
<path id="Path 25761" opacity="0.5" d="M125.652 87.4037H116.812C116.699 87.4053 116.588 87.3828 116.484 87.3379C116.381 87.293 116.289 87.2267 116.213 87.1432C116.137 87.0598 116.08 86.9613 116.046 86.8541C116.011 86.747 115.999 86.6337 116.012 86.5217V86.5217C116.038 86.2831 116.149 86.0619 116.326 85.8996C116.503 85.7373 116.733 85.6449 116.973 85.6397H125.813C125.926 85.6382 126.037 85.6606 126.141 85.7055C126.244 85.7504 126.336 85.8168 126.412 85.9002C126.488 85.9836 126.545 86.0822 126.579 86.1893C126.614 86.2965 126.625 86.4098 126.613 86.5217V86.5217C126.587 86.7603 126.475 86.9813 126.298 87.1436C126.122 87.3059 125.892 87.3983 125.652 87.4037V87.4037Z" fill="white"/>
<path id="Path 25762" opacity="0.5" d="M130.962 92.1737H116.378C116.265 92.1753 116.154 92.1529 116.05 92.108C115.947 92.063 115.855 91.9967 115.779 91.9133C115.703 91.8298 115.646 91.7313 115.612 91.6241C115.577 91.517 115.565 91.4037 115.578 91.2917V91.2917C115.604 91.053 115.716 90.8318 115.893 90.6695C116.07 90.5072 116.3 90.4149 116.54 90.4097H131.125C131.238 90.4082 131.349 90.4306 131.453 90.4755C131.556 90.5204 131.648 90.5868 131.724 90.6702C131.8 90.7536 131.857 90.8522 131.891 90.9594C131.926 91.0665 131.937 91.1798 131.925 91.2917V91.2917C131.899 91.5307 131.787 91.752 131.61 91.9143C131.433 92.0766 131.202 92.1688 130.962 92.1737V92.1737Z" fill="white"/>
<path id="Path 25763" opacity="0.5" d="M126.953 96.9447H115.944C115.831 96.9463 115.72 96.9239 115.616 96.879C115.513 96.834 115.421 96.7677 115.345 96.6843C115.269 96.6008 115.212 96.5023 115.178 96.3951C115.143 96.288 115.132 96.1747 115.144 96.0627V96.0627C115.17 95.824 115.282 95.6028 115.459 95.4405C115.636 95.2782 115.866 95.1859 116.106 95.1807H127.115C127.228 95.1792 127.339 95.2016 127.443 95.2465C127.546 95.2914 127.638 95.3578 127.714 95.4412C127.79 95.5247 127.847 95.6232 127.881 95.7304C127.916 95.8375 127.927 95.9508 127.915 96.0627V96.0627C127.889 96.3015 127.777 96.5227 127.6 96.685C127.423 96.8472 127.193 96.9396 126.953 96.9447V96.9447Z" fill="white"/>
<path id="Path 25764" opacity="0.5" d="M119.244 101.715H115.508C115.395 101.716 115.284 101.694 115.18 101.649C115.077 101.604 114.985 101.538 114.909 101.454C114.833 101.371 114.776 101.272 114.742 101.165C114.707 101.058 114.695 100.945 114.708 100.833V100.833C114.734 100.594 114.846 100.373 115.023 100.211C115.2 100.048 115.43 99.9559 115.67 99.9508H119.408C119.521 99.9492 119.632 99.9716 119.736 100.017C119.839 100.061 119.931 100.128 120.007 100.211C120.083 100.295 120.14 100.393 120.174 100.5C120.209 100.608 120.22 100.721 120.208 100.833C120.182 101.072 120.07 101.293 119.892 101.456C119.715 101.618 119.484 101.71 119.244 101.715V101.715Z" fill="white"/>
<path id="Path 25765" opacity="0.5" d="M129.66 106.487H115.076C114.963 106.488 114.852 106.466 114.748 106.421C114.645 106.376 114.553 106.31 114.477 106.226C114.401 106.143 114.344 106.044 114.31 105.937C114.275 105.83 114.263 105.717 114.276 105.605V105.605C114.302 105.366 114.414 105.145 114.591 104.983C114.768 104.82 114.998 104.728 115.238 104.723H129.822C129.935 104.721 130.046 104.744 130.149 104.789C130.253 104.833 130.345 104.9 130.421 104.983C130.497 105.067 130.554 105.165 130.588 105.272C130.623 105.38 130.634 105.493 130.622 105.605V105.605C130.596 105.843 130.484 106.065 130.307 106.227C130.13 106.389 129.9 106.482 129.66 106.487V106.487Z" fill="white"/>
<path id="Path 25766" opacity="0.5" d="M123.483 111.257H114.643C114.53 111.258 114.419 111.236 114.315 111.191C114.212 111.146 114.12 111.08 114.044 110.996C113.968 110.913 113.911 110.814 113.877 110.707C113.842 110.6 113.83 110.487 113.843 110.375V110.375C113.869 110.136 113.981 109.915 114.158 109.752C114.335 109.59 114.565 109.498 114.805 109.493H123.644C123.757 109.491 123.868 109.514 123.972 109.559C124.075 109.603 124.167 109.67 124.243 109.753C124.319 109.837 124.376 109.935 124.41 110.042C124.445 110.15 124.456 110.263 124.444 110.375V110.375C124.418 110.613 124.306 110.834 124.13 110.997C123.953 111.159 123.723 111.251 123.483 111.257V111.257Z" fill="white"/>
<path id="Path 25767" opacity="0.5" d="M128.792 116.028H114.208C114.095 116.029 113.984 116.007 113.88 115.962C113.777 115.917 113.685 115.851 113.609 115.767C113.533 115.684 113.476 115.585 113.442 115.478C113.407 115.371 113.395 115.258 113.408 115.146V115.146C113.434 114.907 113.546 114.686 113.723 114.524C113.9 114.361 114.13 114.269 114.37 114.264H128.952C129.065 114.262 129.176 114.285 129.28 114.33C129.383 114.374 129.475 114.441 129.551 114.524C129.627 114.608 129.684 114.706 129.718 114.813C129.753 114.921 129.764 115.034 129.752 115.146V115.146C129.726 115.384 129.614 115.605 129.438 115.767C129.261 115.93 129.032 116.022 128.792 116.028Z" fill="white"/>
</g>
</g>
<path id="Path 25768" d="M156.503 77.6987L153.337 74.9478L151.853 80.0117C151.853 80.0117 155.069 81.7558 156.183 80.1548L156.503 77.6987Z" fill="#FFC3BD"/>
<path id="Path 25769" d="M149.888 74.75L148.858 78.994L151.85 80.014L153.334 74.949L149.888 74.75Z" fill="#FFC3BD"/>
</g>
</g>
<g id="Group 26651">
<path id="Vector 480" d="M51.5 188.5V142L65.5 179L51.5 188.5Z" fill="url(#paint3_linear_93_4942)"/>
<path id="Vector 481" d="M51.5 188.5V142L39 183L51.5 188.5Z" fill="url(#paint4_linear_93_4942)"/>
<path id="Rectangle 5571" d="M51.5 183C51.5 181.343 52.8431 180 54.5 180V180C56.1569 180 57.5 181.343 57.5 183V191C57.5 192.657 56.1569 194 54.5 194V194C52.8431 194 51.5 192.657 51.5 191V183Z" fill="#B5D0FA"/>
</g>
<g id="Group 26654">
<path id="Vector 480_2" d="M267.731 190.192V158L277.423 183.615L267.731 190.192Z" fill="url(#paint5_linear_93_4942)"/>
<path id="Vector 481_2" d="M267.731 190.192V158L259.077 186.385L267.731 190.192Z" fill="url(#paint6_linear_93_4942)"/>
<path id="Rectangle 5571_2" d="M267.731 186.385C267.731 185.237 268.661 184.308 269.808 184.308V184.308C270.955 184.308 271.885 185.237 271.885 186.385V191.923C271.885 193.07 270.955 194 269.808 194V194C268.661 194 267.731 193.07 267.731 191.923V186.385Z" fill="#B5D0FA"/>
</g>
<g id="Group 26653">
<path id="Vector 480_3" d="M229.25 160.25V137L236.25 155.5L229.25 160.25Z" fill="url(#paint7_linear_93_4942)"/>
<path id="Vector 481_3" d="M229.25 160.25V137L223 157.5L229.25 160.25Z" fill="url(#paint8_linear_93_4942)"/>
<path id="Rectangle 5571_3" d="M229.25 157.501C229.25 156.672 229.922 156 230.75 156V156C231.579 156 232.25 156.672 232.25 157.501V161.501C232.25 162.329 231.579 163.001 230.75 163.001V163.001C229.922 163.001 229.25 162.329 229.25 161.501V157.501Z" fill="#B5D0FA"/>
</g>
</g>
<defs>
<linearGradient id="paint0_linear_93_4942" x1="118.5" y1="0" x2="118.5" y2="170" gradientUnits="userSpaceOnUse">
<stop stop-color="#407BFF" stop-opacity="0.1"/>
<stop offset="1" stop-color="#407BFF" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear_93_4942" x1="255" y1="52" x2="255" y2="164.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#407BFF" stop-opacity="0.1"/>
<stop offset="1" stop-color="#407BFF" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint2_linear_93_4942" x1="156" y1="143" x2="161.133" y2="239.988" gradientUnits="userSpaceOnUse">
<stop stop-color="#EDF2FF"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint3_linear_93_4942" x1="58.5" y1="142" x2="58.5" y2="188.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#C2D5F5"/>
<stop offset="1" stop-color="#B3CFFB"/>
</linearGradient>
<linearGradient id="paint4_linear_93_4942" x1="45.25" y1="142" x2="45.25" y2="188.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#DFEBFF"/>
<stop offset="1" stop-color="#D7E5FF"/>
</linearGradient>
<linearGradient id="paint5_linear_93_4942" x1="272.577" y1="158" x2="272.577" y2="190.192" gradientUnits="userSpaceOnUse">
<stop stop-color="#C2D5F5"/>
<stop offset="1" stop-color="#B3CFFB"/>
</linearGradient>
<linearGradient id="paint6_linear_93_4942" x1="263.404" y1="158" x2="263.404" y2="190.192" gradientUnits="userSpaceOnUse">
<stop stop-color="#DFEBFF"/>
<stop offset="1" stop-color="#D7E5FF"/>
</linearGradient>
<linearGradient id="paint7_linear_93_4942" x1="232.75" y1="137" x2="232.75" y2="160.25" gradientUnits="userSpaceOnUse">
<stop stop-color="#C2D5F5"/>
<stop offset="1" stop-color="#B3CFFB"/>
</linearGradient>
<linearGradient id="paint8_linear_93_4942" x1="226.125" y1="137" x2="226.125" y2="160.25" gradientUnits="userSpaceOnUse">
<stop stop-color="#DFEBFF"/>
<stop offset="1" stop-color="#D7E5FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -0,0 +1,84 @@
<svg width="312" height="298" viewBox="0 0 312 298" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="empty1">
<g id="empty2">
<path id="&#60;Path&#62;" d="M156 278C242.156 278 312 243.302 312 200.5C312 157.698 242.156 123 156 123C69.8436 123 0 157.698 0 200.5C0 243.302 69.8436 278 156 278Z" fill="url(#paint0_linear_93_5190)"/>
<g id="Group 26658">
<rect id="Rectangle 5574" x="82" y="20" width="106" height="137" rx="12" fill="url(#paint1_linear_93_5190)"/>
<rect id="Rectangle 5575" x="101" y="38" width="68" height="8" rx="4" fill="white"/>
<rect id="Rectangle 5576" x="101" y="58" width="44" height="8" rx="4" fill="white"/>
<rect id="Rectangle 5577" x="101" y="79" width="33" height="8" rx="4" fill="white"/>
</g>
<g id="Group 26651">
<path id="Vector 480" d="M51.5 168.5V122L65.5 159L51.5 168.5Z" fill="url(#paint2_linear_93_5190)"/>
<path id="Vector 481" d="M51.5 168.5V122L39 163L51.5 168.5Z" fill="url(#paint3_linear_93_5190)"/>
<path id="Rectangle 5571" d="M51.5 163C51.5 161.343 52.8431 160 54.5 160V160C56.1569 160 57.5 161.343 57.5 163V171C57.5 172.657 56.1569 174 54.5 174V174C52.8431 174 51.5 172.657 51.5 171V163Z" fill="#B5D0FA"/>
</g>
<g id="Group 26654">
<path id="Vector 480_2" d="M267.731 170.192V138L277.423 163.615L267.731 170.192Z" fill="url(#paint4_linear_93_5190)"/>
<path id="Vector 481_2" d="M267.731 170.192V138L259.077 166.385L267.731 170.192Z" fill="url(#paint5_linear_93_5190)"/>
<path id="Rectangle 5571_2" d="M267.731 166.385C267.731 165.237 268.661 164.308 269.808 164.308V164.308C270.955 164.308 271.885 165.237 271.885 166.385V171.923C271.885 173.07 270.955 174 269.808 174V174C268.661 174 267.731 173.07 267.731 171.923V166.385Z" fill="#B5D0FA"/>
</g>
<g id="Group 26653">
<path id="Vector 480_3" d="M243.25 142.25V119L250.25 137.5L243.25 142.25Z" fill="url(#paint6_linear_93_5190)"/>
<path id="Vector 481_3" d="M243.25 142.25V119L237 139.5L243.25 142.25Z" fill="url(#paint7_linear_93_5190)"/>
<path id="Rectangle 5571_3" d="M243.25 139.501C243.25 138.672 243.922 138 244.75 138V138C245.579 138 246.25 138.672 246.25 139.501V143.501C246.25 144.329 245.579 145.001 244.75 145.001V145.001C243.922 145.001 243.25 144.329 243.25 143.501V139.501Z" fill="#B5D0FA"/>
</g>
<g id="Group 26657">
<path id="Union" fill-rule="evenodd" clip-rule="evenodd" d="M202 53C197.029 53 193 57.0294 193 62C193 66.9706 197.029 71 202 71H213.536V76L219.078 71H232C236.971 71 241 66.9706 241 62C241 57.0294 236.971 53 232 53H202Z" fill="url(#paint8_linear_93_5190)"/>
<circle id="Ellipse 9" cx="209" cy="62" r="2" fill="white"/>
<circle id="Ellipse 10" cx="217" cy="62" r="2" fill="white"/>
<circle id="Ellipse 11" cx="225" cy="62" r="2" fill="white"/>
</g>
<g id="Group 26656">
<path id="Union_2" fill-rule="evenodd" clip-rule="evenodd" d="M212.522 143.111C218.421 136.415 222 127.625 222 118C222 97.0132 204.987 80 184 80C163.013 80 146 97.0132 146 118C146 138.987 163.013 156 184 156C189.947 156 195.574 154.634 200.586 152.199L212.07 166.826C214.628 170.084 219.343 170.651 222.6 168.093C225.858 165.535 226.426 160.821 223.868 157.563L212.522 143.111Z" fill="url(#paint9_linear_93_5190)"/>
<circle id="Ellipse 8" cx="184" cy="118" r="28" fill="url(#paint10_linear_93_5190)"/>
</g>
</g>
</g>
<defs>
<linearGradient id="paint0_linear_93_5190" x1="156" y1="123" x2="161.133" y2="219.988" gradientUnits="userSpaceOnUse">
<stop stop-color="#EDF2FF"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear_93_5190" x1="161.5" y1="148.5" x2="164.088" y2="-5.2649" gradientUnits="userSpaceOnUse">
<stop stop-color="#E0ECFF"/>
<stop offset="1" stop-color="#ADC6FF" stop-opacity="0.77"/>
</linearGradient>
<linearGradient id="paint2_linear_93_5190" x1="58.5" y1="122" x2="58.5" y2="168.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#C2D5F5"/>
<stop offset="1" stop-color="#B3CFFB"/>
</linearGradient>
<linearGradient id="paint3_linear_93_5190" x1="45.25" y1="122" x2="45.25" y2="168.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#DFEBFF"/>
<stop offset="1" stop-color="#D7E5FF"/>
</linearGradient>
<linearGradient id="paint4_linear_93_5190" x1="272.577" y1="138" x2="272.577" y2="170.192" gradientUnits="userSpaceOnUse">
<stop stop-color="#C2D5F5"/>
<stop offset="1" stop-color="#B3CFFB"/>
</linearGradient>
<linearGradient id="paint5_linear_93_5190" x1="263.404" y1="138" x2="263.404" y2="170.192" gradientUnits="userSpaceOnUse">
<stop stop-color="#DFEBFF"/>
<stop offset="1" stop-color="#D7E5FF"/>
</linearGradient>
<linearGradient id="paint6_linear_93_5190" x1="246.75" y1="119" x2="246.75" y2="142.25" gradientUnits="userSpaceOnUse">
<stop stop-color="#C2D5F5"/>
<stop offset="1" stop-color="#B3CFFB"/>
</linearGradient>
<linearGradient id="paint7_linear_93_5190" x1="240.125" y1="119" x2="240.125" y2="142.25" gradientUnits="userSpaceOnUse">
<stop stop-color="#DFEBFF"/>
<stop offset="1" stop-color="#D7E5FF"/>
</linearGradient>
<linearGradient id="paint8_linear_93_5190" x1="210.053" y1="54.2105" x2="214.24" y2="76.8962" gradientUnits="userSpaceOnUse">
<stop stop-color="#B7D1F9"/>
<stop offset="1" stop-color="#6E98F6"/>
</linearGradient>
<linearGradient id="paint9_linear_93_5190" x1="164.302" y1="91.1242" x2="163.855" y2="154.625" gradientUnits="userSpaceOnUse">
<stop stop-color="#B7D1F9"/>
<stop offset="1" stop-color="#6E98F6"/>
</linearGradient>
<linearGradient id="paint10_linear_93_5190" x1="175.895" y1="92.9474" x2="195.053" y2="142.684" gradientUnits="userSpaceOnUse">
<stop stop-color="#F4F8FF"/>
<stop offset="1" stop-color="#DDE7FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
src/assets/images/login.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 KiB

View File

@ -4,7 +4,7 @@
@use './sidebar.scss'; @use './sidebar.scss';
@use './btn.scss'; @use './btn.scss';
@use './ruoyi.scss'; @use './ruoyi.scss';
@use './reset.scss';
body { body {
height: 100%; height: 100%;
margin: 0; margin: 0;
@ -123,6 +123,11 @@ aside {
//main-container全局样式 //main-container全局样式
.app-container { .app-container {
padding: 20px; padding: 20px;
min-height: 100%;
}
.tab-page-content{
min-height: calc(100vh - 200px);
} }
.components-container { .components-container {

View File

@ -0,0 +1,180 @@
:root{
--app-header-height: 80px;
--app-nav-bj: #F4F8FF;
--el-text-color-primary: #1f2329;
}
#app .sidebar-container .el-menu,
#app .main-container{
background-color: var(--app-nav-bj) !important;
// background-color: transparent !important
}
#app .app-main{
border-radius: 16px;
box-sizing: border-box;
background-color: #fff;
}
#app .sidebar-container .svg-icon{
margin-right: 8px;
}
/*左侧菜单选中样式*/
#app .router-link-active{
position: relative;
}
#app .el-menu-item.is-active{
position: relative;
z-index: 1;
background: transparent !important;
}
#app .app-wrapper .el-menu-item.is-active:hover{
background-color: transparent!important;
}
#app .el-scrollbar .router-link-active::after{
background-color: #ecf2ff;
content: '';
position: absolute;
top: 7px;
left: 12px;
width: calc(100% - 24px);
height: 36px;
border-radius: 8px;
z-index: 0;
}
/* flex */
.flex {
display: flex;
}
.flex-center {
display: flex;
align-items: center;
justify-content: center;
}
.flex-between {
display: flex;
justify-content: space-between;
align-items: center;
}
.flex-wrap {
display: flex;
flex-wrap: wrap;
align-content: space-between;
}
.flex-direction-column {
display: flex;
flex-direction: column;
}
.align-center {
align-items: center;
}
.align-baseline {
align-items: baseline;
}
.justify-center {
justify-content: center;
}
.text-left {
text-align: left;
}
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
.vertical-middle {
vertical-align: middle;
}
.cursor,
.cursor-pointer {
cursor: pointer;
}
.mr-6{
margin-right: 6px;
}
.mr-8{
margin-right: 8px;
}
.mt-20{
margin-top: 20px;
}
.mb-20{
margin-bottom: 20px;
}
/* 重置tabs */
.res-el-tab {
--el-tabs-header-height: 60px;
height: 100%;
.el-tabs__nav-wrap:after {
height: 0 !important;
}
.el-tabs__active-bar {
height: 4px;
border-radius: 4px 4px 0 0;
}
}
/* 重置message */
.el-message-box{
padding: 24px;
--el-messagebox-font-size: 16px;
--el-messagebox-width: 475px;
.el-message-box__headerbtn{
right: 10px;
top: 15px;
.el-message-box__close {
font-size: 20px;
}
}
.el-message-box__header,
.el-message-box__btns{
padding: 0;
}
.el-message-box__content {
padding: 24px 0;
font-weight: 400;
}
.el-message-box__message{
color: var(--el-text-color-primary);
}
}
/* 体彩操作栏 */
.tc-view-time{
display: inline-block;
padding: 4px 10px;
line-height: 15px;
border-radius: 4px;
background: #fff3d9;
color: #c9993e;
font-size: 12px;
cursor: pointer;
width: 75px;
}
.tc-view-time-disabled{
background: #eaf2fe;
color: #c0c4cc;
cursor: not-allowed;
}
#app .has-active{
background: #f56c6c;
color: #fff;
}

View File

@ -78,7 +78,7 @@
.el-table__header-wrapper, .el-table__fixed-header-wrapper { .el-table__header-wrapper, .el-table__fixed-header-wrapper {
th { th {
word-break: break-word; word-break: break-word;
background-color: #f8f8f9 !important; background-color: var(--app-nav-bj) !important;
color: #515a6e; color: #515a6e;
height: 40px !important; height: 40px !important;
font-size: 13px; font-size: 13px;
@ -151,7 +151,7 @@
/** 表格更多操作下拉样式 */ /** 表格更多操作下拉样式 */
.el-table .el-dropdown-link { .el-table .el-dropdown-link {
cursor: pointer; cursor: pointer;
color: #409EFF; color: #3067EF;
margin-left: 10px; margin-left: 10px;
} }

View File

@ -24,8 +24,12 @@
left: 0; left: 0;
z-index: 1001; z-index: 1001;
overflow: hidden; overflow: hidden;
-webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35); // -webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1); // box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
background-color: var(--app-nav-bj) !important;
.sidebar-logo-container{
background-color: var(--app-nav-bj) !important;
}
// reset element-ui css // reset element-ui css
.horizontal-collapse-transition { .horizontal-collapse-transition {
@ -84,7 +88,7 @@
.sub-menu-title-noDropdown, .sub-menu-title-noDropdown,
.el-sub-menu__title { .el-sub-menu__title {
&:hover { &:hover {
background-color: rgba(0, 0, 0, 0.06) !important; background-color: var(--app-nav-bj) !important;
} }
} }
@ -97,7 +101,7 @@
min-width: vars.$base-sidebar-width !important; min-width: vars.$base-sidebar-width !important;
&:hover { &:hover {
background-color: rgba(0, 0, 0, 0.06) !important; background-color: var(--app-nav-bj) !important;
} }
} }
@ -213,7 +217,7 @@
.el-menu-item { .el-menu-item {
&:hover { &:hover {
// you can use $sub-menuHover // you can use $sub-menuHover
background-color: rgba(0, 0, 0, 0.06) !important; background-color: var(--app-nav-bj) !important;
} }
} }

View File

@ -10,7 +10,7 @@ $panGreen: #30B08F;
// 默认主题变量 // 默认主题变量
$menuText: #bfcbd9; $menuText: #bfcbd9;
$menuActiveText: #409eff; $menuActiveText: #3067EF;
$menuBg: #304156; $menuBg: #304156;
$menuHover: #263445; $menuHover: #263445;
@ -18,7 +18,7 @@ $menuHover: #263445;
$menuLightBg: #ffffff; $menuLightBg: #ffffff;
$menuLightHover: #f0f1f5; $menuLightHover: #f0f1f5;
$menuLightText: #303133; $menuLightText: #303133;
$menuLightActiveText: #409EFF; $menuLightActiveText: #3067EF;
// 基础变量 // 基础变量
$base-sidebar-width: 200px; $base-sidebar-width: 200px;
@ -32,7 +32,7 @@ $base-sub-menu-background: #1f2d3d;
$base-sub-menu-hover: #001528; $base-sub-menu-hover: #001528;
// 组件变量 // 组件变量
$--color-primary: #409EFF; $--color-primary: #3067EF;
$--color-success: #67C23A; $--color-success: #67C23A;
$--color-warning: #E6A23C; $--color-warning: #E6A23C;
$--color-danger: #F56C6C; $--color-danger: #F56C6C;

View File

@ -0,0 +1,31 @@
<template>
<MdEditor v-model="content" />
</template>
<script setup>
import { ref, computed } from 'vue';
import { MdEditor } from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';
//
const props = defineProps({
modelValue: {
type: String,
default: ''
}
});
//
const emit = defineEmits(['update:modelValue']);
//
const content = computed({
get() {
return props.modelValue;
},
set(value) {
emit('update:modelValue', value);
}
});
defineOptions({ name: 'MdEditorPreview' })
</script>

View File

@ -0,0 +1,19 @@
<template>
<div v-if="!$attrs.modelValue"></div>
<MdPreview v-else noIconfont noPrettier :codeFoldable="false" v-bind="$attrs"/>
</template>
<script setup>
import { MdPreview, config } from 'md-editor-v3'
//
import ZH_TW from '@vavt/cm-extension/dist/locale/zh-TW'
defineOptions({ name: 'MdPreview' })
config({
editorConfig: {
languageUserDefined: {
'zh-Hant': ZH_TW
}
},
})
</script>

152
src/enums/tc.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -38,7 +38,7 @@ function addIframe() {
<style lang="scss" scoped> <style lang="scss" scoped>
.app-main { .app-main {
/* 50= navbar 50 */ /* 50= navbar 50 */
min-height: calc(100vh - 50px); min-height: calc(100vh - var(--app-header-height));
width: 100%; width: 100%;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
@ -47,7 +47,7 @@ function addIframe() {
.fixed-header + .app-main { .fixed-header + .app-main {
overflow-y: auto; overflow-y: auto;
scrollbar-gutter: auto; scrollbar-gutter: auto;
height: calc(100vh - 50px); height: calc(100vh - var(--app-header-height));
min-height: 0px; min-height: 0px;
} }
@ -56,18 +56,18 @@ function addIframe() {
} }
.fixed-header + .app-main { .fixed-header + .app-main {
margin-top: 50px; margin-top: var(--app-header-height);
} }
.hasTagsView { .hasTagsView {
.app-main { .app-main {
/* 84 = navbar + tags-view = 50 + 34 */ /* 84 = navbar + tags-view = 50 + 34 */
min-height: calc(100vh - 84px); min-height: calc(100vh - var(--app-header-height) - 34px);
} }
.fixed-header + .app-main { .fixed-header + .app-main {
margin-top: 84px; // margin-top: var(--app-header-height) + 34px;
height: calc(100vh - 84px); height: calc(100vh - var(--app-header-height));
min-height: 0px; min-height: 0px;
} }
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="navbar"> <div class="navbar">
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> <hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<breadcrumb v-if="!settingsStore.topNav" id="breadcrumb-container" class="breadcrumb-container" /> <breadcrumb v-if="settingsStore.topNav" id="breadcrumb-container" class="breadcrumb-container" />
<top-nav v-if="settingsStore.topNav" id="topmenu-container" class="topmenu-container" /> <top-nav v-if="settingsStore.topNav" id="topmenu-container" class="topmenu-container" />
<div class="right-menu"> <div class="right-menu">
@ -102,14 +102,14 @@ function toggleTheme() {
<style lang='scss' scoped> <style lang='scss' scoped>
.navbar { .navbar {
height: 50px; height: var(--app-header-height);
overflow: hidden; overflow: hidden;
position: relative; position: relative;
background: var(--navbar-bg); background: var(--app-nav-bj);
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); // box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.hamburger-container { .hamburger-container {
line-height: 46px; line-height: 60px;
height: 100%; height: 100%;
float: left; float: left;
cursor: pointer; cursor: pointer;
@ -117,7 +117,7 @@ function toggleTheme() {
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
&:hover { &:hover {
background: rgba(0, 0, 0, 0.025); background-color: var(--app-nav-bj);
} }
} }
@ -158,7 +158,7 @@ function toggleTheme() {
transition: background 0.3s; transition: background 0.3s;
&:hover { &:hover {
background: rgba(0, 0, 0, 0.025); background-color: var(--app-nav-bj);
} }
} }
@ -181,7 +181,8 @@ function toggleTheme() {
padding-right: 0px; padding-right: 0px;
.avatar-wrapper { .avatar-wrapper {
margin-top: 10px; margin-top: 20px;
margin-right: 10px;
right: 8px; right: 8px;
position: relative; position: relative;

View File

@ -106,7 +106,7 @@ const showSettings = ref(false)
const theme = ref(settingsStore.theme) const theme = ref(settingsStore.theme)
const sideTheme = ref(settingsStore.sideTheme) const sideTheme = ref(settingsStore.sideTheme)
const storeSettings = computed(() => settingsStore) const storeSettings = computed(() => settingsStore)
const predefineColors = ref(["#409EFF", "#ff4500", "#ff8c00", "#ffd700", "#90ee90", "#00ced1", "#1e90ff", "#c71585"]) const predefineColors = ref(["#3067EF", "#ff4500", "#ff8c00", "#ffd700", "#90ee90", "#00ced1", "#1e90ff", "#c71585"])
/** 是否需要topnav */ /** 是否需要topnav */
function topNavChange(val) { function topNavChange(val) {

View File

@ -59,8 +59,8 @@ const getLogoTextColor = computed(() => {
.sidebar-logo-container { .sidebar-logo-container {
position: relative; position: relative;
width: 100%; width: 100%;
height: 50px; height: 65px;
line-height: 50px; line-height: 65px;
background: v-bind(getLogoBackground); background: v-bind(getLogoBackground);
text-align: center; text-align: center;
overflow: hidden; overflow: hidden;

View File

@ -91,7 +91,7 @@ const activeMenu = computed(() => {
color: v-bind(getMenuTextColor); color: v-bind(getMenuTextColor);
&.is-active { &.is-active {
color: var(--menu-active-text, #409eff); color: var(--menu-active-text, #3067EF);
background-color: var(--menu-hover, rgba(0, 0, 0, 0.06)) !important; background-color: var(--menu-hover, rgba(0, 0, 0, 0.06)) !important;
} }
} }

View File

@ -5,7 +5,7 @@
<div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container"> <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
<div :class="{ 'fixed-header': fixedHeader }"> <div :class="{ 'fixed-header': fixedHeader }">
<navbar @setLayout="setLayout" /> <navbar @setLayout="setLayout" />
<tags-view v-if="needTagsView" /> <tags-view v-if="needTagsView" v-show="false"/>
</div> </div>
<app-main /> <app-main />
<settings ref="settingRef" /> <settings ref="settingRef" />

View File

@ -9,6 +9,10 @@ import locale from 'element-plus/es/locale/lang/zh-cn'
import '@/assets/styles/index.scss' // global css import '@/assets/styles/index.scss' // global css
import LzUiLib from '@lzui/lzui-lib'
import '@lzui/lzui-lib/style.css'
import App from './App' import App from './App'
import store from './store' import store from './store'
import router from './router' import router from './router'
@ -47,6 +51,43 @@ import DictTag from '@/components/DictTag'
//版本更新检查 //版本更新检查
import '@/utils/cachedBuildTime' import '@/utils/cachedBuildTime'
// md 编辑器
import { config } from 'md-editor-v3'
import 'md-editor-v3/lib/style.css';
import screenfull from 'screenfull'
import katex from 'katex'
import 'katex/dist/katex.min.css'
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css'
import mermaid from 'mermaid'
import highlight from 'highlight.js'
import 'highlight.js/styles/atom-one-dark.css'
config({
editorExtensions: {
highlight: {
instance: highlight
},
screenfull: {
instance: screenfull
},
katex: {
instance: katex
},
cropper: {
instance: Cropper
},
mermaid: {
instance: mermaid
}
}
})
const app = createApp(App) const app = createApp(App)
// 全局方法挂载 // 全局方法挂载
@ -75,6 +116,8 @@ app.use(plugins)
app.use(elementIcons) app.use(elementIcons)
app.component('svg-icon', SvgIcon) app.component('svg-icon', SvgIcon)
app.use(LzUiLib)
directive(app) directive(app)
// 使用element-plus 并且设置全局的大小 // 使用element-plus 并且设置全局的大小

View File

@ -12,13 +12,18 @@ export default {
/** /**
* 是否系统布局配置 * 是否系统布局配置
*/ */
showSettings: true, showSettings: false,
/** /**
* 是否显示顶部导航 * 是否显示顶部导航
*/ */
topNav: false, topNav: false,
/**
* 是否显示汉堡菜单
*/
showHamburger: true,
/** /**
* 是否显示 tagsView * 是否显示 tagsView
*/ */
@ -32,7 +37,7 @@ export default {
/** /**
* 是否固定头部 * 是否固定头部
*/ */
fixedHeader: false, fixedHeader: true,
/** /**
* 是否显示logo * 是否显示logo
@ -52,6 +57,6 @@ export default {
/** /**
* 底部版权文本内容 * 底部版权文本内容
*/ */
footerContent: 'Copyright © 2025 北京数维无穹科技有限公司' footerContent: '' //'Copyright © 2025 北京数维无穹科技有限公司'
} }

View File

@ -35,7 +35,24 @@ const usePermissionStore = defineStore(
generateRoutes(roles) { generateRoutes(roles) {
return new Promise(resolve => { return new Promise(resolve => {
// 向后端请求路由数据 // 向后端请求路由数据
getRouters().then(res => { getRouters().then(r => {
const res = r
// 查找 Tc 菜单项目
// const tcMenu = res.data.find(item => item.name === 'Tc')
// if (tcMenu && tcMenu.children) {
// tcMenu.children.forEach((child) => {
// switch (child.name) {
// case 'EventAnalysisReport/detail':
// child.meta = { ...child.meta, activeMenu: '/tc/eventAnalysisReport/index' }
// break
// case 'VideoScript/detail':
// child.meta = { ...child.meta, activeMenu: '/tc/videoScript/index' }
// break
// }
// })
// }
// console.log('res', res.data)
const sdata = JSON.parse(JSON.stringify(res.data)) const sdata = JSON.parse(JSON.stringify(res.data))
const rdata = JSON.parse(JSON.stringify(res.data)) const rdata = JSON.parse(JSON.stringify(res.data))
const defaultData = JSON.parse(JSON.stringify(res.data)) const defaultData = JSON.parse(JSON.stringify(res.data))

View File

@ -2,7 +2,7 @@ import defaultSettings from '@/settings'
import { useDark, useToggle } from '@vueuse/core' import { useDark, useToggle } from '@vueuse/core'
import { useDynamicTitle } from '@/utils/dynamicTitle' import { useDynamicTitle } from '@/utils/dynamicTitle'
const isDark = useDark() const isDark = ref(false) // useDark()
const toggleDark = useToggle(isDark) const toggleDark = useToggle(isDark)
const { sideTheme, showSettings, topNav, tagsView, tagsIcon, fixedHeader, sidebarLogo, dynamicTitle, footerVisible, footerContent } = defaultSettings const { sideTheme, showSettings, topNav, tagsView, tagsIcon, fixedHeader, sidebarLogo, dynamicTitle, footerVisible, footerContent } = defaultSettings
@ -14,7 +14,7 @@ const useSettingsStore = defineStore(
{ {
state: () => ({ state: () => ({
title: '', title: '',
theme: storageSetting.theme || '#409EFF', theme: storageSetting.theme || '#3067EF',
sideTheme: storageSetting.sideTheme || sideTheme, sideTheme: storageSetting.sideTheme || sideTheme,
showSettings: showSettings, showSettings: showSettings,
topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav, topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,

View File

@ -84,7 +84,7 @@ service.interceptors.response.use(res => {
if (code === 401) { if (code === 401) {
if (!isRelogin.show) { if (!isRelogin.show) {
isRelogin.show = true isRelogin.show = true
ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => { ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning', closeOnClickModal: false }).then(() => {
isRelogin.show = false isRelogin.show = false
useUserStore().logOut().then(() => { useUserStore().logOut().then(() => {
location.href = '/' location.href = '/'
@ -111,7 +111,7 @@ service.interceptors.response.use(res => {
console.log('err' + error) console.log('err' + error)
let { message } = error let { message } = error
if (message == "Network Error") { if (message == "Network Error") {
message = "后端接口连接异常" message = "网络连接异常"
} else if (message.includes("timeout")) { } else if (message.includes("timeout")) {
message = "系统接口请求超时" message = "系统接口请求超时"
} else if (message.includes("Request failed with status code")) { } else if (message.includes("Request failed with status code")) {

View File

@ -1,3 +1,5 @@
import { MatchResults } from '@/enums/tc'
export function jumpLink(mid, matchType) { export function jumpLink(mid, matchType) {
/** matchType 1足球 2篮球 */ /** matchType 1足球 2篮球 */
const url = matchType === 1 ? const url = matchType === 1 ?
@ -5,3 +7,40 @@ export function jumpLink(mid, matchType) {
`https://www.sporttery.cn/jc/lqdz/index.html?showType=3&mid=${mid}` `https://www.sporttery.cn/jc/lqdz/index.html?showType=3&mid=${mid}`
window.open(url) window.open(url)
} }
export function processMatchResults(data) {
// 获取MatchResults的key值并按字母顺序排序
const sortedKeys = Object.keys(MatchResults)
// 创建一个新数组,用于存储处理后的结果
const result = [];
// 遍历排序后的key值
for (const key of sortedKeys) {
// 在原始数据中查找匹配的code
const item = data.find(item => item.code === key);
// 如果找到匹配的item则添加codeName属性并添加到结果数组中
if (item) {
result.push({
...item,
codeName: MatchResults[key]
});
}
}
return result;
}
export function processMatchResults2(arr) {
const res = arr.map(item => ({
...item,
codeName: MatchResults[item.code]
}));
return res
}

6
src/utils/timer.js Normal file
View File

@ -0,0 +1,6 @@
import dayjs from 'dayjs'
export function timerToStr(t = null, f = 'YYYY-MM-DD-HH-mm-ss') {
return dayjs(t).format(f)
}

View File

@ -59,7 +59,7 @@
</el-form> </el-form>
<!-- 底部 --> <!-- 底部 -->
<div class="el-login-footer"> <div class="el-login-footer">
<span>Copyright ©2025 北京数维无穹科技有限公司</span> <!-- <span>Copyright ©2025 北京数维无穹科技有限公司</span> -->
</div> </div>
</div> </div>
</template> </template>
@ -77,9 +77,9 @@ const router = useRouter()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const loginForm = ref({ const loginForm = ref({
username: "admin", username: "",
password: "admin123", password: "",
rememberMe: false, rememberMe: true,
code: "", code: "",
uuid: "" uuid: ""
}) })
@ -169,7 +169,7 @@ getCookie()
justify-content: center; justify-content: center;
align-items: center; align-items: center;
height: 100%; height: 100%;
background-image: url("../assets/images/login-background.jpg"); background-image: url("../assets/images/login.png");
background-size: cover; background-size: cover;
} }
.title { .title {

View File

@ -0,0 +1,391 @@
<template>
<div class="app-container">
<!-- 搜索区域 -->
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="80px">
<el-form-item label="模型名称" prop="useCase">
<el-input v-model="queryParams.useCase" placeholder="请输入名称" clearable style="width: 240px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery" :loading="loading">查询</el-button>
<el-button icon="Refresh" @click="resetQuery" :loading="loading">重置</el-button>
</el-form-item>
</el-form>
<!--loading-->
<div v-if="loading" v-loading="loading" class="loading-page" element-loading-text="正在加载..."
style="width: 100%; height: calc(100vh - 250px)"></div>
<div v-else-if="pageList.length && !loading">
<!-- 表格数据 -->
<el-table v-loading="loading" :data="pageList">
<el-table-column label="模型名称" prop="useCase" />
<el-table-column label="模型类型" prop="modelType" />
<el-table-column label="模型" prop="modelName" />
<el-table-column label="API密钥" prop="apiKey" :show-overflow-tooltip="true" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="openDialog('edit', scope.row)">编辑</el-button>
<el-button link type="primary" icon="Edit" @click="openDialogHistory(scope.row)">模型历史</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页区域 -->
<pagination :show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
</div>
<lz-page-empty v-else-if="!loading" :type="'2'">
<lz-svg-icon icon-class="empty2" style="font-size: 312px;" />
</lz-page-empty>
<!-- 修改对话框 -->
<el-dialog :title="dialogTitle" v-model="dialogOpen" width="980px" append-to-body :close-on-click-modal="false"
@close="cancel">
<el-form :model="dialogForm" :rules="dialogRules" ref="configModelsRef" label-width="110px" class="config-form" :disabled="dialogIsView">
<el-row>
<el-col :span="12">
<el-form-item label="模型名称" prop="useCase">
<el-input v-model="dialogForm.useCase" disabled="true" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="模型" prop="modelId">
<el-select v-model="dialogForm.modelId" placeholder="请选择模型" @change="handleModelChange">
<el-option
v-for="item in modelsOptions"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="Api Url" prop="apiUrl">
<el-input v-model="dialogForm.apiUrl" placeholder="请输入Api Url"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Api密钥" prop="apiKey">
<el-input v-model="dialogForm.apiKey" placeholder="请输入Api密钥"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="Top-K" prop="topK">
<el-slider :step="1" :min="0" :max="100" v-model="dialogForm.topK" show-input />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Top-P" prop="topP">
<el-slider :step="0.01" :min="0" :max="1" v-model="dialogForm.topP" show-input />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="最大回复长度" prop="temperature">
<el-slider :step="1" :min="1" :max="163840" v-model="dialogForm.maxTokens" show-input />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="温度" prop="temperature">
<el-slider :step="0.01" :min="0" :max="1" v-model="dialogForm.temperature" show-input />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="提示词" prop="modelPrompt">
<MdEditorPreview v-model="dialogForm.modelPrompt" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm" v-if="!dialogIsView"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!--模型历史列表-->
<el-dialog :title="dialogHistoryTitle" v-model="dialogHistoryOpen" width="980px" append-to-body :close-on-click-modal="false"
@close="cancel">
<el-table v-loading="dialogLoading" :data="dialogPageList">
<el-table-column label="模型名称" prop="useCase" />
<el-table-column label="模型类型" prop="modelType" />
<el-table-column label="更新时间" prop="updateTime" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="view" @click="openDialog('view', scope.row)">查看</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页区域 -->
<pagination
:show="dialogTotal > 0"
:total="dialogTotal"
v-model:page="dialogQueryParams.pageNum"
v-model:limit="dialogQueryParams.pageSize"
@pagination="getDialogList"
/>
<template #footer>
<div class="dialog-footer">
<el-button @click="cancelHistory"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="configModels">
import { modelConfigList, modelConfigUpdate, modelConfigHistory } from "@/api/tc/model"
import { getDicts } from "@/api/system/dict/data"
import MdEditorPreview from "@/components/Markdown/MdEditorPreview"
import { ref } from "vue"
const { proxy } = getCurrentInstance()
const pageList = ref([])
const loading = ref(false)
const showSearch = ref(true)
const total = ref(0)
const modelsOptions = ref([])
/** 对话框列表数据 */
const dialogHistoryTitle = ref('模型历史列表')
const dialogHistoryOpen = ref(false)
const dialogPageList = ref([])
const dialogTotal = ref(0)
const dialogLoading = ref(false)
const dialogQueryParams = ref({
pageNum: 1,
pageSize: 10,
})
/** 配置模型表单引用 */
const configModelsRef = ref(null)
const dialogOpen = ref(false)
const dialogTitle = ref('新增')
const dialogIsView = ref(false)
const dialogForm = ref({
useCase: '',
modelId: '',
modelName: '',
modelPrompt: '',
apiKey: '',
apiUrl:'',
temperature:'',
topK:'',
topP:'',
maxTokens:'',
})
const dialogRules = ref({
modelId: [{ required: true, message: '请选择模型', trigger: ['change'] }],
modelPrompt: [{ required: true, message: '请输入提示词', trigger: ['blur'] }],
apiKey: [{ required: true, message: '请输入API密钥', trigger: ['blur'] }],
apiUrl: [{ required: true, message: '请输入API Url', trigger: ['blur'] }],
temperature: [{ required: true, message: '请输入温度', trigger: ['blur'] }],
topK: [{ required: true, message: '请输入Top-K', trigger: ['blur'] }],
topP: [{ required: true, message: '请输入Top-P', trigger: ['blur'] }],
maxTokens: [{ required: true, message: '请输入最大回复长度', trigger: ['blur'] }],
})
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
useCase: undefined,
},
rules: {},
})
const { queryParams } = toRefs(data)
/** 查询模型列表 */
function getModelList() {
getDicts('model_name').then(res => {
modelsOptions.value = res.data
})
}
/** 模型选择 */
function handleModelChange() {
dialogForm.value.modelName = modelsOptions.value.find(item => item.dictValue === dialogForm.value.modelId)?.dictLabel || ''
}
/** 提交表单 */
function submitForm() {
//
configModelsRef.value.validate((valid) => {
if (valid) {
const data = { ...dialogForm.value }; //
console.log(data);
const params = {
id: data.id,
modelId: data.modelId,
modelName: data.modelName,
modelPrompt: data.modelPrompt,
apiKey: data.apiKey,
apiUrl: data.apiUrl,
temperature: data.temperature,
topK: data.topK,
topP: data.topP,
maxTokens: data.maxTokens,
}
//
modelConfigUpdate(params).then(response => {
proxy.$message.success(response.msg);
getList(); //
}).finally(() => {
dialogOpen.value = false; //
reset()
});
} else {
console.log('表单验证失败');
}
});
}
/** 取消按钮 */
function cancel() {
dialogOpen.value = false
reset()
}
/** 重置操作表单 */
function reset() {
dialogForm.value = {
useCase: '',
modelId: '',
modelName: '',
modelPrompt: '',
apiKey: '',
}
proxy.resetForm("configModelsRef")
}
/** 打开新增/编辑弹窗 */
function openDialog(type = 'add', row = {}) {
dialogIsView.value = false
if (modelsOptions.value.length === 0) {
getModelList()
}
if (type === 'add') {
dialogTitle.value = '新增'
} else if (type === 'edit') {
dialogTitle.value = '编辑'
dialogForm.value = JSON.parse(JSON.stringify(row))
} else if (type === 'view') {
dialogTitle.value = '查看'
dialogForm.value = JSON.parse(JSON.stringify(row))
dialogIsView.value = true
}
dialogOpen.value = true
}
/** 打开模型历史弹窗 */
function openDialogHistory(row = {}) {
dialogHistoryOpen.value = true
getDialogList(row.modelType)
}
/** 模型历史列表 */
function cancelHistory() {
dialogHistoryOpen.value = false
}
/** 分页查询模型历史列表 */
function getDialogList(modelType) {
const data = { modelType }
modelConfigHistory(data).then(response => {
const res = response.rows;
dialogPageList.value = res
dialogTotal.value = response.total
}).finally(() => {
dialogLoading.value = false
})
}
/** 查询列表 */
function getList() {
loading.value = true
const data = { ...queryParams.value }
modelConfigList(data).then(response => {
const res = response.rows;
pageList.value = res
total.value = response.total
}).finally(() => {
loading.value = false
})
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
}
onMounted(() => {
//
getModelList()
//
getList()
})
</script>
<style lang="scss" scoped>
.config-form{
.el-slider {
--el-slider-button-size: 14px;
--el-slider-height: 4px;
}
.el-slider__button {
border: solid 1px #bbbfc4;
&.hover {
border: solid 2px #5E8BFB;
}
}
.el-slider__runway.show-input {
margin-right: 12px;
}
.el-slider__input {
width: 72px;
}
:deep(.el-slider__input){
width: 130px;
margin-left: 30px;
}
:deep(.el-slider__bar) {
height: 6px;
background-color: #5E8BFB;
}
:deep(.el-slider__runway) {
background: #E8E8E8;
height: 6px;
}
:deep(.el-slider__button.hover){
border: 4px solid #3067EF;
transform: scale(1.3);
}
:deep(.el-input__wrapper.is-focus){
box-shadow: 0 0 0 1px var(--el-input-border-color, var(--el-border-color)) inset;
}
}
</style>

View File

@ -0,0 +1,128 @@
<template>
<div class="had">
<div class="had-content flex" v-for="(item,index) in enumsPredictionList" :key="item.value">
<div class="had-content-item-left">
{{ item.label || '' }}
</div>
<div class="had-content-table flex">
<div :class="['had-content-table-item', {'is-active': isActiveClass(item, data, '1')}]" @click="handleClick(item, data, '1')">
</div>
<div v-if="item.value === 'asianHandicapFlag'" :class="['had-content-table-item', {'is-active': isActiveClass(item, data, '0.5')}]" @click="handleClick(item, data, '0.5')">
红半
</div>
<div :class="['had-content-table-item', {'is-active-black': isActiveClass(item, data, '-1')}]" @click="handleClick(item, data, '-1')">
</div>
<div v-if="item.value === 'asianHandicapFlag'" :class="['had-content-table-item', {'is-active-black': isActiveClass(item, data, '-0.5')}]" @click="handleClick(item, data, '-0.5')">
黑半
</div>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
//
const props = defineProps({
data: {
type: Object,
default: () => ({})
},
type: {
type: String,
default: 'view' // edit:,view:
}
});
//
const { data } = toRefs(props);
const enumsPredictionList = [
{ label: '胜平负:', value: 'resultFlag'},
{ label: '让分胜平负:', value: 'hhadResultFlag'},
{ label: '比分:', value: 'scoreResultFlag' },
{ label: '进球数:', value: 'goalsResultFlag' },
{ label: '半全场:', value: 'halfFullResultFlag' },
{ label: '亚盘:', value: 'asianHandicapFlag' },
];
function isActiveClass (item, data, activeValue) {
// console.log(item, data, activeValue)
if (!data || !data[item.value]) return false;
return data[item.value] === activeValue;
}
function handleClick (item,data, value) {
if(props.type === 'view') return;
data[item.value] = value
}
function getFormData () {
const formData = props.data
return formData;
}
onMounted(() => {
// if(data.value.reportDetail && data.value.matchSpfDetails){
// const reportDetail = data.value.reportDetail;
// data.value.matchSpfDetails.forEach(el => {
// if(el.goalType === 'HAD') {
// el.isActive = reportDetail.hadFlag || '';
// }
// if(el.goalType === 'HHAD') {
// el.isActive = reportDetail.hhadFlag || '';
// }
// });
// }
})
defineExpose({
getFormData
});
</script>
<style lang="scss" scoped>
.had-content-item-left{
width: 120px;
text-align: right;
line-height: 45px;
padding-right: 6px;
}
.had-content-table{
display: flex;
justify-content: space-between;
width: 100%;
}
.had-content-table-item {
padding: 12px;
// border: 1px solid #ccc;
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
width: 50%;
cursor: pointer;
display: flex;
justify-content: space-between;
background-color: #F4F8FF;
}
.had-content-table .had-content-table-item:last-child {
border-right: 1px solid #ccc;
}
.had-content:last-child .had-content-table-item {
border-bottom: 1px solid #ccc;
}
.is-active {
background-color: #f56c6c;
color: #fff;
}
.is-active-black {
background-color: #333;
color: #fff;
}
</style>

View File

@ -0,0 +1,124 @@
<template>
<div class="had">
<div class="had-content flex" v-for="(item,index) in enumsPredictionList" :key="item.value">
<div class="had-content-item-left">
{{ item.label || '' }}
</div>
<div class="had-content-table flex">
<div :class="['had-content-table-item', {'is-active': isActiveClass(item, data, '1')}]" @click="handleClick(item, data, '1')">
</div>
<div v-if="item.value === 'asianHandicapFlag'" :class="['had-content-table-item', {'is-active': isActiveClass(item, data, '0.5')}]" @click="handleClick(item, data, '0.5')">
红半
</div>
<div :class="['had-content-table-item', {'is-active-black': isActiveClass(item, data, '-1')}]" @click="handleClick(item, data, '-1')">
</div>
<div v-if="item.value === 'asianHandicapFlag'" :class="['had-content-table-item', {'is-active-black': isActiveClass(item, data, '-0.5')}]" @click="handleClick(item, data, '-0.5')">
黑半
</div>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
//
const props = defineProps({
data: {
type: Object,
default: () => ({})
},
type: {
type: String,
default: 'view' // edit:,view:
}
});
//
const { data } = toRefs(props);
const enumsPredictionList = [
{ label: '进球数:', value: 'goalsResultFlag' },
{ label: '亚盘:', value: 'asianHandicapFlag' },
];
function isActiveClass (item, data, activeValue) {
// console.log(item, data, activeValue)
if (!data || !data[item.value]) return false;
return data[item.value] === activeValue;
}
function handleClick (item,data, value) {
if(props.type === 'view') return;
data[item.value] = value
}
function getFormData () {
const formData = props.data
return formData;
}
onMounted(() => {
// if(data.value.reportDetail && data.value.matchSpfDetails){
// const reportDetail = data.value.reportDetail;
// data.value.matchSpfDetails.forEach(el => {
// if(el.goalType === 'HAD') {
// el.isActive = reportDetail.hadFlag || '';
// }
// if(el.goalType === 'HHAD') {
// el.isActive = reportDetail.hhadFlag || '';
// }
// });
// }
})
defineExpose({
getFormData
});
</script>
<style lang="scss" scoped>
.had-content-item-left{
width: 120px;
text-align: right;
line-height: 45px;
padding-right: 6px;
}
.had-content-table{
display: flex;
justify-content: space-between;
width: 100%;
}
.had-content-table-item {
padding: 12px;
// border: 1px solid #ccc;
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
width: 50%;
cursor: pointer;
display: flex;
justify-content: space-between;
background-color: #F4F8FF;
}
.had-content-table .had-content-table-item:last-child {
border-right: 1px solid #ccc;
}
.had-content:last-child .had-content-table-item {
border-bottom: 1px solid #ccc;
}
.is-active {
background-color: #f56c6c;
color: #fff;
}
.is-active-black {
background-color: #333;
color: #fff;
}
</style>

View File

@ -0,0 +1,550 @@
<template>
<div class="tab-page-content">
<!-- 搜索区域 -->
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="80px">
<el-form-item label="赛事编号" prop="matchNumStr">
<el-input v-model="queryParams.matchNumStr" placeholder="请输入赛事编号" clearable style="width: 240px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="联赛类型" prop="leagueAbbName">
<el-select v-model="queryParams.leagueAbbName" @change="handleQuery" style="width: 240px" clearable placeholder="请选择联赛类型">
<el-option
v-for="item in dataScopeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="标记状态" prop="flagStatus">
<el-select v-model="queryParams.flagStatus" @change="handleQuery" style="width: 240px" clearable placeholder="请选择标记状态">
<el-option
v-for="item in flagStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="时间">
<el-date-picker v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-"
start-placeholder="开始日期" end-placeholder="结束日期" style="width: 240px"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery" :loading="loading">查询</el-button>
<el-button icon="Refresh" @click="resetQuery" :loading="loading">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row>
<!--loading-->
<div
v-if="loading"
v-loading="loading"
class="loading-page"
element-loading-text="正在加载..."
style="width: 100%; height: calc(100vh - 250px)"
></div>
<div v-else-if="pageList.length && !loading">
<!-- 表格数据 -->
<el-table v-loading="loading" :data="pageList">
<el-table-column label="赛事编号" prop="matchNumStr" />
<el-table-column label="联赛" prop="leagueAllName" :show-overflow-tooltip="true" />
<el-table-column label="主队" prop="homeTeamAllName" :show-overflow-tooltip="true" />
<el-table-column label="客队" prop="awayTeamAbbName" />
<el-table-column label="比赛开始时间" align="center" prop="matchDateTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.matchDateTime) }}</span>
</template>
</el-table-column>
<el-table-column label="赛果" prop="matchId">
<template #default="scope">
<el-popover placement="bottom" :width="360">
<template #reference>
<el-button link type="primary" @dblclick="handleJumpLink(scope.row)">查看</el-button>
</template>
<template #default>
<div>
<el-table border :data="scope.row.matchResults">
<el-table-column label="游戏" prop="matchNumStr">
<template #default="item">
{{ item.row.codeName }}
</template>
</el-table-column>
<el-table-column label="开赛结果" prop="reportSatus">
<template #default="item">
<el-tag type="error">{{ item.row.combinationDesc }}</el-tag>
</template>
</el-table-column>
<el-table-column label="奖金" prop="matchNumStr">
<template #default="item">
{{ item.row.odds }}
</template>
</el-table-column>
</el-table>
</div>
</template>
</el-popover>
</template>
</el-table-column>
<el-table-column label="AI预测" prop="matchId">
<template #default="scope">
<el-popover placement="bottom" :width="360">
<template #reference>
<el-button link type="primary">查看</el-button>
</template>
<template #default>
<div style="padding: 8px;">
<el-radio-group v-model="activeName" style="margin-bottom: 10px">
<el-radio-button value="FINYX_F">finyx-AI</el-radio-button>
<el-radio-button value="D3_F">D3-index</el-radio-button>
</el-radio-group>
<div v-show="activeName === 'FINYX_F'">
<el-table border :data="scope.row.farmatReportResults['FINYX_F']" :show-header="false">
<el-table-column>
<template #default="item">
{{ item.row.lable }}
</template>
</el-table-column>
<el-table-column>
<template #default="item">
{{ item.row.value || '-' }}
</template>
</el-table-column>
</el-table>
</div>
<div v-show="activeName === 'D3_F'">
<el-table border :data="scope.row.farmatReportResults['D3_F']" :show-header="false">
<el-table-column>
<template #default="item">
{{ item.row.lable }}
</template>
</el-table-column>
<el-table-column>
<template #default="item">
{{ item.row.value || '-' }}
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
</el-popover>
</template>
</el-table-column>
<el-table-column label="Finyx预测结果" width="300" align="center">
<el-table-column label="常" width="50" align="center">
<template #default="scope">
<span :class="['icon-d3', tableColumnActive(scope.row, 'FINYX_F', 'resultFlag')]"></span>
</template>
</el-table-column>
<el-table-column label="让" width="50" align="center">
<template #default="scope">
<span :class="['icon-d3', tableColumnActive(scope.row, 'FINYX_F', 'hhadResultFlag')]"></span>
</template>
</el-table-column>
<el-table-column label="分" width="50" align="center">
<template #default="scope">
<span :class="['icon-d3', tableColumnActive(scope.row, 'FINYX_F', 'scoreResultFlag')]"></span>
</template>
</el-table-column>
<el-table-column label="总" width="50" align="center">
<template #default="scope">
<span :class="['icon-d3', tableColumnActive(scope.row, 'FINYX_F', 'goalsResultFlag')]"></span>
</template>
</el-table-column>
<el-table-column label="半" width="50" align="center">
<template #default="scope">
<span :class="['icon-d3', tableColumnActive(scope.row, 'FINYX_F', 'halfFullResultFlag')]"></span>
</template>
</el-table-column>
<el-table-column label="亚" width="50" align="center">
<template #default="scope">
<span :class="['icon-d3', tableColumnActive(scope.row, 'FINYX_F', 'asianHandicapFlag')]"></span>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="结果标记" align="center" class-name="small-padding fixed-width" width="200">
<template #default="scope">
<el-button
v-show="showBtn(scope.row, 'FINYX_F')"
link
type="primary"
icon="Edit"
@click="openDialog(scope.row, 'FINYX_F')"
:class="[matchIdType.id === scope.row.matchId && matchIdType.type === 'FINYX_F' ? 'has-active' : '']"
>finyx-AI</el-button>
<el-button
v-show="showBtn(scope.row, 'D3_F')"
link
type="primary"
icon="Edit"
@click="openDialog(scope.row, 'D3_F')"
:class="[matchIdType.id === scope.row.matchId && matchIdType.type === 'D3_F' ? 'has-active' : '']"
>D3-index</el-button>
</template>
</el-table-column>
<el-table-column label="D3预测结果" width="300" align="center">
<el-table-column label="常" width="50" align="center">
<template #default="scope">
<span :class="['icon-d3', tableColumnActive(scope.row, 'D3_F', 'resultFlag')]"></span>
</template>
</el-table-column>
<el-table-column label="让" width="50" align="center">
<template #default="scope">
<span :class="['icon-d3', tableColumnActive(scope.row, 'D3_F', 'hhadResultFlag')]"></span>
</template>
</el-table-column>
<el-table-column label="分" width="50" align="center">
<template #default="scope">
<span :class="['icon-d3', tableColumnActive(scope.row, 'D3_F', 'scoreResultFlag')]"></span>
</template>
</el-table-column>
<el-table-column label="总" width="50" align="center">
<template #default="scope">
<span :class="['icon-d3', tableColumnActive(scope.row, 'D3_F', 'goalsResultFlag')]"></span>
</template>
</el-table-column>
<el-table-column label="半" width="50" align="center">
<template #default="scope">
<span :class="['icon-d3', tableColumnActive(scope.row, 'D3_F', 'halfFullResultFlag')]"></span>
</template>
</el-table-column>
<el-table-column label="亚" width="50" align="center">
<template #default="scope">
<span :class="['icon-d3', tableColumnActive(scope.row, 'D3_F', 'asianHandicapFlag')]"></span>
</template>
</el-table-column>
</el-table-column>
</el-table>
<!-- 分页区域 -->
<pagination
:show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList" />
</div>
<lz-page-empty v-else-if="!loading" :type="'2'">
<lz-svg-icon icon-class="empty2" style="font-size: 312px;"/>
</lz-page-empty>
<!-- 修改对话框 -->
<el-dialog :title="dialogTitle" v-model="dialogOpen" width="600px" append-to-body>
<Prediction :data="dialogForm" type="edit" v-if="dialogOpen" @submit="submitForm" ref="editHadRef"/>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="OperationReport">
import { Info, infoSelectDistinctLeagueAbbNames, reportResultUpdate } from "@/api/tc/eventAnalysisReport"
import { jumpLink } from "@/utils/tc"
import { processMatchResults } from "@/utils/tc"
import Prediction from "@/views/operation/report/components/Prediction.vue"
import { ref } from "vue"
const router = useRouter()
const { proxy } = getCurrentInstance()
const pageList = ref([])
const loading = ref(false)
const showSearch = ref(true)
const total = ref(0)
const dateRange = ref([])
const editHadRef = ref(null)
const activeName = ref('FINYX_F')
const matchIdType = ref({ id: '', type: '' })
const dialogOpen = ref(false)
const dialogTitle = ref('标记')
const dialogForm = ref({})
/** 数据范围选项*/
const dataScopeOptions = ref([])
const flagStatusOptions = ref([
{ value: 1, label: '已标记' },
{ value: 0, label: '未标记' },
])
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
matchNumStr: undefined,
leagueAbbName: undefined,
flagStatus: undefined,
},
rules: {},
})
const { queryParams } = toRefs(data)
function tableColumnActive(row, modelType, key) {
// row
if (!row || Object.keys(row).length === 0) {
return '';
}
// reportResults
if (!row.reportResults || !Array.isArray(row.reportResults)) {
return '';
}
// modelType
const reportData = row.reportResults.find(item => item.modelType === modelType);
//
if (!reportData) {
return '';
}
// keyactive
const value = reportData[key];
if (value && value === '1') {
return 'table-column-active-1';
}
if (value && value === '0.5') {
return 'table-column-active-11';
}
if (value && value === '-1') {
return 'table-column-active-2';
}
if (value && value === '-0.5') {
return 'table-column-active-22';
}
return '4';
}
function rowPrediction(row, modelType) {
return row.reportResults && row.reportResults.find(el => el.modelType === modelType) || {}
}
function showBtn(row, type) {
// reportResultsfalse
if(!row.reportResults) {
return false
}
if(row.reportResults.find(el => el.modelType === type)) {
return true
}
return false
}
/** 导出按钮操作 */
function handleExport() {
// proxy.download("system/user/export", {
// ...queryParams.value,
// },`user_${new Date().getTime()}.xlsx`)
}
/** 提交表单 */
function submitForm() {
const data = editHadRef.value.getFormData()
reportResultUpdate(data).then(response => {
proxy.$message.success(response.msg)
getList()
}).finally(() => {
dialogOpen.value = false
})
}
/** 取消按钮 */
function cancel() {
dialogOpen.value = false
dialogForm.value = {}
getList()
}
function openDialog(row, type='') {
if(row && row.reportResults && type){
dialogForm.value = row.reportResults.find(el => el.modelType === type)
dialogOpen.value = true
dialogTitle.value = ' 标记 ' + row.matchNumStr + ' ' + type+ '模型'
matchIdType.value = { id: row.matchId, type: type }
}
}
/** 获取联赛类型 */
function getLeagueAbbNames() {
infoSelectDistinctLeagueAbbNames().then(response => {
dataScopeOptions.value = response.rows ? response.rows.map(item => ({ value: item, label: item })) : []
})
}
/** 跳转链接 */
function handleJumpLink(row) {
jumpLink(row.matchId, 1)
}
function reportResultsModelType(arr){
const res = {}
arr.forEach(item => {
res[item.modelType] = [
{
lable: '主队',
value: item.homeTeamName,
key: 'result'
},
{
lable: '客队',
value: item.awayTeamName,
key: 'result'
},
{
lable: '胜平负',
value: item.result,
key: 'result'
},
{
lable: '让分胜平负',
value: item.hhadResult,
key: 'hhadResult'
},
{
lable: '比分',
value: item.scoreResult,
key: 'scoreResult'
},
{
lable: '进球数',
value: item.goalsResult,
key: 'goalsResult'
},
{
lable: '半全场',
value: item.halfFullResult,
key: 'halfFullResult'
},
{
lable: '亚盘',
value: item.asianHandicap,
key: 'asianHandicap'
}
]
})
return res;
}
function farmatReportResults(list) {
const res = list.map(item => ({
...item,
farmatReportResults: item.reportResults ? reportResultsModelType(item.reportResults): {}
}));
return res;
}
/** 查询列表 */
function getList() {
loading.value = true
const data = { ...queryParams.value }
if (dateRange.value && dateRange.value[0] && dateRange.value[1]) {
data.beginTime = dateRange.value[0]
data.endTime = dateRange.value[1]
} else {
data.beginTime = undefined
data.endTime = undefined
}
Info(data).then(response => {
const res = response.rows.map(item => ({
...item,
matchResults: item.matchResults ? processMatchResults(item.matchResults): null
}));
// reportResults
pageList.value = farmatReportResults(res)
total.value = response.total
}).finally(() => {
loading.value = false
})
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = []
proxy.resetForm("queryRef")
handleQuery()
matchIdType.value = { id: '', type: '' }
}
onMounted(() => {
//
getLeagueAbbNames()
//
getList()
})
</script>
<style scoped lang="scss">
.icon-d3 {
display: inline-block;
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #fff;
border: 2px solid #3067EF;
box-sizing: border-box;
}
.table-column-active-1 {
background-color: #f56c6c;
border-color: #f56c6c;
}
.table-column-active-11 {
background-color: #f56c6c;
border-color: #f56c6c;
position: relative;
}
.table-column-active-11::after {
content: '';
display: block;
width: 20px;
height: 10px;
background-color: #fff;
position: absolute;
top: 50%;
left: -2px;
}
.table-column-active-2 {
background-color: #333;
border-color: #333;
}
.table-column-active-22 {
background-color: #333;
border-color: #333;
position: relative;
}
.table-column-active-22::after {
content: '';
display: block;
width: 20px;
height: 10px;
background-color: #fff;
position: absolute;
top: 50%;
left: -2px;
}
</style>

View File

@ -0,0 +1,415 @@
<template>
<div class="tab-page-content">
<!-- 搜索区域 -->
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="80px">
<el-form-item label="赛事编号" prop="matchDate">
<el-input v-model="queryParams.matchDate" placeholder="请输入赛事编号" clearable style="width: 240px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="联赛类型" prop="leagueAbbName">
<el-select v-model="queryParams.leagueAbbName" @change="handleQuery" style="width: 240px" clearable placeholder="请选择联赛类型">
<el-option
v-for="item in dataScopeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="标记状态" prop="flagStatus">
<el-select v-model="queryParams.flagStatus" @change="handleQuery" style="width: 240px" clearable placeholder="请选择标记状态">
<el-option
v-for="item in flagStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="时间">
<el-date-picker v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-"
start-placeholder="开始日期" end-placeholder="结束日期" style="width: 240px"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery" :loading="loading">查询</el-button>
<el-button icon="Refresh" @click="resetQuery" :loading="loading">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row>
<!--loading-->
<div
v-if="loading"
v-loading="loading"
class="loading-page"
element-loading-text="正在加载..."
style="width: 100%; height: calc(100vh - 250px)"
></div>
<div v-else-if="pageList.length && !loading">
<!-- 表格数据 -->
<el-table v-loading="loading" :data="pageList">
<el-table-column label="赛事编号" prop="matchDate" />
<el-table-column label="联赛" prop="leagueAbbName" :show-overflow-tooltip="true" />
<el-table-column label="主队" prop="homeTeamAbbName" :show-overflow-tooltip="true" />
<el-table-column label="客队" prop="awayTeamAbbName" />
<el-table-column label="比赛开始时间" align="center" prop="matchDateTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.matchDateTime) }}</span>
</template>
</el-table-column>
<el-table-column label="赛果" prop="matchId">
<template #default="scope">
<el-button link type="primary" @click="handleJumpLink(scope.row)">查看</el-button>
</template>
</el-table-column>
<el-table-column label="AI预测" prop="matchId">
<template #default="scope">
<el-popover placement="bottom" :width="360">
<template #reference>
<el-button link type="primary">查看</el-button>
</template>
<template #default>
<div style="padding: 8px;">
<el-table border :data="scope.row.farmatReportResults['HOT_F']" :show-header="false">
<el-table-column>
<template #default="item">
{{ item.row.lable }}
</template>
</el-table-column>
<el-table-column>
<template #default="item">
{{ item.row.value || '-' }}
</template>
</el-table-column>
</el-table>
</div>
</template>
</el-popover>
</template>
</el-table-column>
<el-table-column label="结果标记" align="center" class-name="small-padding fixed-width" width="200">
<template #default="scope">
<el-button
v-show="showBtn(scope.row, 'HOT_F')"
link
type="primary"
icon="Edit"
@click="openDialog(scope.row, 'HOT_F')"
:class="[matchIdType.id === scope.row.matchId && matchIdType.type === 'HOT_F' ? 'has-active' : '']"
>D3-index</el-button>
</template>
</el-table-column>
<el-table-column label="D3预测结果" width="300" align="center">
<el-table-column label="总" width="50" align="center">
<template #default="scope">
<span :class="['icon-d3', tableColumnActive(scope.row, 'HOT_F', 'goalsResultFlag')]"></span>
</template>
</el-table-column>
<el-table-column label="亚" width="50" align="center">
<template #default="scope">
<span :class="['icon-d3', tableColumnActive(scope.row, 'HOT_F', 'asianHandicapFlag')]"></span>
</template>
</el-table-column>
</el-table-column>
</el-table>
<!-- 分页区域 -->
<pagination
:show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList" />
</div>
<lz-page-empty v-else-if="!loading" :type="'2'">
<lz-svg-icon icon-class="empty2" style="font-size: 312px;"/>
</lz-page-empty>
<!-- 修改对话框 -->
<el-dialog :title="dialogTitle" v-model="dialogOpen" width="600px" append-to-body>
<Prediction2 :data="dialogForm" type="edit" v-if="dialogOpen" @submit="submitForm" ref="editHadRef"/>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="OperationReport">
import { infoSelectDistinctLeagueAbbNames, reportResultUpdate } from "@/api/tc/eventAnalysisReport"
import { hotMatchList } from "@/api/tc/hot"
import { processMatchResults } from "@/utils/tc"
import Prediction2 from "@/views/operation/report/components/Prediction2.vue"
import { ref } from "vue"
const router = useRouter()
const { proxy } = getCurrentInstance()
const pageList = ref([])
const loading = ref(false)
const showSearch = ref(true)
const total = ref(0)
const dateRange = ref([])
const editHadRef = ref(null)
const activeName = ref('FINYX_F')
const matchIdType = ref({ id: '', type: '' })
const dialogOpen = ref(false)
const dialogTitle = ref('标记')
const dialogForm = ref({})
/** 数据范围选项*/
const dataScopeOptions = ref([])
const flagStatusOptions = ref([
{ value: 1, label: '已标记' },
{ value: 0, label: '未标记' },
])
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
matchDate: undefined,
leagueAbbName: undefined,
flagStatus: undefined,
},
rules: {},
})
const { queryParams } = toRefs(data)
function tableColumnActive(row, modelType, key) {
// row
if (!row || Object.keys(row).length === 0) {
return '';
}
// reportResults
if (!row.reportResults || !Array.isArray(row.reportResults)) {
return '';
}
// modelType
const reportData = row.reportResults.find(item => item.modelType === modelType);
//
if (!reportData) {
return '';
}
// keyactive
const value = reportData[key];
if (value && value === '1') {
return 'table-column-active-1';
}
if (value && value === '0.5') {
return 'table-column-active-11';
}
if (value && value === '-1') {
return 'table-column-active-2';
}
if (value && value === '-0.5') {
return 'table-column-active-22';
}
return '4';
}
function rowPrediction(row, modelType) {
return row.reportResults && row.reportResults.find(el => el.modelType === modelType) || {}
}
function showBtn(row, type) {
// reportResultsfalse
if(!row.reportResults) {
return false
}
if(row.reportResults.find(el => el.modelType === type)) {
return true
}
return false
}
/** 导出按钮操作 */
function handleExport() {
// proxy.download("system/user/export", {
// ...queryParams.value,
// },`user_${new Date().getTime()}.xlsx`)
}
/** 提交表单 */
function submitForm() {
const data = editHadRef.value.getFormData()
reportResultUpdate(data).then(response => {
proxy.$message.success(response.msg)
getList()
}).finally(() => {
dialogOpen.value = false
})
}
/** 取消按钮 */
function cancel() {
dialogOpen.value = false
dialogForm.value = {}
getList()
}
function openDialog(row, type='') {
if(row && row.reportResults && type){
dialogForm.value = row.reportResults.find(el => el.modelType === type)
dialogOpen.value = true
dialogTitle.value = ' 标记 ' + row.matchDate + ' ' + type+ '模型'
matchIdType.value = { id: row.matchId, type: type }
}
}
/** 获取联赛类型 */
function getLeagueAbbNames() {
infoSelectDistinctLeagueAbbNames().then(response => {
dataScopeOptions.value = response.rows ? response.rows.map(item => ({ value: item, label: item })) : []
})
}
/** 跳转链接 */
function handleJumpLink(row) {
window.open(`https://live.titan007.com/detail/${row.matchId}sb.htm`)
}
function reportResultsModelType(arr){
const res = {}
arr.forEach(item => {
res[item.modelType] = [
{
lable: '进球数',
value: item.goalsResult,
key: 'goalsResult'
},
{
lable: '亚盘',
value: item.asianHandicap,
key: 'asianHandicap'
}
]
})
return res;
}
function farmatReportResults(list) {
const res = list.map(item => ({
...item,
farmatReportResults: item.reportResults ? reportResultsModelType(item.reportResults): {}
}));
return res;
}
/** 查询列表 */
function getList() {
loading.value = true
const data = { ...queryParams.value }
if (dateRange.value && dateRange.value[0] && dateRange.value[1]) {
data.beginTime = dateRange.value[0]
data.endTime = dateRange.value[1]
} else {
data.beginTime = undefined
data.endTime = undefined
}
hotMatchList(data).then(response => {
const res = response.rows.map(item => ({
...item,
matchResults: item.matchResults ? processMatchResults(item.matchResults): null
}));
// reportResults
pageList.value = farmatReportResults(res)
total.value = response.total
}).finally(() => {
loading.value = false
})
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = []
proxy.resetForm("queryRef")
handleQuery()
matchIdType.value = { id: '', type: '' }
}
onMounted(() => {
//
getLeagueAbbNames()
//
getList()
})
</script>
<style scoped lang="scss">
.icon-d3 {
display: inline-block;
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #fff;
border: 2px solid #3067EF;
box-sizing: border-box;
}
.table-column-active-1 {
background-color: #f56c6c;
border-color: #f56c6c;
}
.table-column-active-11 {
background-color: #f56c6c;
border-color: #f56c6c;
position: relative;
}
.table-column-active-11::after {
content: '';
display: block;
width: 20px;
height: 10px;
background-color: #fff;
position: absolute;
top: 50%;
left: -2px;
}
.table-column-active-2 {
background-color: #333;
border-color: #333;
}
.table-column-active-22 {
background-color: #333;
border-color: #333;
position: relative;
}
.table-column-active-22::after {
content: '';
display: block;
width: 20px;
height: 10px;
background-color: #fff;
position: absolute;
top: 50%;
left: -2px;
}
</style>

View File

@ -0,0 +1,36 @@
<template>
<div class="app-container">
<el-tabs v-model="activeName" class="res-el-tab" @tab-click="handleClick">
<el-tab-pane label="竞猜足球" name="betting_soccer"><TabPane1 /></el-tab-pane>
<el-tab-pane label="热门足球" name="hot_soccer"><TabPane2 /></el-tab-pane>
</el-tabs>
</div>
</template>
<script setup name="EventAnalysisReport">
import { ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import TabPane1 from './components/TabPane1.vue'
import TabPane2 from './components/TabPane2.vue'
const route = useRoute()
const router = useRouter()
// URLactiveName'soccer'
const activeName = ref(route.query.tab || 'betting_soccer')
// activeNameURL
watch(activeName, (newVal) => {
router.replace({
query: {
...route.query,
tab: newVal
}
})
})
const handleClick = (tab, event) => {
console.log('点击标签页:', tab.props.name)
}
</script>

View File

@ -70,7 +70,7 @@
</el-form> </el-form>
<!-- 底部 --> <!-- 底部 -->
<div class="el-register-footer"> <div class="el-register-footer">
<span>Copyright ©2025 北京数维无穹科技有限公司</span> <!-- <span>Copyright ©2025 北京数维无穹科技有限公司</span> -->
</div> </div>
</div> </div>
</template> </template>
@ -161,7 +161,7 @@ getCode()
justify-content: center; justify-content: center;
align-items: center; align-items: center;
height: 100%; height: 100%;
background-image: url("../assets/images/login-background.jpg"); background-image: url("../assets/images/login.png");
background-size: cover; background-size: cover;
} }
.title { .title {

View File

@ -0,0 +1,161 @@
<template>
<div class="had">
<div class="had-content flex" v-for="(item,index) in data.matchSpfDetails" :key="item.id" :data-goalType="item.goalType">
<!-- <span>{{ item.goalLine || 0 }}</span> -->
<span class="had-content-item-left flex-center">
<el-badge :value="item.goalLine||0" :color="index === 0 ?'#666' : '#f56c6c'" />
</span>
<div class="had-content-table flex">
<div :class="['had-content-table-item', {'is-active': item.isActive === 'h'}]" data-id="h" @click="handleClick(item, 'h')">
<span></span>
<span>{{ item.win || 0 }}</span>
</div>
<div :class="['had-content-table-item', {'is-active': item.isActive === 'a'}]" data-id="a" @click="handleClick(item, 'a')">
<span></span>
<span>{{ item.draw || 0 }}</span>
</div>
<div :class="['had-content-table-item', {'is-active': item.isActive === 'd'}]" data-id="d" @click="handleClick(item, 'd')">
<span></span>
<span>{{ item.debt || 0 }}</span>
</div>
</div>
</div>
<!--编辑模式-->
<div class="had-content flex had-content-edit">
<span class="had-content-item-left flex-center"></span>
<div class="had-content-table flex">
<div :class="['had-content-table-item', {'is-active': ttgFlag === 'aover'}]" style="width: 50%; text-align: center;" @click="handleTtgClick('aover')">
<span>大球</span>
</div>
<div :class="['had-content-table-item', {'is-active': ttgFlag === 'under'}]" style="width: 50%; text-align: center;"@click="handleTtgClick('under')">
<span>小球</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
//
const props = defineProps({
data: {
type: Object,
default: () => ({})
},
type: {
type: String,
default: 'view' // edit view
}
});
//
const { data } = toRefs(props);
const ttgFlag = ref('');
function handleClick(item, type) {
if(props.type === 'edit'){
item.isActive = item.isActive === type ? '' : type;
}
}
function handleTtgClick(type) {
if(props.type === 'edit'){
ttgFlag.value = ttgFlag.value === type ? '' : type;
}
}
function getFormData() {
const res = {
matchId: data.value.matchId,
ttgFlag: ttgFlag.value
}
data.value.matchSpfDetails.forEach(el => {
if(el.goalType === 'HAD') {
res.hadFlag = el.isActive || '';
}
if(el.goalType === 'HHAD') {
res.hhadFlag = el.isActive || '';
}
});
return res;
}
onMounted(() => {
if(data.value.reportDetail && data.value.matchSpfDetails){
const reportDetail = data.value.reportDetail;
console.log(reportDetail.hadFlag, reportDetail.hhadFlag, reportDetail.ttgFlag);
ttgFlag.value = reportDetail.ttgFlag;
data.value.matchSpfDetails.forEach(el => {
if(el.goalType === 'HAD') {
el.isActive = reportDetail.hadFlag || '';
}
if(el.goalType === 'HHAD') {
el.isActive = reportDetail.hhadFlag || '';
}
});
}
})
defineExpose({
getFormData
});
</script>
<style lang="scss" scoped>
.had {
.had-content:nth-child(2) {
.had-content-table{
.had-content-table-item{
border-top: none
}
}
}
}
.had-content-item-left{
width: 60px;
text-align: center;
}
.had-content-table{
display: flex;
justify-content: space-between;
width: 100%;
}
.had-content-table-item {
padding: 12px;
border: 1px solid #ccc;
width: 33.33%;
cursor: pointer;
display: flex;
justify-content: space-between;
background-color: #f2f2f2;
}
.had-content-table .had-content-table-item:nth-child(2) {
border-left: none;
border-right: none;
}
.is-active {
background-color: #f56c6c;
color: #fff;
}
/** 编辑模式 */
.had-content-edit {
.had-content-table-item {
border-top: none;
}
.had-content-table-item:nth-child(2) {
border-right: 1px solid #ccc;
}
}
</style>

View File

@ -1,64 +1,179 @@
<template> <template>
<div> <div class="tab-page-content">
<!-- 搜索区域 --> <!-- 搜索区域 -->
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="80px"> <el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="80px">
<el-form-item label="编号/名称" prop="roleName"> <!-- <el-form-item label="赛事编号" prop="matchNumStr">
<el-input v-model="queryParams.roleName" placeholder="请输入集合编号/球队名称" clearable style="width: 240px" <el-input v-model="queryParams.matchNumStr" placeholder="请输入赛事编号" clearable style="width: 240px"
@keyup.enter="handleQuery" /> @keyup.enter="handleQuery" />
</el-form-item> </el-form-item> -->
<el-form-item label="联赛类型" prop="roleKey"> <el-form-item label="联赛类型" prop="leagueAbbName">
<el-select v-model="queryParams.roleKey" @change="handleQuery" style="width: 240px" clearable <el-select v-model="queryParams.leagueAbbName" @change="handleQuery" style="width: 240px" clearable
placeholder="请选择联赛类型"> placeholder="请选择联赛类型">
<el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label" <el-option
:value="item.value"></el-option> v-for="item in dataScopeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="时间"> <!-- <el-form-item label="日期范围">
<el-date-picker v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-" <el-date-picker v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-"
start-placeholder="开始日期" end-placeholder="结束日期" style="width: 240px"></el-date-picker> start-placeholder="开始日期" end-placeholder="结束日期" style="width: 240px"></el-date-picker>
</el-form-item> -->
<el-form-item label="时间" prop="weekDay">
<el-select
v-model="queryParams.weekDay"
style="width: 240px"
@change="handleWeekdayChange"
clearable
placeholder="请选择星期"
>
<el-option
v-for="item in PickerOptions"
:key="item.text"
:label="item.text"
:value="item.text"
></el-option>
</el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">查询</el-button> <el-button type="primary" icon="Search" @click="handleQuery" :loading="loading">查询</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button> <el-button icon="Refresh" @click="resetQuery" :loading="loading">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<!--loading-->
<div
v-if="loading"
v-loading="loading"
class="loading-page"
element-loading-text="正在加载..."
style="width: 100%; height: calc(100vh - 250px)"
></div>
<div v-else-if="roleList.length && !loading">
<!-- 表格数据 -->
<el-table v-loading="loading" :data="roleList">
<el-table-column label="赛事编号" prop="matchNumStr" />
<el-table-column label="联赛" prop="leagueAllName" :show-overflow-tooltip="true" />
<el-table-column label="主队" prop="homeTeamAllName" :show-overflow-tooltip="true" />
<el-table-column label="客队" prop="awayTeamAllName" />
<!-- <el-table-column label="固定奖金" prop="matchId" >
<template #default="scope">
<el-button link type="primary" @click="handleJumpLink(scope.row)">查看</el-button>
</template>
</el-table-column> -->
<el-table-column label="赛果" prop="matchId">
<template #default="scope">
<el-popover placement="bottom" :width="360">
<template #reference>
<el-button link type="primary" @dblclick="handleJumpLink(scope.row)">查看</el-button>
</template>
<template #default>
<div>
<el-table border :data="scope.row.matchResults">
<el-table-column label="游戏" prop="matchNumStr">
<template #default="item">
{{ item.row.codeName || '-' }}
</template>
</el-table-column>
<el-table-column label="开赛结果" prop="reportSatus">
<template #default="item">
<el-tag type="error">{{ item.row.combinationDesc || '-' }}</el-tag>
</template>
</el-table-column>
<el-table-column label="分值" prop="matchNumStr">
<template #default="item">
{{ item.row.goalLine || '-' }}
</template>
</el-table-column>
<el-table-column label="奖金" prop="matchNumStr">
<template #default="item">
{{ item.row.odds || '-' }}
</template>
</el-table-column>
</el-table>
</div>
</template>
</el-popover>
</template>
</el-table-column>
<el-table-column label="比赛开始时间" align="center" prop="matchDateTime">
<template #default="scope">
<span>{{ parseTime(scope.row.matchDateTime) }}</span>
</template>
</el-table-column>
<!-- <el-table-column label="报告状态" prop="reportSatus">
<template #default="scope">
<el-tag v-if="scope.row.reportSatus === 1" type="success">已生成</el-tag>
<el-tag v-else>未生成</el-tag>
</template>
</el-table-column> -->
<!-- <el-table-column label="finyx模型" align="center" class-name="small-padding fixed-width">
<template #header>
<span>finyx模型</span>
<el-popover placement="top" width="300" trigger="click">
<template #reference>
<el-icon class="ml-1 cursor-pointer" style="vertical-align: middle;">
<QuestionFilled />
</el-icon>
</template>
<template #default>
<div>
<p>finyx模型是机构保证稳定盈利的模型之一根据模型的波动走向同赔倾向等特点再加上百万赛事信息的数据整理及独有情报信息绘制出赛事趋势走向推演赛果走向</p>
</div>
</template>
</el-popover>
</template>
<template #default="scope">
<span :class="['flex-row cursor-pointer tc-view-time', scope.row.reportSatus != 1 && 'tc-view-time-disabled']" @click="handleView(scope.row)">
分析结果<br/>
{{ scope.row.reportSatus === 1? timerToStr(scope.row.reportTime, 'HH:mm') : '待' }}更新
</span>
</template>
</el-table-column> -->
<!-- 表格数据 --> <el-table-column :label="item.name" align="center" class-name="small-padding fixed-width" v-for="item in ModelsTypes.basketball" :key="item.value">
<el-table v-loading="loading" :data="roleList"> <template #header>
<el-table-column label="赛事编号" prop="matchNumStr" /> <span>{{ item.name }}</span>
<el-table-column label="联赛" prop="awayTeamAllName" :show-overflow-tooltip="true" /> <el-popover placement="top" width="300" trigger="click">
<el-table-column label="主队" prop="homeTeamAllName" :show-overflow-tooltip="true" /> <template #reference>
<el-table-column label="客队" prop="awayTeamAllName" /> <el-icon class="ml-1 cursor-pointer" style="vertical-align: middle;">
<el-table-column label="固定奖金" prop="matchId" > <QuestionFilled />
<template #default="scope"> </el-icon>
<el-button link type="primary" @click="handleJumpLink(scope.row)">查看</el-button> </template>
</template> <template #default>
</el-table-column> <div>
<el-table-column label="比赛开始时间" align="center" prop="matchDateTime"> <p>{{ item.title }}</p>
<template #default="scope"> </div>
<span>{{ parseTime(scope.row.matchDateTime) }}</span> </template>
</template> </el-popover>
</el-table-column> </template>
<el-table-column label="比赛状态" prop="matchStatus" /> <template #default="scope">
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <span :class="['flex-row cursor-pointer tc-view-time', isBtnDisabled(scope.row, item.value) && 'tc-view-time-disabled']" @click="handleView(scope.row, item.value)">
<template #default="scope"> 分析结果<br/>
<el-tooltip content="查看" placement="top" v-if="scope.row.roleId !== 1"> {{ isBtnTimer(scope.row, item.value) }}
<el-button link type="primary" icon="view" @click="handleView(scope.row)"></el-button> </span>
</el-tooltip> </template>
</template> </el-table-column>
</el-table-column> </el-table>
</el-table>
<!-- 分页区域 --> <!-- 分页区域 -->
<pagination :show="total > 0" :total="total" v-model:page="queryParams.pageNum" <pagination :show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" /> v-model:limit="queryParams.pageSize" @pagination="getList" />
</div>
<lz-page-empty v-else-if="!loading" :type="'2'">
<lz-svg-icon icon-class="empty2" style="font-size: 312px;"/>
</lz-page-empty>
</div> </div>
</template> </template>
<script setup name="Role"> <script setup name="Role">
import { bbInfo } from "@/api/tc/eventAnalysisReport" import { bbInfo, bbInfoSelectDistinctLeagueAbbNames } from "@/api/tc/eventAnalysisReport"
import { jumpLink } from "@/utils/tc" import { jumpLink, processMatchResults2 } from "@/utils/tc"
import { timerToStr } from "@/utils/timer"
import { PickerOptions, ModelsTypes } from "@/enums/tc"
const router = useRouter() const router = useRouter()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
@ -67,41 +182,74 @@ const loading = ref(true)
const showSearch = ref(true) const showSearch = ref(true)
const total = ref(0) const total = ref(0)
const dateRange = ref([]) const dateRange = ref([])
const queryRef = ref(null)
/** 数据范围选项*/ /** 数据范围选项*/
const dataScopeOptions = ref([ const dataScopeOptions = ref([])
{ value: "1", label: "全部数据权限" },
{ value: "2", label: "自定数据权限" },
{ value: "3", label: "本部门数据权限" },
{ value: "4", label: "本部门及以下数据权限" },
{ value: "5", label: "仅本人数据权限" }
])
const data = reactive({ const data = reactive({
form: {}, form: {},
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
roleName: undefined, // matchNumStr: undefined,
roleKey: undefined, leagueAbbName: undefined,
status: undefined weekDay: undefined,
}, },
rules: {}, rules: {},
}) })
const { queryParams } = toRefs(data) const { queryParams } = toRefs(data)
/** 检查按钮是否禁用 */
function isBtnDisabled(row, modelType) {
let disabled = true
if(row.reportDetails && row.reportDetails.length) {
row.reportDetails.forEach(item => {
if(item.modelType == modelType && item.reportStatus == 1) {
disabled = false
}
})
}
return disabled
}
function isBtnTimer(row, modelType){
let res = '待更新'
if(row.reportDetails && row.reportDetails.length) {
row.reportDetails.forEach(item => {
if(item.modelType == modelType && item.reportStatus == 1) {
res = timerToStr(item.reportTime, 'HH:mm') + '更新'
}
})
}
return res
}
/** 获取联赛类型 */
function getLeagueAbbNames() {
bbInfoSelectDistinctLeagueAbbNames().then(response => {
dataScopeOptions.value = response.rows ? response.rows.map(item => ({ value: item, label: item })) : []
})
}
/** 跳转链接 */ /** 跳转链接 */
function handleJumpLink(row) { function handleJumpLink(row) {
jumpLink(row.matchId, 2) jumpLink(row.matchId, 2)
} }
/** 查看详情 */ /** 查看详情 */
function handleView(row) { function handleView(row, modelType) {
if (row.reportSatus != 1) {
return
}
// window.open(window.location.origin + '/#/tc/eventAnalysisReport/detail?id=' + row.matchId)
router.push({ router.push({
path: '/tc/eventAnalysisReport/detail', path: '/tc/eventAnalysisReport/detail',
query: { query: {
id: row.matchId id: row.matchId,
modelType
} }
}) })
} }
@ -109,8 +257,21 @@ function handleView(row) {
/** 查询角色列表 */ /** 查询角色列表 */
function getList() { function getList() {
loading.value = true loading.value = true
bbInfo(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => { const data = { ...queryParams.value }
roleList.value = response.rows if (dateRange.value && dateRange.value[0] && dateRange.value[1]) {
data.beginTime = dateRange.value[0]
data.endTime = dateRange.value[1]
} else {
data.beginTime = undefined
data.endTime = undefined
}
bbInfo(data).then(response => {
const res = response.rows.map(item => ({
...item,
matchResults: item.matchResults ? processMatchResults2(item.matchResults): null
}));
console.log(res);
roleList.value = res
total.value = response.total total.value = response.total
}).finally(() => { }).finally(() => {
loading.value = false loading.value = false
@ -131,7 +292,15 @@ function resetQuery() {
} }
onMounted(() => { onMounted(() => {
//
getLeagueAbbNames()
//
getList() getList()
}) })
onActivated(() => {
getList()
})
</script> </script>

View File

@ -0,0 +1,98 @@
<template>
<div class="had">
<div class="had-content flex" v-for="(item,index) in data.matchSpfDetails" :key="item.id">
<!-- <span>{{ item.goalLine || 0 }}</span> -->
<span class="had-content-item-left flex-center">
<el-badge :value="item.goalLine||0" :color="index === 0 ?'#666' : '#f56c6c'" />
</span>
<div class="had-content-table flex">
<div :class="['had-content-table-item', {'is-active': item.isActive === 'h'}]">
<span></span>
<span>{{ item.win || 0 }}</span>
</div>
<div :class="['had-content-table-item', {'is-active': item.isActive === 'a'}]">
<span></span>
<span>{{ item.draw || 0 }}</span>
</div>
<div :class="['had-content-table-item', {'is-active': item.isActive === 'd'}]">
<span></span>
<span>{{ item.debt || 0 }}</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
//
const props = defineProps({
data: {
type: Object,
default: () => ({})
},
});
//
const { data } = toRefs(props);
onMounted(() => {
if(data.value.reportDetail && data.value.matchSpfDetails){
const reportDetail = data.value.reportDetail;
data.value.matchSpfDetails.forEach(el => {
if(el.goalType === 'HAD') {
el.isActive = reportDetail.hadFlag || '';
}
if(el.goalType === 'HHAD') {
el.isActive = reportDetail.hhadFlag || '';
}
});
}
})
</script>
<style lang="scss" scoped>
.had {
.had-content:nth-child(2) {
.had-content-table{
.had-content-table-item{
border-top: none
}
}
}
}
.had-content-item-left{
width: 60px;
text-align: center;
}
.had-content-table{
display: flex;
justify-content: space-between;
width: 100%;
}
.had-content-table-item {
padding: 12px;
border: 1px solid #ccc;
width: 33.33%;
cursor: pointer;
display: flex;
justify-content: space-between;
background-color: #f2f2f2;
}
.had-content-table .had-content-table-item:nth-child(2) {
border-left: none;
border-right: none;
}
.is-active {
background-color: #f56c6c;
color: #fff;
}
</style>

View File

@ -1,13 +1,13 @@
<template> <template>
<div> <div class="tab-page-content">
<!-- 搜索区域 --> <!-- 搜索区域 -->
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="80px"> <el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="80px">
<el-form-item label="编号/名称" prop="roleName"> <!-- <el-form-item label="赛事编号" prop="matchNumStr">
<el-input v-model="queryParams.roleName" placeholder="请输入集合编号/球队名称" clearable style="width: 240px" <el-input v-model="queryParams.matchNumStr" placeholder="请输入赛事编号" clearable style="width: 240px"
@keyup.enter="handleQuery" /> @keyup.enter="handleQuery" />
</el-form-item> </el-form-item> -->
<el-form-item label="联赛类型" prop="roleKey"> <el-form-item label="联赛类型" prop="leagueAbbName">
<el-select v-model="queryParams.roleKey" @change="handleQuery" style="width: 240px" clearable placeholder="请选择联赛类型"> <el-select v-model="queryParams.leagueAbbName" @change="handleQuery" style="width: 240px" clearable placeholder="请选择联赛类型">
<el-option <el-option
v-for="item in dataScopeOptions" v-for="item in dataScopeOptions"
:key="item.value" :key="item.value"
@ -17,112 +17,231 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="时间"> <!-- <el-form-item label="时间">
<el-date-picker v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-" <el-date-picker v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-"
start-placeholder="开始日期" end-placeholder="结束日期" style="width: 240px"></el-date-picker> start-placeholder="开始日期" end-placeholder="结束日期" style="width: 240px"></el-date-picker>
</el-form-item> -->
<el-form-item label="时间" prop="weekDay">
<el-select
v-model="queryParams.weekDay"
style="width: 240px"
@change="handleWeekdayChange"
clearable
placeholder="请选择星期"
>
<el-option
v-for="item in PickerOptions"
:key="item.text"
:label="item.text"
:value="item.text"
></el-option>
</el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">查询</el-button> <el-button type="primary" icon="Search" @click="handleQuery" :loading="loading">查询</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button> <el-button icon="Refresh" @click="resetQuery" :loading="loading">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<!--loading-->
<div
v-if="loading"
v-loading="loading"
class="loading-page"
element-loading-text="正在加载..."
style="width: 100%; height: calc(100vh - 250px)"
></div>
<div v-else-if="pageList.length && !loading">
<!-- 表格数据 -->
<el-table v-loading="loading" :data="pageList">
<el-table-column label="赛事编号" prop="matchNumStr" />
<el-table-column label="联赛" prop="leagueAllName" :show-overflow-tooltip="true" />
<el-table-column label="主队" prop="homeTeamAllName" :show-overflow-tooltip="true" />
<el-table-column label="客队" prop="awayTeamAbbName" />
<el-table-column label="赛果" prop="matchId">
<template #default="scope">
<el-popover placement="bottom" :width="360">
<template #reference>
<el-button link type="primary" @dblclick="handleJumpLink(scope.row)">查看</el-button>
</template>
<template #default>
<div>
<el-table border :data="scope.row.matchResults">
<el-table-column label="游戏" prop="matchNumStr">
<template #default="item">
{{ item.row.codeName }}
</template>
</el-table-column>
<el-table-column label="开赛结果" prop="reportSatus">
<template #default="item">
<el-tag type="error">{{ item.row.combinationDesc }}</el-tag>
</template>
</el-table-column>
<el-table-column label="奖金" prop="matchNumStr">
<template #default="item">
{{ item.row.odds }}
</template>
</el-table-column>
</el-table>
</div>
</template>
</el-popover>
</template>
</el-table-column>
<el-table-column label="比赛开始时间" align="center" prop="matchDateTime">
<template #default="scope">
<span>{{ parseTime(scope.row.matchDateTime) }}</span>
</template>
</el-table-column>
<el-table-column :label="item.name" align="center" class-name="small-padding fixed-width" v-for="item in ModelsTypes.soccer" :key="item.value">
<template #header>
<span>{{ item.name }}</span>
<el-popover placement="top" width="300" trigger="click">
<template #reference>
<el-icon class="ml-1 cursor-pointer" style="vertical-align: middle;">
<QuestionFilled />
</el-icon>
</template>
<template #default>
<div>
<p>{{ item.title }}</p>
</div>
</template>
</el-popover>
</template>
<template #default="scope">
<span :class="['flex-row cursor-pointer tc-view-time', isBtnDisabled(scope.row, item.value) && 'tc-view-time-disabled']" @click="handleView(scope.row, item.value)">
分析结果<br/>
{{ isBtnTimer(scope.row, item.value) }}
</span>
</template>
</el-table-column>
</el-table>
<!-- 表格数据 --> <!-- 分页区域 -->
<el-table v-loading="loading" :data="roleList"> <pagination
<el-table-column label="赛事编号" prop="matchNumStr" /> :show="total > 0"
<el-table-column label="联赛" prop="leagueAllName" :show-overflow-tooltip="true" /> :total="total"
<el-table-column label="主队" prop="homeTeamAllName" :show-overflow-tooltip="true" /> v-model:page="queryParams.pageNum"
<el-table-column label="客队" prop="awayTeamAbbName" /> v-model:limit="queryParams.pageSize"
<el-table-column label="固定奖金" prop="matchId"> @pagination="getList" />
<template #default="scope"> </div>
<el-button link type="primary" @click="handleJumpLink(scope.row)">查看</el-button> <lz-page-empty v-else-if="!loading" :type="'2'">
</template> <lz-svg-icon icon-class="empty2" style="font-size: 312px;"/>
</el-table-column> </lz-page-empty>
<el-table-column label="比赛开始时间" align="center" prop="matchDateTime">
<template #default="scope">
<span>{{ parseTime(scope.row.matchDateTime) }}</span>
</template>
</el-table-column>
<el-table-column label="比赛状态" prop="matchStatus" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="查看" placement="top" v-if="scope.row.roleId !== 1">
<el-button link type="primary" icon="view" @click="handleView(scope.row)"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<!-- 分页区域 -->
<pagination
:show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList" />
</div> </div>
</template> </template>
<script setup name="Role"> <script setup>
import { Info } from "@/api/tc/eventAnalysisReport" import { Info, infoSelectDistinctLeagueAbbNames } from "@/api/tc/eventAnalysisReport"
import { jumpLink } from "@/utils/tc" import { jumpLink } from "@/utils/tc"
import { timerToStr } from "@/utils/timer"
import { processMatchResults } from "@/utils/tc"
import { onActivated } from "vue"
import { PickerOptions, ModelsTypes } from "@/enums/tc"
const router = useRouter() const router = useRouter()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const roleList = ref([]) const pageList = ref([])
const loading = ref(false) const loading = ref(false)
const showSearch = ref(true) const showSearch = ref(true)
const total = ref(0) const total = ref(0)
const dateRange = ref([]) // const dateRange = ref([])
/** 数据范围选项*/ /** 数据范围选项*/
const dataScopeOptions = ref([ const dataScopeOptions = ref([])
{ value: "1", label: "全部数据权限" },
{ value: "2", label: "自定数据权限" },
{ value: "3", label: "本部门数据权限" },
{ value: "4", label: "本部门及以下数据权限" },
{ value: "5", label: "仅本人数据权限" }
])
const data = reactive({ const data = reactive({
form: {}, form: {},
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
roleName: undefined, // matchNumStr: undefined,
roleKey: undefined, leagueAbbName: undefined,
status: undefined weekDay: undefined,
}, },
rules: {}, rules: {},
}) })
const { queryParams } = toRefs(data) const { queryParams } = toRefs(data)
/** 检查按钮是否禁用 */
function isBtnDisabled(row, modelType) {
let disabled = true
if(row.reportDetails && row.reportDetails.length) {
row.reportDetails.forEach(item => {
if(item.modelType == modelType && item.reportStatus == 1) {
disabled = false
}
})
}
return disabled
}
function isBtnTimer(row, modelType){
let res = '待更新'
if(row.reportDetails && row.reportDetails.length) {
row.reportDetails.forEach(item => {
if(item.modelType == modelType && item.reportStatus == 1) {
res = timerToStr(item.reportTime, 'HH:mm') + '更新'
}
})
}
return res
}
//
function handleWeekdayChange(value) {
//
handleQuery();
}
/** 查询角色列表 */
function getList() {
loading.value = true
const data = { ...queryParams.value }
Info(data).then(response => {
const res = response.rows.map(item => ({
...item,
matchResults: item.matchResults ? processMatchResults(item.matchResults): null
}));
pageList.value = res
total.value = response.total
}).finally(() => {
loading.value = false
})
}
/** 获取联赛类型 */
function getLeagueAbbNames() {
infoSelectDistinctLeagueAbbNames().then(response => {
dataScopeOptions.value = response.rows ? response.rows.map(item => ({ value: item, label: item })) : []
})
}
/** 跳转链接 */ /** 跳转链接 */
function handleJumpLink(row) { function handleJumpLink(row) {
jumpLink(row.matchId, 1) jumpLink(row.matchId, 1)
} }
/** 查看详情 */ /** 查看详情 */
function handleView(row) { function handleView(row, modelType) {
if (row.reportSatus != 1) {
return
}
// window.open(window.location.origin + '/#/tc/eventAnalysisReport/detail?id=' + row.matchId)
router.push({ router.push({
path: '/tc/eventAnalysisReport/detail', path: '/tc/eventAnalysisReport/detail',
query: { query: {
id: row.matchId id: row.matchId,
modelType
} }
}) })
} }
/** 查询角色列表 */
function getList() {
loading.value = true
Info(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
roleList.value = response.rows
total.value = response.total
}).finally(() => {
loading.value = false
})
}
/** 搜索按钮操作 */ /** 搜索按钮操作 */
function handleQuery() { function handleQuery() {
@ -132,12 +251,20 @@ function handleQuery() {
/** 重置按钮操作 */ /** 重置按钮操作 */
function resetQuery() { function resetQuery() {
dateRange.value = [] // dateRange.value = []
proxy.resetForm("queryRef") proxy.resetForm("queryRef")
handleQuery() handleQuery()
} }
onMounted(() => { onMounted(() => {
//
getLeagueAbbNames()
//
getList() getList()
}) })
onActivated(() => {
getList()
})
</script> </script>

View File

@ -1,45 +1,205 @@
<template> <template>
<div class="app-container" v-loading="loading"> <div class="app-container" v-loading="loading">
<el-row :gutter="20"> <!--顶部-->
<div class="flex align-center mb-20">
<el-icon @click="proxy.$router.go(-1)" class="mr-6 cursor">
<ArrowLeftBold />
</el-icon>
{{ data && data.reportTime && timerToStr(data.reportTime, 'YYYY-MM-DD HH:mm:ss') }}
</div>
<!-- 自定义表格渲染 -->
<el-row :gutter="20" v-if="!loading && data && data.report && isJson && isCustom">
<el-col :xs="24" :sm="24" :md="24" :lg="24"> <el-col :xs="24" :sm="24" :md="24" :lg="24">
<el-card class="update-log"> <el-card class="update-log">
<template v-slot:header> <template v-slot:header>
<div class="clearfix"> <div class="clearfix">
<span>赛事分析 {{ data && data.reportTime }}</span> <span>赛事分析 {{ data && data.matchCode }}</span>
</div> </div>
</template> </template>
<div class="body"> <div class="body">
<p v-if="!loading && data && data.report"> <h3>1.比赛基础信息</h3>
{{ data && data.report }} <el-table v-loading="loading" :data="basicList" :show-header="false" border>
</p> <el-table-column label="比赛编号" prop="name" :show-overflow-tooltip="true" />
<el-empty v-else description="暂无数据"></el-empty> <el-table-column label="联赛" prop="value" :show-overflow-tooltip="true" />
</el-table>
<h3 class="mt-20">2.关键影响因素</h3>
<el-table v-loading="loading" :data="influencingList" :show-header="false" border>
<el-table-column :show-overflow-tooltip="true">
<template v-slot="{ row }">
{{ row }}
</template>
</el-table-column>
</el-table>
<h3 class="mt-20">3.核心预测结果</h3>
<el-table class="mb-20" v-loading="loading" :data="coreList" border>
<el-table-column label="预测类型" width="180" prop="name" :show-overflow-tooltip="true" />
<el-table-column label="预测结果" width="220" prop="prediction" :show-overflow-tooltip="true" />
<el-table-column label="分析依据" prop="analysis" :show-overflow-tooltip="true" />
</el-table>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
<!-- md 预览-->
<el-row :gutter="20" v-else-if="!loading && data && data.report && !isCustom">
<el-col :xs="24" :sm="24" :md="24" :lg="24">
<el-card class="update-log">
<template v-slot:header>
<div class="clearfix">
<span>赛事分析 {{ data && data.matchCode }}</span>
</div>
</template>
<div class="body">
<MdPreview
ref="editorRef"
editorId="preview-only"
:modelValue="data.report"
class="maxkb-md"
/>
</div>
</el-card>
</el-col>
</el-row>
<lz-page-empty v-else :type="'4'" text1="暂无赛事分析报告" text2="请稍后再试...">
<lz-svg-icon icon-class="empty1" style="font-size: 312px;" />
</lz-page-empty>
</div> </div>
</template> </template>
<script setup name="EventAnalysisReportDetail"> <script setup name="EventAnalysisReportDetail">
import { reportDetail } from '@/api/tc/eventAnalysisReport' import { detail } from '@/api/tc/eventAnalysisReport'
import MdPreview from '@/components/Markdown/MdPreview'
import { timerToStr } from '@/utils/timer'
import { computed } from 'vue'
const route = useRoute() const route = useRoute()
const isJson = computed(() => {
try {
return JSON.parse(data.value.report)
} catch (error) {
return false
}
})
let { proxy } = getCurrentInstance()
const id = ref(0) const id = ref(0)
const modelType = ref('')
const data = ref({}) const data = ref({})
const loading = ref(false) const loading = ref(false)
const basicList = ref([])
const influencingList = ref([])
const coreList = ref([])
const skipType = ['HONG_F', 'HONG_B','FINYX_B','D3_B'] // mdmodelType
const isCustom = computed(() => !skipType.includes(route.query.modelType)) // false: md true:
function getDetail() { function getDetail() {
loading.value = true loading.value = true
reportDetail(id.value).then(res => { detail({ matchId: id.value, modelType: modelType.value }).then(res => {
data.value = res.data data.value = res.data
if (res.data.report) {
try {
if(isCustom.value) {
//
const matchDateTime = res.data.matchInfo && res.data.matchInfo.matchDateTime ? timerToStr(res.data.matchInfo.matchDateTime, 'YYYY-MM-DD HH:mm') : '-'
const matchCode = res.data.matchCode
const report = JSON.parse(res.data.report)
const { keyFactors, matchInfo, predictions } = report
// 1.
basicList.value = [
{
name: "比赛编号",
value: matchCode
},
{
name: "主队",
value: matchInfo.homeTeam
},
{
name: "客队",
value: matchInfo.awayTeam
},
{
name: "时间",
value: matchDateTime
}
]
// 2.
influencingList.value = keyFactors
// 3.
if (modelType.value === 'HOT_F') {
//
coreList.value = [
{
"name": "总进球数",
"key": "total_goals",
"prediction": predictions.total_goals.prediction,
"analysis": predictions.total_goals.analysis
},
{
"name": "亚洲盘口",
"key": "asian_handicap",
"prediction": predictions.asian_handicap.prediction,
"analysis": predictions.asian_handicap.analysis
},
]
} else {
coreList.value = [
{
"name": "最终赛果",
"key": "result_final",
"prediction": predictions.result_final.prediction,
"analysis": predictions.result_final.analysis
},
{
"name": "让球结果",
"key": "result_handicap",
"prediction": predictions.result_handicap.prediction,
"analysis": predictions.result_handicap.analysis
},
{
"name": "比分预测",
"key": "score_prediction",
"prediction": predictions.score_prediction.prediction,
"analysis": predictions.score_prediction.analysis
},
{
"name": "总进球数",
"key": "total_goals",
"prediction": predictions.total_goals.prediction,
"analysis": predictions.total_goals.analysis
},
{
"name": "半全场赛果",
"key": "half_full_time",
"prediction": predictions.half_full_time.prediction,
"analysis": predictions.half_full_time.analysis
},
{
"name": "亚洲盘口",
"key": "asian_handicap",
"prediction": predictions.asian_handicap.prediction,
"analysis": predictions.asian_handicap.analysis
},
]
}
}
} catch (error) {
console.log(error)
}
}
}).finally(() => { }).finally(() => {
loading.value = false loading.value = false
}) })
} }
onMounted(() => { onMounted(() => {
if (route.query.id) { if (route.query.id && route.query.modelType) {
id.value = route.query.id id.value = route.query.id
modelType.value = route.query.modelType
getDetail() getDetail()
} }
}) })

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick"> <el-tabs v-model="activeName" class="res-el-tab" @tab-click="handleClick">
<el-tab-pane label="竞彩足球" name="soccer"><soccer /></el-tab-pane> <el-tab-pane label="竞彩足球" name="soccer"><soccer /></el-tab-pane>
<el-tab-pane label="竞彩篮球" name="basketball"><basketball /></el-tab-pane> <el-tab-pane label="竞彩篮球" name="basketball"><basketball /></el-tab-pane>
</el-tabs> </el-tabs>
@ -8,13 +8,29 @@
</template> </template>
<script setup name="EventAnalysisReport"> <script setup name="EventAnalysisReport">
import { ref } from 'vue' import { ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import soccer from './components/soccer.vue' import soccer from './components/soccer.vue'
import basketball from './components/basketball.vue' import basketball from './components/basketball.vue'
const activeName = ref('soccer') const route = useRoute()
const router = useRouter()
// URLactiveName'soccer'
const activeName = ref(route.query.tab || 'soccer')
// activeNameURL
watch(activeName, (newVal) => {
router.replace({
query: {
...route.query,
tab: newVal
}
})
})
const handleClick = (tab, event) => { const handleClick = (tab, event) => {
console.log(tab, event) console.log('点击标签页:', tab.props.name)
} }
</script> </script>

View File

@ -0,0 +1,246 @@
<template>
<div class="app-container">
<!-- 搜索区域 -->
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="80px">
<!-- <el-form-item label="赛事编号" prop="matchNumStr">
<el-input v-model="queryParams.matchNumStr" placeholder="请输入赛事编号" clearable style="width: 240px"
@keyup.enter="handleQuery" />
</el-form-item> -->
<el-form-item label="联赛类型" prop="leagueAbbName">
<el-select v-model="queryParams.leagueAbbName" @change="handleQuery" style="width: 240px" clearable placeholder="请选择联赛类型">
<el-option
v-for="item in dataScopeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item label="时间">
<el-date-picker v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-"
start-placeholder="开始日期" end-placeholder="结束日期" style="width: 240px"></el-date-picker>
</el-form-item> -->
<el-form-item label="时间" prop="weekDay">
<el-select
v-model="queryParams.weekDay"
style="width: 240px"
@change="handleWeekdayChange"
clearable
placeholder="请选择星期"
>
<el-option
v-for="item in PickerOptions"
:key="item.text"
:label="item.text"
:value="item.text"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery" :loading="loading">查询</el-button>
<el-button icon="Refresh" @click="resetQuery" :loading="loading">重置</el-button>
</el-form-item>
</el-form>
<!--loading-->
<div
v-if="loading"
v-loading="loading"
class="loading-page"
element-loading-text="正在加载..."
style="width: 100%; height: calc(100vh - 250px)"
></div>
<div v-else-if="pageList.length && !loading">
<!-- 表格数据 -->
<el-table v-loading="loading" :data="pageList">
<el-table-column label="赛事编号" prop="matchDate" />
<el-table-column label="联赛" prop="leagueAbbName" :show-overflow-tooltip="true" />
<el-table-column label="主队" prop="homeTeamAbbName" :show-overflow-tooltip="true" />
<el-table-column label="客队" prop="awayTeamAbbName" />
<el-table-column label="赛果" prop="matchId">
<template #default="scope">
<el-button link type="primary" @click="handleJumpLink(scope.row)">查看</el-button>
</template>
</el-table-column>
<el-table-column label="比赛开始时间" align="center" prop="matchDateTime">
<template #default="scope">
<span>{{ parseTime(scope.row.matchDateTime) }}</span>
</template>
</el-table-column>
<el-table-column :label="item.name" align="center" class-name="small-padding fixed-width" v-for="item in ModelsTypes.hot" :key="item.value">
<template #header>
<span>{{ item.name }}</span>
<el-popover placement="top" width="300" trigger="click">
<template #reference>
<el-icon class="ml-1 cursor-pointer" style="vertical-align: middle;">
<QuestionFilled />
</el-icon>
</template>
<template #default>
<div>
<p>{{ item.title }}</p>
</div>
</template>
</el-popover>
</template>
<template #default="scope">
<span :class="['flex-row cursor-pointer tc-view-time', isBtnDisabled(scope.row, item.value) && 'tc-view-time-disabled']" @click="handleView(scope.row, item.value)">
分析结果<br/>
{{ isBtnTimer(scope.row, item.value) }}
</span>
</template>
</el-table-column>
</el-table>
<!-- 分页区域 -->
<pagination
:show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList" />
</div>
<lz-page-empty v-else-if="!loading" :type="'2'">
<lz-svg-icon icon-class="empty2" style="font-size: 312px;"/>
</lz-page-empty>
</div>
</template>
<script setup>
import { infoSelectDistinctLeagueAbbNames } from "@/api/tc/eventAnalysisReport"
import { hotMatchList } from "@/api/tc/hot"
import { jumpLink } from "@/utils/tc"
import { timerToStr } from "@/utils/timer"
import { processMatchResults } from "@/utils/tc"
import { onActivated } from "vue"
import { PickerOptions, ModelsTypes } from "@/enums/tc"
const router = useRouter()
const { proxy } = getCurrentInstance()
const pageList = ref([])
const loading = ref(false)
const showSearch = ref(true)
const total = ref(0)
// const dateRange = ref([])
/** 数据范围选项*/
const dataScopeOptions = ref([])
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
// matchNumStr: undefined,
leagueAbbName: undefined,
weekDay: undefined,
},
rules: {},
})
const { queryParams } = toRefs(data)
/** 检查按钮是否禁用 */
function isBtnDisabled(row) {
let disabled = true
if(row.reportDetail && row.reportDetail.reportStatus === 1) {
disabled = false
}
return disabled
}
function isBtnTimer(row){
let res = '待更新'
if(row.reportDetail && row.reportDetail.reportTime) {
res = timerToStr(row.reportDetail.reportTime, 'HH:mm') + '更新'
}
return res
}
//
function handleWeekdayChange(value) {
//
handleQuery();
}
/** 查询角色列表 */
function getList() {
loading.value = true
const data = { ...queryParams.value }
// if (dateRange.value && dateRange.value[0] && dateRange.value[1]) {
// data.beginTime = dateRange.value[0]
// data.endTime = dateRange.value[1]
// } else {
// data.beginTime = undefined
// data.endTime = undefined
// }
hotMatchList(data).then(response => {
const res = response.rows.map(item => ({
...item,
matchResults: item.matchResults ? processMatchResults(item.matchResults): null
}));
pageList.value = res
total.value = response.total
}).finally(() => {
loading.value = false
})
}
/** 获取联赛类型 */
function getLeagueAbbNames() {
infoSelectDistinctLeagueAbbNames().then(response => {
dataScopeOptions.value = response.rows ? response.rows.map(item => ({ value: item, label: item })) : []
})
}
/** 跳转链接 */
function handleJumpLink(row) {
// jumpLink(row.matchId, 1)
window.open(`https://live.titan007.com/detail/${row.matchId}sb.htm`)
}
/** 查看详情 */
function handleView(row, modelType) {
if (!row.reportDetail || (row.reportDetail && row.reportDetail.reportStatus != 1)) {
return
}
router.push({
path: '/tc/eventAnalysisReport/detail',
query: {
id: row.matchId,
modelType
}
})
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
// dateRange.value = []
proxy.resetForm("queryRef")
handleQuery()
}
onMounted(() => {
//
getLeagueAbbNames()
//
getList()
})
onActivated(() => {
getList()
})
</script>

View File

@ -1,13 +1,13 @@
<template> <template>
<div> <div class="tab-page-content">
<!-- 搜索区域 --> <!-- 搜索区域 -->
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="80px"> <el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="80px">
<el-form-item label="编号/名称" prop="roleName"> <el-form-item label="赛事编号" prop="matchNumStr">
<el-input v-model="queryParams.roleName" placeholder="请输入集合编号/球队名称" clearable style="width: 240px" <el-input v-model="queryParams.matchNumStr" placeholder="请输入赛事编号" clearable style="width: 240px"
@keyup.enter="handleQuery" /> @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="联赛类型" prop="roleKey"> <el-form-item label="联赛类型" prop="leagueAbbName">
<el-select v-model="queryParams.roleKey" @change="handleQuery" style="width: 240px" clearable <el-select v-model="queryParams.leagueAbbName" @change="handleQuery" style="width: 240px" clearable
placeholder="请选择联赛类型"> placeholder="请选择联赛类型">
<el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label" <el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label"
:value="item.value"></el-option> :value="item.value"></el-option>
@ -19,46 +19,69 @@
start-placeholder="开始日期" end-placeholder="结束日期" style="width: 240px"></el-date-picker> start-placeholder="开始日期" end-placeholder="结束日期" style="width: 240px"></el-date-picker>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">查询</el-button> <el-button type="primary" icon="Search" @click="handleQuery" :loading="loading">查询</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button> <el-button icon="Refresh" @click="resetQuery" :loading="loading">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<!--loading-->
<div
v-if="loading"
v-loading="loading"
class="loading-page"
element-loading-text="正在加载..."
style="width: 100%; height: calc(100vh - 250px)"
></div>
<div v-else-if="roleList.length && !loading">
<!-- 表格数据 -->
<el-table v-loading="loading" :data="roleList">
<el-table-column label="赛事编号" prop="matchNumStr" />
<el-table-column label="联赛" prop="leagueAllName" :show-overflow-tooltip="true" />
<el-table-column label="主队" prop="homeTeamAllName" :show-overflow-tooltip="true" />
<el-table-column label="客队" prop="awayTeamAllName"/>
<el-table-column label="固定奖金" prop="matchId" >
<template #default="scope">
<el-button link type="primary" @click="handleJumpLink(scope.row)">查看</el-button>
</template>
</el-table-column>
<el-table-column label="比赛开始时间" align="center" prop="matchDateTime">
<template #default="scope">
<span>{{ parseTime(scope.row.matchDateTime) }}</span>
</template>
</el-table-column>
<!-- <el-table-column label="报告状态" prop="reportSatus">
<template #default="scope">
<el-tag v-if="scope.row.reportSatus === 1" type="success">已生成</el-tag>
<el-tag v-else>未生成</el-tag>
</template>
</el-table-column> -->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<span v-if="scope.row.scriptDetail" :class="['flex-row cursor-pointer tc-view-time mr-8', scope.row.scriptDetail.sciptStatus != 1 && 'tc-view-time-disabled']" @click="handleView(scope.row, 'video')">
脚本结果<br/>
{{ scope.row.scriptDetail.sciptStatus === 1? timerToStr(scope.row.scriptDetail.scriptTime, 'HH:mm') : '待' }}更新
</span>
<span v-if="scope.row.scriptDetail" :class="['flex-row cursor-pointer tc-view-time', scope.row.scriptDetail.sciptStatus != 1 && 'tc-view-time-disabled']" @click="handleView(scope.row, 'market')">
营销文案<br/>
{{ scope.row.scriptDetail.sciptStatus === 1? timerToStr(scope.row.scriptDetail.marketTime, 'HH:mm') : '待' }}更新
</span>
</template>
</el-table-column>
</el-table>
<!-- 表格数据 --> <!-- 分页区域 -->
<el-table v-loading="loading" :data="roleList"> <pagination :show="total > 0" :total="total" v-model:page="queryParams.pageNum"
<el-table-column label="赛事编号" prop="matchNumStr" /> v-model:limit="queryParams.pageSize" @pagination="getList" />
<el-table-column label="联赛" prop="awayTeamAllName" :show-overflow-tooltip="true" /> </div>
<el-table-column label="主队" prop="homeTeamAllName" :show-overflow-tooltip="true" /> <lz-page-empty v-else-if="!loading" :type="'2'">
<el-table-column label="客队" prop="awayTeamAllName"/> <lz-svg-icon icon-class="empty2" style="font-size: 312px;"/>
<el-table-column label="固定奖金" prop="matchId" > </lz-page-empty>
<template #default="scope">
<el-button link type="primary" @click="handleJumpLink(scope.row)">查看</el-button>
</template>
</el-table-column>
<el-table-column label="比赛开始时间" align="center" prop="matchDateTime">
<template #default="scope">
<span>{{ parseTime(scope.row.matchDateTime) }}</span>
</template>
</el-table-column>
<el-table-column label="比赛状态" prop="matchStatus"/>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="查看" placement="top" v-if="scope.row.roleId !== 1">
<el-button link type="primary" icon="view" @click="handleView(scope.row)"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<!-- 分页区域 -->
<pagination :show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
</div> </div>
</template> </template>
<script setup name="Role"> <script setup name="Role">
import { bbInfo } from "@/api/tc/eventAnalysisReport" import { bbInfo, bbInfoSelectDistinctLeagueAbbNames } from "@/api/tc/eventAnalysisReport"
import { jumpLink } from "@/utils/tc" import { jumpLink } from "@/utils/tc"
import { timerToStr } from "@/utils/timer"
import { onMounted } from "vue" import { onMounted } from "vue"
const router = useRouter() const router = useRouter()
@ -70,39 +93,44 @@ const total = ref(0)
const dateRange = ref([]) const dateRange = ref([])
/** 数据范围选项*/ /** 数据范围选项*/
const dataScopeOptions = ref([ const dataScopeOptions = ref([])
{ value: "1", label: "全部数据权限" },
{ value: "2", label: "自定数据权限" },
{ value: "3", label: "本部门数据权限" },
{ value: "4", label: "本部门及以下数据权限" },
{ value: "5", label: "仅本人数据权限" }
])
const data = reactive({ const data = reactive({
form: {}, form: {},
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
roleName: undefined, matchNumStr: undefined,
roleKey: undefined, leagueAbbName: undefined,
status: undefined
}, },
rules: {}, rules: {},
}) })
const { queryParams } = toRefs(data) const { queryParams } = toRefs(data)
/** 获取联赛类型 */
function getLeagueAbbNames() {
bbInfoSelectDistinctLeagueAbbNames().then(response => {
dataScopeOptions.value = response.rows ? response.rows.map(item => ({ value: item, label: item })) : []
})
}
/** 跳转链接 */ /** 跳转链接 */
function handleJumpLink(row) { function handleJumpLink(row) {
jumpLink(row.matchId, 2) jumpLink(row.matchId, 2)
} }
/** 查看详情 */ /** 查看详情 */
function handleView(row) { function handleView(row, type) {
if (!row.scriptDetail ||row.scriptDetail.sciptStatus != 1) {
return
}
// window.open(`/#/tc/videoScript/detail?id=${row.matchId}`)
router.push({ router.push({
path: '/tc/videoScript/detail', path: '/tc/videoScript/detail',
query: { query: {
id: row.matchId id: row.matchId,
type,
} }
}) })
} }
@ -110,7 +138,15 @@ function handleView(row) {
/** 查询角色列表 */ /** 查询角色列表 */
function getList() { function getList() {
loading.value = true loading.value = true
bbInfo(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => { const data = { ...queryParams.value }
if (dateRange.value && dateRange.value[0] && dateRange.value[1]) {
data.beginTime = dateRange.value[0]
data.endTime = dateRange.value[1]
} else {
data.beginTime = undefined
data.endTime = undefined
}
bbInfo(data).then(response => {
roleList.value = response.rows roleList.value = response.rows
total.value = response.total total.value = response.total
}).finally(() => { }).finally(() => {
@ -131,6 +167,9 @@ function resetQuery() {
handleQuery() handleQuery()
} }
onMounted(() => { onMounted(() => {
//
getLeagueAbbNames()
//
getList() getList()
}) })
</script> </script>

View File

@ -1,13 +1,13 @@
<template> <template>
<div> <div class="tab-page-content">
<!-- 搜索区域 --> <!-- 搜索区域 -->
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="80px"> <el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="80px">
<el-form-item label="编号/名称" prop="roleName"> <el-form-item label="赛事编号" prop="matchNumStr">
<el-input v-model="queryParams.roleName" placeholder="请输入集合编号/球队名称" clearable style="width: 240px" <el-input v-model="queryParams.matchNumStr" placeholder="请输入赛事编号" clearable style="width: 240px"
@keyup.enter="handleQuery" /> @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="联赛类型" prop="roleKey"> <el-form-item label="联赛类型" prop="leagueAbbName">
<el-select v-model="queryParams.roleKey" @change="handleQuery" style="width: 240px" clearable placeholder="请选择联赛类型"> <el-select v-model="queryParams.leagueAbbName" @change="handleQuery" style="width: 240px" clearable placeholder="请选择联赛类型">
<el-option <el-option
v-for="item in dataScopeOptions" v-for="item in dataScopeOptions"
:key="item.value" :key="item.value"
@ -22,50 +22,73 @@
start-placeholder="开始日期" end-placeholder="结束日期" style="width: 240px"></el-date-picker> start-placeholder="开始日期" end-placeholder="结束日期" style="width: 240px"></el-date-picker>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">查询</el-button> <el-button type="primary" icon="Search" @click="handleQuery" :loading="loading">查询</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button> <el-button icon="Refresh" @click="resetQuery" :loading="loading">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<!--loading-->
<div
v-if="loading"
v-loading="loading"
class="loading-page"
element-loading-text="正在加载..."
style="width: 100%; height: calc(100vh - 250px)"
></div>
<div v-else-if="roleList.length && !loading">
<!-- 表格数据 -->
<el-table v-loading="loading" :data="roleList">
<el-table-column label="赛事编号" prop="matchNumStr" />
<el-table-column label="联赛" prop="leagueAllName" :show-overflow-tooltip="true"/>
<el-table-column label="主队" prop="homeTeamAllName" :show-overflow-tooltip="true" />
<el-table-column label="客队" prop="awayTeamAbbName" />
<el-table-column label="固定奖金" prop="matchId">
<template #default="scope">
<el-button link type="primary" @click="handleJumpLink(scope.row)">查看</el-button>
</template>
</el-table-column>
<el-table-column label="比赛开始时间" align="center" prop="matchDateTime">
<template #default="scope">
<span>{{ parseTime(scope.row.matchDateTime) }}</span>
</template>
</el-table-column>
<!-- <el-table-column label="报告状态" prop="reportSatus">
<template #default="scope">
<el-tag v-if="scope.row.reportSatus === 1" type="success">已生成</el-tag>
<el-tag v-else>未生成</el-tag>
</template>
</el-table-column> -->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<span v-if="scope.row.scriptDetail" :class="['flex-row cursor-pointer tc-view-time mr-8', scope.row.scriptDetail.sciptStatus != 1 && 'tc-view-time-disabled']" @click="handleView(scope.row, 'video')">
脚本结果<br/>
{{ scope.row.scriptDetail.sciptStatus === 1? timerToStr(scope.row.scriptDetail.scriptTime, 'HH:mm') : '待' }}更新
</span>
<span v-if="scope.row.scriptDetail" :class="['flex-row cursor-pointer tc-view-time', scope.row.scriptDetail.sciptStatus != 1 && 'tc-view-time-disabled']" @click="handleView(scope.row, 'market')">
营销文案<br/>
{{ scope.row.scriptDetail.sciptStatus === 1? timerToStr(scope.row.scriptDetail.marketTime, 'HH:mm') : '待' }}更新
</span>
</template>
</el-table-column>
</el-table>
<!-- 表格数据 --> <!-- 分页区域 -->
<el-table v-loading="loading" :data="roleList"> <pagination
<el-table-column label="赛事编号" prop="matchNumStr" /> :show="total > 0"
<el-table-column label="联赛" prop="leagueAllName" :show-overflow-tooltip="true"/> :total="total"
<el-table-column label="主队" prop="homeTeamAllName" :show-overflow-tooltip="true" /> v-model:page="queryParams.pageNum"
<el-table-column label="客队" prop="awayTeamAbbName" /> v-model:limit="queryParams.pageSize"
<el-table-column label="固定奖金" prop="matchId"> @pagination="getList" />
<template #default="scope"> </div>
<el-button link type="primary" @click="handleJumpLink(scope.row)">查看</el-button> <lz-page-empty v-else-if="!loading" :type="'2'">
</template> <lz-svg-icon icon-class="empty2" style="font-size: 312px;"/>
</el-table-column> </lz-page-empty>
<el-table-column label="比赛开始时间" align="center" prop="matchDateTime">
<template #default="scope">
<span>{{ parseTime(scope.row.matchDateTime) }}</span>
</template>
</el-table-column>
<el-table-column label="比赛状态" prop="matchStatus" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="查看" placement="top" v-if="scope.row.roleId !== 1">
<el-button link type="primary" icon="view" @click="handleView(scope.row)"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<!-- 分页区域 -->
<pagination
:show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList" />
</div> </div>
</template> </template>
<script setup name="Role"> <script setup name="Role">
import { Info } from "@/api/tc/eventAnalysisReport" import { Info, infoSelectDistinctLeagueAbbNames } from "@/api/tc/eventAnalysisReport"
import { jumpLink } from "@/utils/tc" import { jumpLink } from "@/utils/tc"
import { timerToStr } from "@/utils/timer"
import { onMounted } from "vue" import { onMounted } from "vue"
const router = useRouter() const router = useRouter()
@ -77,46 +100,59 @@ const total = ref(0)
const dateRange = ref([]) const dateRange = ref([])
/** 数据范围选项*/ /** 数据范围选项*/
const dataScopeOptions = ref([ const dataScopeOptions = ref([])
{ value: "1", label: "全部数据权限" },
{ value: "2", label: "自定数据权限" },
{ value: "3", label: "本部门数据权限" },
{ value: "4", label: "本部门及以下数据权限" },
{ value: "5", label: "仅本人数据权限" }
])
const data = reactive({ const data = reactive({
form: {}, form: {},
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
roleName: undefined, matchNumStr: undefined,
roleKey: undefined, leagueAbbName: undefined,
status: undefined
}, },
rules: {}, rules: {},
}) })
const { queryParams } = toRefs(data) const { queryParams } = toRefs(data)
/** 获取联赛类型 */
function getLeagueAbbNames() {
infoSelectDistinctLeagueAbbNames().then(response => {
dataScopeOptions.value = response.rows ? response.rows.map(item => ({ value: item, label: item })) : []
})
}
/** 跳转链接 */ /** 跳转链接 */
function handleJumpLink(row) { function handleJumpLink(row) {
jumpLink(row.matchId, 1) jumpLink(row.matchId, 1)
} }
/** 查看详情 */ /** 查看详情 */
function handleView(row) { function handleView(row, type) {
if (!row.scriptDetail ||row.scriptDetail.sciptStatus != 1) {
return
}
// window.open(`/#/tc/videoScript/detail?id=${row.matchId}`)
router.push({ router.push({
path: '/tc/videoScript/detail', path: '/tc/videoScript/detail',
query: { query: {
id: row.matchId id: row.matchId,
type
} }
}) })
} }
/** 查询角色列表 */ /** 查询角色列表 */
function getList() { function getList() {
loading.value = true loading.value = true
Info(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => { const data = { ...queryParams.value }
if (dateRange.value && dateRange.value[0] && dateRange.value[1]) {
data.beginTime = dateRange.value[0]
data.endTime = dateRange.value[1]
} else {
data.beginTime = undefined
data.endTime = undefined
}
Info(data).then(response => {
roleList.value = response.rows roleList.value = response.rows
total.value = response.total total.value = response.total
}).finally(() => { }).finally(() => {
@ -138,6 +174,9 @@ function resetQuery() {
} }
onMounted(() => { onMounted(() => {
//
getLeagueAbbNames()
//
getList() getList()
}) })
</script> </script>

View File

@ -1,30 +1,53 @@
<template> <template>
<div class="app-container" v-loading="loading"> <div class="app-container" v-loading="loading">
<el-row :gutter="20"> <!--顶部-->
<div class="flex align-center mb-20">
<el-icon @click="proxy.$router.go(-1)" class="mr-6 cursor">
<ArrowLeftBold />
</el-icon>
{{ data && data.scriptTime ? timerToStr(data.scriptTime, 'YYYY-MM-DD HH:mm:ss') : '' }}
</div>
<el-row :gutter="20" v-if="!loading && data && (type === 'video' ? data.videoScript : data.marketScript)" >
<el-col :xs="24" :sm="24" :md="24" :lg="24"> <el-col :xs="24" :sm="24" :md="24" :lg="24">
<el-card class="update-log"> <el-card class="update-log">
<template v-slot:header> <template v-slot:header>
<div class="clearfix"> <div class="clearfix">
<span>短视频脚本 {{ data && data.scriptTime }}</span> <span>{{ type === 'video' ? '短视频脚本' : '营销文案' }} {{ data && data.matchCode }}</span>
</div> </div>
</template> </template>
<div class="body"> <div class="body">
<p v-if="!loading && data && data.report"> <MdPreview
{{ data && data.report }} ref="editorRef"
</p> editorId="preview-only"
<el-empty v-else description="暂无数据"></el-empty> :modelValue="type === 'video' ? data.videoScript : data.marketScript"
class="maxkb-md"
/>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
<lz-page-empty
v-else
:type="'4'"
:text1="type === 'video' ? '暂无短视频脚本' : '暂无营销文案'"
text2="请稍后再试..."
>
<lz-svg-icon icon-class="empty1" style="font-size: 312px;"/>
</lz-page-empty>
</div> </div>
</template> </template>
<script setup name="videoScriptDetail"> <script setup name="videoScriptDetail">
import { scriptDetail } from '@/api/tc/videoScript' import { scriptDetail } from '@/api/tc/videoScript'
import MdPreview from '@/components/Markdown/MdPreview'
import { timerToStr } from "@/utils/timer"
const route = useRoute() const route = useRoute()
let { proxy } = getCurrentInstance()
const editorRef = ref(null)
const id = ref(0) const id = ref(0)
const type = ref('') // video || market
const data = ref({}) const data = ref({})
const loading = ref(false) const loading = ref(false)
@ -38,8 +61,9 @@ function getDetail() {
} }
onMounted(() => { onMounted(() => {
if (route.query.id) { if (route.query.id && route.query.type) {
id.value = route.query.id id.value = route.query.id
type.value = route.query.type
getDetail() getDetail()
} }
}) })

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick"> <el-tabs v-model="activeName" class="res-el-tab" @tab-click="handleClick">
<el-tab-pane label="竞彩足球" name="soccer"><soccer /></el-tab-pane> <el-tab-pane label="竞彩足球" name="soccer"><soccer /></el-tab-pane>
<el-tab-pane label="竞彩篮球" name="basketball"><basketball /></el-tab-pane> <el-tab-pane label="竞彩篮球" name="basketball"><basketball /></el-tab-pane>
</el-tabs> </el-tabs>
@ -8,13 +8,30 @@
</template> </template>
<script setup name="VideoScript"> <script setup name="VideoScript">
import { ref } from 'vue' import { ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import soccer from './components/soccer.vue' import soccer from './components/soccer.vue'
import basketball from './components/basketball.vue' import basketball from './components/basketball.vue'
const activeName = ref('soccer')
const route = useRoute()
const router = useRouter()
// URLactiveName'soccer'
const activeName = ref(route.query.tab || 'soccer')
// activeNameURL
watch(activeName, (newVal) => {
router.replace({
query: {
...route.query,
tab: newVal
}
})
})
const handleClick = (tab, event) => { const handleClick = (tab, event) => {
console.log(tab, event) console.log('点击标签页:', tab.props.name)
} }
</script> </script>

View File

@ -844,7 +844,7 @@ function tagChange(tagIcon) {
} }
.select-item.sortable-chosen { .select-item.sortable-chosen {
border: 1px dashed #409eff; border: 1px dashed #3067EF;
} }
.select-line-icon { .select-line-icon {
@ -878,7 +878,7 @@ function tagChange(tagIcon) {
top: 0; top: 0;
left: 0; left: 0;
cursor: pointer; cursor: pointer;
background: #409eff; background: #3067EF;
z-index: 1; z-index: 1;
border-radius: 0 0 6px 0; border-radius: 0 0 6px 0;
justify-content: center; justify-content: center;

View File

@ -307,7 +307,7 @@ onMounted(() => {
</script> </script>
<style lang='scss'> <style lang='scss'>
$lighterBlue: #409EFF; $lighterBlue: #3067EF;
.container { .container {
position: relative; position: relative;

View File

@ -42,6 +42,14 @@ export default defineConfig(({ mode, command }) => {
build: { build: {
// https://vite.dev/config/build-options.html // https://vite.dev/config/build-options.html
sourcemap: command === 'build' ? false : 'inline', sourcemap: command === 'build' ? false : 'inline',
minify: 'terser', // 启用 terser 压缩
terserOptions: {
compress: {
pure_funcs: ['console.log'], // 只删除 console.log
//drop_console: true, // 删除所有 console
drop_debugger: true, // 删除 debugger
}
},
outDir: 'dist', outDir: 'dist',
assetsDir: 'assets', assetsDir: 'assets',
chunkSizeWarningLimit: 2000, chunkSizeWarningLimit: 2000,