feat: 查位次

master
xjs 2025-03-11 18:09:06 +08:00
parent be40ec0395
commit d1f2b31260
44 changed files with 2136 additions and 229 deletions

View File

@ -44,7 +44,7 @@ const subMenus = [
{ {
id: 5, id: 5,
name: '查位次', name: '查位次',
path: '/pages-sub/home/rank/index', path: '/pages-evaluation-sub/rank/index',
icon: '/static/images/home/rank.svg', icon: '/static/images/home/rank.svg',
}, },
// //

View File

@ -0,0 +1,121 @@
<template>
<CheckboxGroup v-model="defValue" checked-color="#1580FF" @change="handleChange" v-bind="$attrs">
<Checkbox
v-for="item in list"
:key="item[valueKey]"
:name="item[valueKey]"
cell
shape="button"
class="custom-checkbox"
:style="checkboxStyle"
>
{{ item[labelKey] }}
</Checkbox>
</CheckboxGroup>
</template>
<script lang="ts" setup>
import Checkbox from './Checkbox.vue'
import CheckboxGroup from './CheckboxGroup.vue'
const props = defineProps({
list: {
type: Array,
default: () => [],
},
labelKey: {
type: String,
default: 'name',
},
valueKey: {
type: String,
default: 'code',
},
defaultValue: {
type: Array<string>,
default: () => [],
},
width: {
type: [String, Number],
default: '216rpx',
},
height: {
type: [String, Number],
default: '60rpx',
},
})
defineOptions({
options: {
styleIsolation: 'shared',
},
})
const emits = defineEmits(['change'])
const defValue = ref<string[]>([])
//
onMounted(() => {
if (props.defaultValue?.length) {
defValue.value = [...props.defaultValue]
}
})
const handleChange = (val: unknown) => {
defValue.value = val as string[]
emits('change', val)
}
watch(
() => props.defaultValue,
(newVal) => {
defValue.value = [...newVal]
},
)
//
const checkboxStyle = computed(() => {
const width = typeof props.width === 'number' ? `${props.width}rpx` : props.width
const height = typeof props.height === 'number' ? `${props.height}rpx` : props.height
return {
'--checkbox-width': width,
'--checkbox-height': height,
}
})
</script>
<style lang="scss" scoped>
:deep(.custom-checkbox) {
//
--checkbox-width: 216rpx;
--checkbox-height: 60rpx;
--checkbox-bg: #f7f8fa;
--checkbox-radius: 8rpx;
.checkbox {
width: var(--checkbox-width);
height: var(--checkbox-height);
min-width: var(--checkbox-width);
background-color: var(--checkbox-bg);
border-radius: var(--checkbox-radius);
display: flex;
align-items: center;
justify-content: center;
border: 2rpx solid var(--checkbox-bg);
}
.checkbox__icon {
display: none;
}
}
:deep(.checkbox-group) {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
padding: 32rpx 16rpx 16rpx;
}
:deep(.checkbox-active) {
border-color: #1580ff !important;
.checkbox__label {
color: #1580ff !important;
}
}
</style>

View File

@ -0,0 +1,133 @@
<template>
<view
class="checkbox"
:class="{
'checkbox--disabled': isDisabled,
'checkbox-active': isChecked,
'checkbox-disabled': isDisabled,
}"
@click="handleClick"
>
<view class="checkbox__icon" :class="{ 'checkbox__icon--checked': isChecked }">
<text v-if="isChecked" class="i-carbon-checkmark checkbox__icon-check"></text>
</view>
<view class="checkbox__label">
<slot>{{ label }}</slot>
</view>
</view>
</template>
<script lang="ts" setup>
import { computed, inject } from 'vue'
const props = defineProps({
name: {
type: [String, Number],
required: true,
},
label: {
type: String,
default: '',
},
disabled: {
type: Boolean,
default: false,
},
})
const emit = defineEmits(['change'])
interface CheckboxGroupContext {
modelValue: ComputedRef<any[]>
disabled: ComputedRef<boolean>
max: ComputedRef<number>
selectedCount: ComputedRef<number>
toggleOption: (option: { value: string | number }) => void
}
// checkbox group
const checkboxGroup = inject<CheckboxGroupContext>('checkboxGroup', {
modelValue: computed(() => []),
disabled: computed(() => false),
max: computed(() => 0),
selectedCount: computed(() => 0),
toggleOption: () => {},
})
//
const isChecked = computed(() => {
const modelValue = checkboxGroup.modelValue.value
return modelValue.includes(props.name)
})
//
const isDisabled = computed(() => {
const max = checkboxGroup.max.value
const selectedCount = checkboxGroup.selectedCount.value
// group
return (
props.disabled ||
checkboxGroup.disabled.value ||
(max > 0 && !isChecked.value && selectedCount >= max)
)
})
//
const handleClick = () => {
if (isDisabled.value) return
checkboxGroup.toggleOption({
value: props.name,
})
}
</script>
<style scoped>
.checkbox {
display: inline-flex;
align-items: center;
cursor: pointer;
font-size: 28rpx;
}
.checkbox--disabled {
cursor: not-allowed;
opacity: 0.5;
}
.checkbox__icon {
width: 40rpx;
height: 40rpx;
border: 2rpx solid #dcdfe6;
border-radius: 4rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 8rpx;
transition: all 0.2s;
}
.checkbox__icon--checked {
background-color: #0083ff;
border-color: #0083ff;
}
.checkbox__icon-check {
color: #fff;
font-size: 32rpx;
}
.checkbox__label {
line-height: 1;
}
.checkbox-active {
background-color: #0083ff;
border-color: #0083ff;
}
.checkbox-disabled {
opacity: 0.5;
cursor: not-allowed !important;
}
</style>

View File

@ -0,0 +1,69 @@
<template>
<view class="checkbox-group">
<slot></slot>
</view>
</template>
<script lang="ts" setup>
import { provide, computed } from 'vue'
const props = defineProps({
modelValue: {
type: Array,
default: () => [],
},
max: {
type: Number,
default: 0,
},
disabled: {
type: Boolean,
default: false,
},
})
const emit = defineEmits(['update:modelValue', 'change'])
//
const innerValue = computed(() => props.modelValue)
//
const toggleOption = (option: { label: string; value: string | number }) => {
const currentValue = innerValue.value
const index = currentValue.indexOf(option.value)
const newValue = [...currentValue]
if (index === -1) {
if (props.max && currentValue.length >= props.max) {
uni.showToast({
title: `最多只能选择${props.max}`,
icon: 'none',
})
return
}
newValue.push(option.value)
} else {
newValue.splice(index, 1)
}
emit('update:modelValue', newValue)
emit('change', newValue)
}
// checkbox
provide('checkboxGroup', {
modelValue: computed(() => props.modelValue),
disabled: computed(() => props.disabled),
max: computed(() => props.max),
selectedCount: computed(() => props.modelValue.length),
toggleOption,
})
</script>
<style scoped lang="scss">
.checkbox-group {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
</style>

View File

@ -0,0 +1,158 @@
<template>
<view class="drop-menu" ref="dropMenuRef">
<view class="drop-menu__bar">
<view
v-for="(item, index) in titles"
:key="index"
class="drop-menu__item"
:class="{ 'drop-menu__item--active': index === activeIndex }"
@click="handleTitleClick(index)"
>
<text class="drop-menu__title">{{ item }}</text>
<text
class="drop-menu__arrow i-carbon-chevron-down"
:class="{ 'drop-menu__arrow--active': index === activeIndex }"
></text>
</view>
</view>
<view class="drop-menu__content-wrapper">
<slot></slot>
</view>
<view
v-if="activeIndex !== -1"
class="drop-menu__mask"
:style="{ top: maskTop }"
@click="closeDropMenu"
></view>
</view>
</template>
<script lang="ts" setup>
import { ref, provide } from 'vue'
const props = defineProps({
zIndex: {
type: Number,
default: 10,
},
duration: {
type: Number,
default: 200,
},
direction: {
type: String,
default: 'down',
},
})
//
const titles = ref<string[]>([])
//
const activeIndex = ref(-1)
const maskTop = ref('88px')
//
const addTitle = (title: string) => {
titles.value.push(title)
}
const instance = getCurrentInstance()
const dropMenuRef = ref()
//
const handleTitleClick = (index: number) => {
//
if (activeIndex.value === index) {
activeIndex.value = -1
} else {
//
activeIndex.value = index
}
const query = uni.createSelectorQuery().in(instance.proxy)
query
.select('.drop-menu')
.boundingClientRect((data: { top: number }) => {
maskTop.value = `${data.top}px`
})
.exec()
}
//
const closeDropMenu = () => {
activeIndex.value = -1
}
//
provide('dropMenu', {
activeIndex,
addTitle,
closeDropMenu,
zIndex: props.zIndex,
duration: props.duration,
direction: props.direction,
titles, // titles
})
</script>
<style scoped lang="scss">
.drop-menu {
position: relative;
background: #fff;
z-index: 10;
}
.drop-menu__bar {
position: relative;
display: flex;
height: 88rpx;
background: #fff;
z-index: 12;
}
.drop-menu__item {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.drop-menu__item--active {
color: #0083ff;
}
.drop-menu__title {
font-size: 28rpx;
max-width: 80%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.drop-menu__arrow {
font-size: 20rpx;
margin-left: 8rpx;
transition: transform 0.2s;
}
.drop-menu__arrow--active {
transform: rotate(180deg);
}
.drop-menu__content-wrapper {
position: relative;
width: 100%;
}
.drop-menu__mask {
position: fixed;
width: 100%;
left: 0;
right: 0;
top: 88rpx;
bottom: 0;
background: rgba(0, 0, 0, 0.3);
z-index: 9;
}
</style>

View File

@ -0,0 +1,202 @@
<template>
<view
class="drop-menu-item"
:class="[customClass, { 'drop-menu-item--show': isShow }]"
:style="{
'z-index': zIndex,
'transition-duration': `${duration}ms`,
}"
>
<view class="drop-menu-item__wrapper" :class="{ 'drop-menu-item__wrapper--show': isShow }">
<!-- 默认选项列表 -->
<scroll-view v-if="!$slots.default" scroll-y class="drop-menu-item__content">
<view class="drop-menu-item__option-list">
<view
v-for="(option, index) in options"
:key="index"
class="drop-menu-item__option"
:class="{ 'drop-menu-item__option--active': isOptionActive(option) }"
@click="handleOptionClick(option)"
>
<text class="drop-menu-item__text">{{ getOptionText(option) }}</text>
<text v-if="isOptionActive(option)" class="drop-menu-item__icon"></text>
</view>
</view>
</scroll-view>
<!-- 自定义内容插槽 -->
<view v-else class="drop-menu-item__custom-content">
<slot></slot>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import { ref, inject, onMounted, computed, watch } from 'vue'
const props = defineProps({
modelValue: {
type: [String, Number, Object],
default: '',
},
title: {
type: String,
required: true,
},
options: {
type: Array,
default: () => [],
},
labelKey: {
type: String,
default: 'text',
},
valueKey: {
type: String,
default: 'value',
},
customClass: {
type: String,
default: '',
},
})
const emit = defineEmits(['update:modelValue', 'change', 'open'])
//
const { activeIndex, addTitle, closeDropMenu, zIndex, duration, direction, titles } = inject(
'dropMenu',
) as any
//
const itemIndex = ref(-1)
//
const isShow = computed(() => activeIndex.value === itemIndex.value)
//
watch(isShow, (newVal) => {
if (newVal) {
emit('open')
}
})
//
const getOptionText = (option: any) => {
if (typeof option === 'object' && props.labelKey) {
return option[props.labelKey]
}
return option
}
//
const getOptionValue = (option: any) => {
if (typeof option === 'object' && props.valueKey) {
return option[props.valueKey]
}
return option
}
//
const isOptionActive = (option: any) => {
const optionValue = getOptionValue(option)
return props.modelValue === optionValue
}
//
const handleOptionClick = (option: any) => {
const value = getOptionValue(option)
emit('update:modelValue', value)
emit('change', value)
closeDropMenu()
}
//
onMounted(() => {
//
itemIndex.value = titles.value.length
//
addTitle(props.title)
})
//
watch(
() => props.title,
(newTitle) => {
//
if (titles.value[itemIndex.value] !== newTitle) {
titles.value[itemIndex.value] = newTitle
}
},
{ immediate: false },
)
</script>
<style scoped>
.drop-menu-item {
position: relative;
width: 100%;
}
.drop-menu-item__wrapper {
position: absolute;
left: 0;
right: 0;
top: 0;
background: #fff;
transform: translateY(-5px);
transition: all 0.25s ease;
overflow: hidden;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
opacity: 0;
visibility: hidden;
z-index: 11;
}
.drop-menu-item__wrapper--show {
transform: translateY(0);
opacity: 1;
visibility: visible;
}
.drop-menu-item__content {
max-height: 400rpx;
}
.drop-menu-item__custom-content {
width: 100%;
background: #fff;
transform-origin: top;
}
.drop-menu-item__option-list {
padding: 12rpx 0;
}
.drop-menu-item__option {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 32rpx;
line-height: 1.2;
cursor: pointer;
}
.drop-menu-item__option:active {
background-color: #f2f2f2;
}
.drop-menu-item__option--active {
color: #0083ff;
}
.drop-menu-item__text {
font-size: 28rpx;
}
.drop-menu-item__icon {
font-size: 32rpx;
color: #0083ff;
}
</style>

View File

@ -0,0 +1,205 @@
<template>
<view class="navbar">
<!-- 状态栏占位 -->
<view
v-if="safeAreaInsetTop"
class="status-bar"
:style="{ height: statusBarHeight + 'px', backgroundColor: bgColor }"
></view>
<!-- 导航栏主体 -->
<view
class="navbar-content"
:class="[contentClass, fixed ? 'navbar-fixed' : '', bordered ? 'navbar-border' : '']"
:style="{
backgroundColor: bgColor,
height: navHeight + 'px',
top: fixed ? (safeAreaInsetTop ? statusBarHeight : 0) + 'px' : '0',
}"
>
<!-- 左侧区域 -->
<view class="navbar-left" @click="handleClickLeft">
<view v-if="leftArrow" class="back-icon">
<view class="i-carbon-chevron-left text-[48rpx] text-[#333] font-semibold" />
</view>
<slot name="left"></slot>
</view>
<!-- 中间标题区域 -->
<view class="navbar-title">
<slot name="title">
<text class="title-text">{{ title }}</text>
</slot>
</view>
<!-- 右侧区域 -->
<view class="navbar-right">
<slot name="right"></slot>
</view>
</view>
<!-- 占位元素 -->
<view
v-if="placeholder && fixed"
:style="{
height: `${navHeight}px`,
backgroundColor: bgColor,
}"
></view>
<slot name="background"></slot>
</view>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
const props = defineProps({
title: {
type: String,
default: '',
},
leftArrow: {
type: Boolean,
default: false,
},
fixed: {
type: Boolean,
default: false,
},
placeholder: {
type: Boolean,
default: false,
},
bordered: {
type: Boolean,
default: true,
},
safeAreaInsetTop: {
type: Boolean,
default: true,
},
bgColor: {
type: String,
default: '#ffffff',
},
contentClass: {
type: String,
default: 'justify-between',
},
})
const emit = defineEmits(['clickLeft'])
//
const systemInfo = uni.getSystemInfoSync()
const statusBarHeight = systemInfo.statusBarHeight || 0
//
const navHeight = computed(() => {
//
const { platform, screenWidth } = systemInfo
// pxrpx
const ratio = 750 / screenWidth
//
if (platform === 'ios') {
return 88 / ratio // iOS 44ptpx
} else if (platform === 'android') {
return 96 / ratio // Android 48dppx
} else {
return 88 / ratio //
}
})
const handleClickLeft = () => {
emit('clickLeft')
}
</script>
<style scoped>
.navbar {
width: 100%;
}
.status-bar {
width: 100%;
background-color: inherit;
}
.navbar-content {
width: 100%;
display: flex;
align-items: center;
/* justify-content: space-between; */
padding: 0 32rpx;
box-sizing: border-box;
background-color: #fff;
}
.navbar-fixed {
position: fixed;
left: 0;
width: 100%;
z-index: 99;
}
.navbar-border {
border-bottom: 1rpx solid #eee;
}
.navbar-left {
display: flex;
align-items: center;
height: 100%;
}
.back-icon {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.navbar-title {
/* flex: 1; */
text-align: center;
overflow: hidden;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.title-text {
font-size: 36rpx;
color: #333;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.navbar-right {
display: flex;
align-items: center;
min-width: 100rpx;
justify-content: flex-end;
height: 100%;
}
@font-face {
font-family: 'iconfont';
src: url('data:font/woff2;charset=utf-8;base64,d09GMgABAAAAAAKYAAsAAAAABlAAAAJMAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACCcApcdgE2AiQDCAsGAAQgBYRnBzYbmQXIHpIkBQQKkYCABBEPz2/t/XN3twEbowBkQTxQEQ1RKaKSxEOi0agkJKF5Qvj/f037IFKwlZ2dWU2tJu0EhPwHkBwgOVAclKcvAQpI/v/fz/08XECy+YBymmPQiwIcSmhAY4uSFcgJ+IaxC1zCYwLtRjWSnZ2rGgQWBowLxCPrVBBYllQqNTQ0VISaBXEHtTRNUwW4jb4f/xYEC0kqMzDx6CGrQuKXxKc6Zf7POYQgQHs5kIwjYwEoxK3G/DpRwbi0dlNwKKjAL4lf6vw/R2zVWvTPIwuiCnp2wCRUZ3yJX5pJFVDfByyAFR2AblMAX/OR3t7+zOJi8GyyfzC1uQXLZvtnk/0zyfTy+PvH0/Xp5OzR98/H797/+/fDu3d/3739+/fd+/+nmxvLc5vrS+sry2vz84tLs9Mzc4vzs9NTM/Ozc1OzM3MzU/Mz0wvTU4vTk0tTE8uTEyuT4yv/G0E3XUxv7wwNbu/s9G8fbO9v7+3sb+3ubW4dbO4dbO3vbu4dbO3JzqPFtRE4gEGAX0NBkL+hpCZALkEp5FKUQqE0NHlXJIGrDNAOcEQBCHU+kXT5QNblC7kEv1EK9Y9SB/8o7YYu2m0YXrJLouNIjQJhH+QbVkVZrUQ+YuqzUJdzxPMHhdIj0+hg4o0D8ogj5r5bSoQUxjADz+A8hBDQFEYwh3mommXTul7Vm5ZtqAqJHIdoKCDYDyQ3mCqUG1YKn5+C0s0yiJ/qKVAQedKAhg6Y3mEHJBQaWKnvLVMiiEIxGAY8Aw6HIAhAJmEIzIIOUjLTTAB1taL1QvNq+fYN7QDjcc2okeioaOmy5LFXt3QAAAAA')
format('woff2');
}
.back-text {
font-family: 'iconfont' !important;
font-size: 48rpx;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #333;
}
</style>

View File

@ -0,0 +1,194 @@
<template>
<view class="custom-picker">
<view class="picker-mask" @touchmove.stop.prevent></view>
<picker-view
:value="currentIndex"
:indicator-style="indicatorStyle"
:style="{
border: 'none',
'border-top': 'none',
'border-bottom': 'none',
}"
@change="handleChange"
class="picker-view"
:mask-class="'picker-mask'"
:indicator-class="'picker-indicator'"
>
<picker-view-column class="border-none">
<view
v-for="(item, index) in formattedList"
:key="index"
class="picker-item"
:class="{ 'picker-item-selected': currentIndex[0] === index }"
>
{{ item }}
</view>
</picker-view-column>
</picker-view>
<!-- <view class="picker-indicator-line"></view> -->
</view>
</template>
<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
const props = defineProps({
modelValue: {
type: [String, Number, Object],
default: '',
},
list: {
type: Array,
required: true,
default: () => [],
},
valueKey: {
type: String,
default: '',
},
labelKey: {
type: String,
default: '',
},
indicatorStyle: {
type: String,
default: 'height: 50px;',
},
})
const emit = defineEmits(['update:modelValue', 'change'])
//
const formattedList = computed(() => {
if (!props.list.length) return []
// ['123', '456']
if (typeof props.list[0] !== 'object') {
return props.list
}
// 使labelKey
if (props.labelKey) {
return props.list.map((item) => item[props.labelKey])
}
// 使valueKey
if (props.valueKey) {
return props.list.map((item) => item[props.valueKey])
}
//
return props.list
})
//
const currentIndex = computed(() => {
if (!props.modelValue || !props.list.length) return [0]
let targetValue = props.modelValue
if (typeof props.list[0] === 'object' && props.valueKey) {
targetValue = props.modelValue[props.valueKey]
}
const index = props.list.findIndex((item) => {
if (typeof item === 'object' && props.valueKey) {
return item[props.valueKey] === targetValue
}
return item === targetValue
})
return [index > -1 ? index : 0]
})
//
const handleChange = (e: any) => {
const index = e.detail.value[0]
const selectedItem = props.list[index]
let value = selectedItem
if (typeof selectedItem === 'object' && props.valueKey) {
value = selectedItem[props.valueKey]
}
emit('update:modelValue', value)
emit('change', {
value,
index,
item: selectedItem,
})
}
</script>
<style scoped>
.custom-picker {
width: 100%;
height: 400rpx;
position: relative;
background-color: #fff;
}
.picker-view {
width: 100%;
height: 100%;
}
/* 覆盖picker-view的默认边框 */
.picker-view :deep(.uni-picker-view-indicator),
.picker-view :deep(.uni-picker-view-column),
.picker-view :deep(.uni-picker-view-group) {
border: none !important;
border-top: none !important;
border-bottom: none !important;
}
.picker-mask {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
pointer-events: none;
z-index: 2;
}
.picker-indicator {
height: 112rpx;
}
.picker-indicator-line {
position: absolute;
left: 0;
right: 0;
top: 50%;
margin-top: -40rpx;
height: 112rpx;
pointer-events: none;
z-index: 1;
}
.picker-item {
text-align: center;
font-size: 34rpx;
color: #7c7c7c;
transition: all 0.2s;
display: flex;
justify-content: center;
align-items: center;
}
.picker-item-selected {
color: #000;
font-weight: 500;
transform: scale(1.05);
}
/* 添加触摸反馈 */
.picker-view :deep(.uni-picker-view-wrapper) {
-webkit-overflow-scrolling: touch;
}
.picker-view :deep(.uni-picker-view-content) {
touch-action: pan-y;
}
</style>

View File

@ -0,0 +1,130 @@
export const initRankAreaEchart = ({
echart,
echarts,
xAxisData,
yAxisData,
Score,
currentCount,
areaIndex,
}) => {
echart.value.init(echarts, (chart) => {
let option = {
xAxis: {
type: 'category',
data: xAxisData,
axisLine: {
lineStyle: {
color: '#E5E5E5',
},
},
axisLabel: {
color: '#999999',
},
},
yAxis: {
type: 'value',
show: false,
},
grid: {
containLabel: false,
},
series: [
{
data: yAxisData,
type: 'line',
smooth: 0.6,
smoothMonotone: 'x',
symbol: 'none',
lineStyle: {
width: 2,
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{
offset: 0,
color: 'rgba(30, 231, 255, 1)',
},
{
offset: 0.33,
color: 'rgba(36, 154, 255, 1)',
},
{
offset: 0.66,
color: 'rgba(111, 66, 251, 1)',
},
{
offset: 1,
color: 'rgba(111, 66, 251, 1)',
},
]),
},
areaStyle: {
opacity: 1,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgba(17,126,255,0.16)',
},
{
offset: 1,
color: 'rgba(17,128,255,0)',
},
]),
},
markPoint: {
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#4080FF',
borderColor: '#259BFF',
borderWidth: 2,
},
data: [
{
xAxis: Score,
yAxis: currentCount,
label: {
show: true,
position: 'top',
color: '#4080FF',
fontSize: 12,
},
},
],
},
markArea: {
itemStyle: {
color: 'rgba(64, 128, 255, 0.1)',
},
data: [
[
{
xAxis: areaIndex + 30,
},
{
xAxis: areaIndex - 30,
},
],
],
},
markLine: {
symbol: ['none', 'none'],
lineStyle: {
type: 'dashed',
color: '#4080FF',
width: 1,
opacity: 0.5,
},
data: [
{
xAxis: Score,
label: {
show: false,
},
},
],
},
},
],
}
chart.setOption(option)
})
}

View File

@ -0,0 +1,35 @@
<template>
<CheckGroup :list="regionList" @change="handleChange" label-key="simplename" v-bind="$attrs" />
</template>
<script lang="ts" setup>
import { getRegionInfo } from '@/service/index/api'
import CheckGroup from '@/pages-evaluation-sub/components/check-group/CheckGroup.vue'
defineOptions({
options: {
styleIsolation: 'shared',
},
})
interface Region {
code: string
name: string
parentcode: string
simplename: string
pinyin: string
}
const regionList = ref([])
getRegionInfo().then((res) => {
if (res.code === 200) {
regionList.value = res.result as Region[]
}
})
const emits = defineEmits(['change', 'changeName'])
const handleChange = (val: any) => {
const names = regionList.value.filter((item) => val.includes(item.code)).map((item) => item.name)
emits('changeName', names)
emits('change', val)
}
</script>

View File

@ -0,0 +1,31 @@
<template>
<CheckGroup
:list="infoList"
@change="handleChange"
:default-value="defaultInfo"
value-key="id"
label-key="name"
/>
</template>
<script lang="ts" setup>
import { getUniversityType } from '@/service/index/api'
import CheckGroup from '@/pages-evaluation-sub/components/check-group/CheckGroup.vue'
const infoList = ref()
getUniversityType().then((res) => {
if (res.code === 200) {
infoList.value = res.result as { id: number; name: string }[]
}
})
const defaultInfo = ref<string[]>([])
const emits = defineEmits(['change', 'changeName'])
const handleChange = (val: any) => {
const names = infoList.value.filter((item) => val.includes(item.id)).map((item) => item.name)
emits('changeName', names)
emits('change', val)
}
</script>

View File

@ -0,0 +1,257 @@
<route lang="json5" type="page">
{
layout: 'page',
style: {
navigationStyle: 'custom',
},
usingComponents: {
LEchart: '../uni_modules/lime-echart/components/l-echart/l-echart',
},
componentPlaceholder: {
LEchart: 'view',
},
}
</route>
<template>
<view class="h-screen flex flex-col">
<view class="relative">
<Navbar
safeAreaInsetTop
bg-color="transparent"
:bordered="false"
left-arrow
title="位次查询"
@click-left="navigatorBack"
content-class="justify-between"
></Navbar>
<view class="custom-background h-[200rpx] w-full absolute top-0 left-0 z-[-1]"></view>
</view>
<drop-menu>
<drop-menu-item
:key="1"
:title="searchParams.locationName || '省份'"
custom-class="flex items-center"
>
<Region
:defaultValue="searchParams.locationCode ? [searchParams.locationCode] : []"
:max="1"
@changeName="handleRegionChange"
@change="handleRegionChangeCode"
/>
</drop-menu-item>
<drop-menu-item
:key="2"
:title="searchParams.year || '年份'"
custom-class="flex items-center"
>
<CheckGroup
:list="checkYearList"
:default-value="searchParams.year ? [searchParams.year] : []"
@change="handleYearChange"
labelKey="year"
valueKey="year"
:max="1"
/>
</drop-menu-item>
<drop-menu-item :key="3" title="类别" custom-class="flex items-center">
<UniType
@change="handleUniTypeChange"
:max="1"
:default-value="searchParams.type ? [searchParams.type] : []"
/>
</drop-menu-item>
</drop-menu>
<view class="px-32rpx">
<view class="flex items-center justify-between input-wrapper-class">
<input
v-model="searchParams.Score"
type="number"
placeholder="请输入你的高考分数"
confirm-type="done"
input-mode="numeric"
class="flex-auto"
/>
<view class="text-[#1580FF] text-[24rpx] search-text" @click="handleConfirm"></view>
</view>
<view class="text-[#636363] text-[20rpx] mt-[24rpx]">分数范围{{ betweenScores }}</view>
</view>
<view class="bg-[#F8F8F8] h-[16rpx] mt-[40rpx]"></view>
<view class="pt-[40rpx] px-[32rpx] flex flex-col">
<text class="font-semibold text-[32rpx]">查询结果</text>
<view class="flex flex-col mt-[22rpx]">
<view class="text-[24rpx] text-[#636363]">
位次区间:
<text class="text-[#1580FF]">21559-22548</text>
</view>
<view class="text-[24rpx] text-[#636363]">
建议位次:
<text class="text-[#1580FF]">22204</text>
</view>
<view class="text-[24rpx] text-[#636363]">
同分人数:
<text class="text-[#1580FF]">690</text>
</view>
</view>
</view>
<view class="">
<LEchart ref="echart" class="h-[300rpx]" v-show="!noData"></LEchart>
<view class="flex items-center justify-center flex-col my-[80rpx] relative" v-show="noData">
<image
src="../static/images/no-data.jpg"
mode="scaleToFill"
class="w-[300rpx] h-[300rpx]"
/>
<text class="text-[24rpx] text-[#636363] absolute bottom-[60rpx]">暂无数据</text>
</view>
</view>
<view class="flex flex-col p-[24rpx] bg-[#FEF0F0] text-[#F56C6C] mx-[32rpx] border-class">
<text class="text-[32rpx] font-bold">*说明</text>
<text class="text-[24rpx] mt-[16rpx] text-[22rpx] font-normal">
1.位次查询结果根据各省教育考试院发布的一分一段表计算
</text>
<text class="text-[24rpx] mt-[16rpx] text-[22rpx] font-normal">
2.在正式填报时请以各省教育考试院发布的数据为准本平台数据仅供参考
</text>
</view>
</view>
</template>
<script lang="ts" setup>
import Navbar from '@/pages-evaluation-sub/components/navbar/Navbar.vue'
import DropMenu from '@/pages-evaluation-sub/components/drop-menu/DropMenu.vue'
import DropMenuItem from '@/pages-evaluation-sub/components/drop-menu/DropMenuItem.vue'
import Region from './components/Region.vue'
import UniType from './components/UniType.vue'
import CheckGroup from '@/pages-evaluation-sub/components/check-group/CheckGroup.vue'
// import lEchart from '@/pages-evaluation-sub/uni_modules/lime-echart/components/l-echart/l-echart.vue'
const echarts = require('../uni_modules/lime-echart/static/echarts.min')
import { getScoreSection } from '@/service/index/api'
import { useUserStore } from '@/store'
import { initRankAreaEchart } from '../composable/rankAreaEchart'
const userStore = useUserStore()
const navigatorBack = () => {
uni.navigateBack()
}
const searchParams = ref({
locationCode: userStore.userInfo.estimatedAchievement.provinceCode || '370000',
locationName: userStore.userInfo.estimatedAchievement.provinceName || '山东省',
year: '',
type: '',
Score: '500',
})
const handleConfirm = () => {
getScoreSectionData()
}
const checkYearList = ref([])
const handleRegionChange = (val) => {
searchParams.value.locationName = val.join(',')
}
const handleRegionChangeCode = (val) => {
searchParams.value.locationCode = val[0]
getScoreSectionData()
}
const handleYearChange = (val) => {
let _yearList = []
if (val.length > 1 && val.some((item) => item === '')) {
_yearList = val.filter((item) => item !== '')
} else {
_yearList = val
}
searchParams.value.year = _yearList.join(',')
getScoreSectionData()
}
const handleUniTypeChange = (val) => {
searchParams.value.type = val[0]
getScoreSectionData()
}
const betweenScores = ref('')
const noData = ref(false)
const getScoreSectionData = () => {
getScoreSection(searchParams.value).then((resp) => {
if (resp.code === 200) {
const _result = resp.result as {
betweenScores: string
list: {
type: number
score: number
currentCount: number
cumulativeCount: number
startRank: number
endRank: number
}[]
configList: { yearList: { year: string; check: boolean }[] }
}
checkYearList.value = _result.configList.yearList
betweenScores.value = _result.betweenScores
noData.value = _result.list.length === 0
if (!noData.value) {
const xAxisData = _result.list.map((item) => item.score)
const yAxisData = _result.list.map((item) => item.currentCount)
const areaIndex = xAxisData.findIndex((item) => item === Number(searchParams.value.Score))
const currentCount = _result.list.filter(
(item) => item.score === Number(searchParams.value.Score),
)[0].currentCount
console.log(echart.value, echarts)
initRankAreaEchart({
echart,
echarts,
xAxisData,
yAxisData,
Score: searchParams.value.Score,
currentCount,
areaIndex,
})
}
}
})
}
const echart = ref(null)
onMounted(() => {
getScoreSectionData()
})
</script>
<style lang="scss" scoped>
@import '@/pages-evaluation-sub/styles/navbar-background.scss';
.input-wrapper-class {
border-radius: 8rpx;
border: 2rpx solid #ededed;
padding: 10rpx 24rpx;
margin-top: 48rpx;
.search-text {
border-left: 2rpx solid #ededed;
padding-left: 24rpx;
}
}
.border-class {
border-radius: 8rpx;
border: 2rpx solid #ffeaea;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,13 @@
.custom-background {
background-image: linear-gradient(
173deg,
rgb(177, 221, 250) 0,
rgb(177, 221, 250) 13%,
rgba(255, 255, 255, 1) 80%,
rgba(255, 255, 255, 1) 100%
);
background-position: 50% 50%;
background-origin: padding-box;
background-clip: border-box;
background-size: auto auto;
}

View File

@ -0,0 +1,3 @@
:deep(.z-tabs-bottom) {
border-bottom: 1px solid #f8f8f8;
}

View File

@ -1,13 +1,16 @@
<template> <template>
<view class="badge"> <view class="badge" :class="customClass">
<slot></slot> <slot></slot>
<view <view
v-show="showBadge" v-show="showBadge"
class="badge__content" class="badge__content"
:class="{ :class="[
'badge__content--dot': isDot, {
'badge__content--fixed': !$slots.default, 'badge__content--dot': isDot,
}" 'badge__content--fixed': !$slots.default,
},
customContentClass,
]"
:style="badgeStyle" :style="badgeStyle"
> >
<block v-if="!isDot">{{ finalContent }}</block> <block v-if="!isDot">{{ finalContent }}</block>
@ -43,6 +46,14 @@ const props = defineProps({
type: String, type: String,
default: '#fff', default: '#fff',
}, },
customClass: {
type: String,
default: '',
},
customContentClass: {
type: String,
default: '',
},
}) })
// //
@ -84,6 +95,10 @@ const badgeStyle = computed(() => {
position: relative; position: relative;
display: inline-flex; display: inline-flex;
vertical-align: middle; vertical-align: middle;
//
--badge-size: 32rpx;
--badge-font-size: 20rpx;
--badge-dot-size: 16rpx;
&__content { &__content {
position: absolute; position: absolute;
@ -92,21 +107,21 @@ const badgeStyle = computed(() => {
transform: translate(50%, -50%); transform: translate(50%, -50%);
transform-origin: 100% 0%; transform-origin: 100% 0%;
z-index: 10; z-index: 10;
min-width: 32rpx; min-width: var(--badge-size);
height: 32rpx; height: var(--badge-size);
padding: 0 8rpx; padding: 0 8rpx;
color: #fff; color: #fff;
font-size: 20rpx; font-size: var(--badge-font-size);
line-height: 32rpx; line-height: var(--badge-size);
white-space: nowrap; white-space: nowrap;
text-align: center; text-align: center;
background-color: #ff4d4f; background-color: #ff4d4f;
border-radius: 16rpx; border-radius: calc(var(--badge-size) / 2);
box-shadow: 0 0 0 2rpx #fff; box-shadow: 0 0 0 2rpx #fff;
&--dot { &--dot {
width: 16rpx; width: var(--badge-dot-size);
height: 16rpx; height: var(--badge-dot-size);
padding: 0; padding: 0;
min-width: auto; min-width: auto;
border-radius: 50%; border-radius: 50%;

View File

@ -7,7 +7,7 @@
cell cell
shape="button" shape="button"
class="custom-checkbox" class="custom-checkbox"
custom-label-class="min-w-[152rpx]! h-[76rpx]! rounded-[8rpx]! checkbox-item-border bg-[#f7f8fa]!" :style="checkboxStyle"
> >
{{ item[labelKey] }} {{ item[labelKey] }}
</Checkbox> </Checkbox>
@ -34,6 +34,14 @@ const props = defineProps({
type: Array<string>, type: Array<string>,
default: () => [], default: () => [],
}, },
width: {
type: [String, Number],
default: '216rpx',
},
height: {
type: [String, Number],
default: '60rpx',
},
}) })
defineOptions({ defineOptions({
options: { options: {
@ -61,19 +69,36 @@ watch(
defValue.value = [...newVal] defValue.value = [...newVal]
}, },
) )
//
const checkboxStyle = computed(() => {
const width = typeof props.width === 'number' ? `${props.width}rpx` : props.width
const height = typeof props.height === 'number' ? `${props.height}rpx` : props.height
return {
'--checkbox-width': width,
'--checkbox-height': height,
}
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.custom-checkbox) { :deep(.custom-checkbox) {
//
--checkbox-width: 216rpx;
--checkbox-height: 60rpx;
--checkbox-bg: #f7f8fa;
--checkbox-radius: 8rpx;
.checkbox { .checkbox {
width: 216rpx; width: var(--checkbox-width);
height: 60rpx; height: var(--checkbox-height);
background-color: #f7f8fa; min-width: var(--checkbox-width);
border-radius: 8rpx; background-color: var(--checkbox-bg);
border-radius: var(--checkbox-radius);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
border: 2rpx solid #f7f8fa; border: 2rpx solid var(--checkbox-bg);
} }
.checkbox__icon { .checkbox__icon {
display: none; display: none;
@ -84,9 +109,9 @@ watch(
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 16rpx; gap: 16rpx;
padding: 32rpx 16rpx 16rpx; padding: 32rpx 16rpx 16rpx;
} }
:deep(.checkbox-active) { :deep(.checkbox-active) {
border-color: #1580ff !important; border-color: #1580ff !important;
.checkbox__label { .checkbox__label {

View File

@ -5,63 +5,60 @@
v-for="(column, index) in columns" v-for="(column, index) in columns"
:key="index" :key="index"
class="table-cell" class="table-cell"
:style="{ width: column.width || 'auto' }" :class="[`text-${column.align || 'center'}`]"
:style="{ width: column.width }"
> >
<text>{{ column.name }}</text> <text>{{ column.label }}</text>
</view> </view>
</view> </view>
<view v-for="(item, index) in tableData" :key="index" class="table-row"> <view v-for="(item, index) in data" :key="index" class="table-row">
<view <view
v-for="(column, colIndex) in columns" v-for="(column, colIndex) in columns"
:key="colIndex" :key="colIndex"
class="table-cell" class="table-cell"
:style="{ width: column.width || 'auto' }" :class="[`text-${column.align || 'center'}`]"
:style="{ width: column.width }"
> >
<text>{{ item[column.key] }}</text> <text>{{ item[column.prop] }}</text>
</view> </view>
</view> </view>
<view class="text-center p-[32rpx]" v-show="tableData.length === 0"></view> <view class="text-center p-[32rpx]" v-show="data.length === 0"></view>
</view> </view>
</template> </template>
<script> <script lang="ts" setup>
export default { import { useTable } from './useTable'
props: {
columns: { const props = defineProps<{
type: Array, data: any[]
required: true, }>()
default: () => [],
}, const { columns } = useTable()
tableData: {
type: Array,
required: true,
default: () => [],
},
},
}
</script> </script>
<style scoped> <style scoped>
.table { .table {
overflow: hidden; overflow: hidden;
width: calc(100% - 4rpx); width: 100%;
border: 2rpx solid #eee; border: 2rpx solid #eee;
height: 100%; box-sizing: border-box;
} }
.table-header { .table-header {
display: flex; display: flex;
background-color: #f5f5f5; background-color: #f5f5f5;
font-weight: bold; font-weight: bold;
min-height: 60rpx;
} }
.table-cell { .table-cell {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 16rpx;
font-size: 20rpx; font-size: 24rpx;
color: #333333; color: #333333;
box-sizing: border-box;
} }
.table-header .table-cell { .table-header .table-cell {
@ -75,7 +72,6 @@ export default {
.table-row .table-cell { .table-row .table-cell {
text-align: center; text-align: center;
padding: 16rpx;
} }
.table-row:first-child { .table-row:first-child {
@ -85,4 +81,16 @@ export default {
.table-cell:not(:last-child) { .table-cell:not(:last-child) {
border-right: 1px solid #ddd; border-right: 1px solid #ddd;
} }
.text-left {
justify-content: flex-start;
}
.text-center {
justify-content: center;
}
.text-right {
justify-content: flex-end;
}
</style> </style>

View File

@ -0,0 +1,56 @@
<template>
<view style="display: none">
<!-- 这是一个虚拟组件不需要实际渲染内容 -->
</view>
</template>
<script lang="ts" setup>
import { onMounted } from 'vue'
import { useTableInject } from './useTable'
const props = defineProps<{
prop: string
label: string
width?: string
align?: 'left' | 'center' | 'right'
}>()
const { addColumn } = useTableInject()
onMounted(() => {
addColumn({
prop: props.prop,
label: props.label,
width: props.width,
align: props.align,
})
})
</script>
<style scoped>
.table-cell {
display: flex;
align-items: center;
justify-content: center;
padding: 16rpx;
font-size: 20rpx;
color: #333333;
border-right: 1px solid #ddd;
}
.table-cell:last-child {
border-right: none;
}
.text-left {
justify-content: flex-start;
}
.text-center {
justify-content: center;
}
.text-right {
justify-content: flex-end;
}
</style>

View File

@ -0,0 +1,40 @@
import { inject, provide, ref } from 'vue'
export type Column = {
prop: string
label: string
width?: string
align?: 'left' | 'center' | 'right'
}
type TableContext = {
columns: ReturnType<typeof ref<Column[]>>
addColumn: (column: Column) => void
}
const key = Symbol('table')
export function useTable() {
const columns = ref<Column[]>([])
const addColumn = (column: Column) => {
columns.value.push(column)
}
provide(key, {
columns,
addColumn,
} as TableContext)
return {
columns,
}
}
export function useTableInject() {
const table = inject<TableContext>(key)
if (!table) {
throw new Error('useTable must be used within Table component')
}
return table
}

View File

@ -2,20 +2,26 @@
<view class="flex flex-col p-[32rpx] bg-[#fff] mt-16rpx"> <view class="flex flex-col p-[32rpx] bg-[#fff] mt-16rpx">
<text class="text-[32rpx] font-semibold text-[#333]">院系设置</text> <text class="text-[32rpx] font-semibold text-[#333]">院系设置</text>
<WXXTable :columns="columns" :tableData="tableData.slice(0, 4)" class="my-[24rpx]"></WXXTable> <WXXTable :data="tableData.slice(0, 4)" class="my-[24rpx]">
<wd-button <WXXTableCol prop="name" label="学院" width="30%"></WXXTableCol>
<WXXTableCol prop="major" label="所含专业" width="70%"></WXXTableCol>
</WXXTable>
<button
block block
custom-class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]!" class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]! text-[28rpx]! flex! items-center! justify-center! gap-[12rpx]!"
@click="handleMore" @click="handleMore"
> >
查看全部 查看全部
<wd-icon name="arrow-right"></wd-icon> <view class="i-carbon-chevron-down rotate-270"></view>
</wd-button> </button>
</view> </view>
<MessageBox v-model:show="show" title="院系设置"> <MessageBox v-model:show="show" title="院系设置">
<template> <template>
<scroll-view class="max-h-600rpx mb-[32rpx] overflow-y-auto" :scroll-y="true"> <scroll-view class="max-h-600rpx mb-[32rpx] overflow-y-auto" :scroll-y="true">
<WXXTable :columns="columns" :tableData="tableData"></WXXTable> <WXXTable :data="tableData">
<WXXTableCol prop="name" label="学院" width="30%"></WXXTableCol>
<WXXTableCol prop="major" label="所含专业" width="70%"></WXXTableCol>
</WXXTable>
</scroll-view> </scroll-view>
</template> </template>
</MessageBox> </MessageBox>
@ -24,6 +30,7 @@
<script setup lang="ts"> <script setup lang="ts">
import MessageBox from '../../components/MessageBox.vue' import MessageBox from '../../components/MessageBox.vue'
import WXXTable from '@/pages-sub/components/table/Table.vue' import WXXTable from '@/pages-sub/components/table/Table.vue'
import WXXTableCol from '@/pages-sub/components/table/TableCol.vue'
import { getUniversityListByProvince } from '@/service/index/api' import { getUniversityListByProvince } from '@/service/index/api'
const props = defineProps({ const props = defineProps({
@ -49,10 +56,6 @@ watch(
}, },
) )
const columns = [
{ name: '学院', key: 'name', width: '30%' },
{ name: '所含专业', key: 'major', width: '70%' },
]
const tableData = ref([]) const tableData = ref([])
const show = ref(false) const show = ref(false)
let originTableData = [] let originTableData = []

View File

@ -6,19 +6,27 @@
class="px-[24rpx] py-[8rpx] bg-[#f8f8f8] rounded-[8rpx] flex justify-between items-center text-[24rpx]" class="px-[24rpx] py-[8rpx] bg-[#f8f8f8] rounded-[8rpx] flex justify-between items-center text-[24rpx]"
> >
{{ year }} {{ year }}
<wd-icon name="arrow-down" size="16rpx" custom-class="ml-[80rpx]"></wd-icon> <view class="i-carbon-chevron-down rotate-270"></view>
</view> </view>
<!-- <view <!-- <view
@click="handleShow(2)" @click="handleShow(2)"
class="px-[24rpx] py-[8rpx] bg-[#f8f8f8] rounded-[8rpx] flex justify-between items-center text-[24rpx]" class="px-[24rpx] py-[8rpx] bg-[#f8f8f8] rounded-[8rpx] flex justify-between items-center text-[24rpx]"
> >
{{ batche }} {{ batche }}
<wd-icon name="arrow-down" size="16rpx" custom-class="ml-[80rpx]"></wd-icon> <view class="i-carbon-chevron-down rotate-270"></view>
</view> --> </view>
--->
</view> </view>
<scroll-view class="mt-[38rpx] flex-1 pb-safe"> <scroll-view class="mt-[38rpx] flex-1 pb-safe">
<WXXTable :columns="columns" :tableData="tableData"></WXXTable> <WXXTable :data="tableData">
<WXXTableCol prop="year" label="年份" width="10%"></WXXTableCol>
<WXXTableCol prop="subject_name" label="院校/批次" width="19%"></WXXTableCol>
<WXXTableCol prop="second_subject" label="选考要求" width="17%"></WXXTableCol>
<WXXTableCol prop="enroll_num" label="录取数" width="13%"></WXXTableCol>
<WXXTableCol prop="score" label="分数" width="24%"></WXXTableCol>
<WXXTableCol prop="rank_min" label="最低位次" width="17%"></WXXTableCol>
</WXXTable>
</scroll-view> </scroll-view>
<wd-action-sheet v-model="show" title=""> <wd-action-sheet v-model="show" title="">
@ -35,6 +43,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import WXXTable from '@/pages-sub/components/table/Table.vue' import WXXTable from '@/pages-sub/components/table/Table.vue'
import WXXTableCol from '@/pages-sub/components/table/TableCol.vue'
import { getAdmissionMark } from '@/service/index/api' import { getAdmissionMark } from '@/service/index/api'
import { useUserStore } from '@/store' import { useUserStore } from '@/store'
import CustomPickerView from '@/pages-sub/components/CustomPickerView.vue' import CustomPickerView from '@/pages-sub/components/CustomPickerView.vue'
@ -61,15 +70,6 @@ let pickType = 1
const tableData = ref([]) const tableData = ref([])
const columns = [
{ name: '年份', key: 'year', width: '10%' },
{ name: '院校/批次', key: 'subject_name', width: '19%' },
{ name: '选考要求', key: 'second_subject', width: '16%' },
{ name: '录取数', key: 'enroll_num', width: '13%' },
{ name: '分数', key: 'score', width: '24%' },
{ name: '最低位次', key: 'rank_min', width: '18%' },
]
let isFirst = true let isFirst = true
watch( watch(
() => props.id, () => props.id,

View File

@ -9,19 +9,25 @@
class="px-[24rpx] py-[8rpx] bg-[#f8f8f8] rounded-[8rpx] flex justify-between items-center text-[24rpx]" class="px-[24rpx] py-[8rpx] bg-[#f8f8f8] rounded-[8rpx] flex justify-between items-center text-[24rpx]"
> >
{{ year }} {{ year }}
<wd-icon name="arrow-down" size="16rpx" custom-class="ml-[80rpx]"></wd-icon> <view class="i-carbon-chevron-down rotate-270"></view>
</view> </view>
<view <view
@click="handleShow(2)" @click="handleShow(2)"
class="px-[24rpx] py-[8rpx] bg-[#f8f8f8] rounded-[8rpx] flex justify-between items-center text-[24rpx]" class="px-[24rpx] py-[8rpx] bg-[#f8f8f8] rounded-[8rpx] flex justify-between items-center text-[24rpx]"
> >
{{ batche }} {{ batche }}
<wd-icon name="arrow-down" size="16rpx" custom-class="ml-[80rpx]"></wd-icon> <view class="i-carbon-chevron-down rotate-270"></view>
</view> </view>
</view> </view>
<scroll-view class="mt-[38rpx] flex-1 pb-safe"> <scroll-view class="mt-[38rpx] flex-1 pb-safe">
<WXXTable :columns="columns" :tableData="tableData"></WXXTable> <WXXTable :data="tableData">
<WXXTableCol prop="universityName" label="院校名称" width="25%"></WXXTableCol>
<WXXTableCol prop="major" label="招生专业" width="37%"></WXXTableCol>
<WXXTableCol prop="plancount" label="计划数" width="13%"></WXXTableCol>
<WXXTableCol prop="academic" label="学制" width="10%"></WXXTableCol>
<WXXTableCol prop="fee" label="学费" width="15%"></WXXTableCol>
</WXXTable>
</scroll-view> </scroll-view>
<wd-action-sheet v-model="show" title=""> <wd-action-sheet v-model="show" title="">
@ -38,6 +44,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import WXXTable from '@/pages-sub/components/table/Table.vue' import WXXTable from '@/pages-sub/components/table/Table.vue'
import WXXTableCol from '@/pages-sub/components/table/TableCol.vue'
import { getPlanProList } from '@/service/index/api' import { getPlanProList } from '@/service/index/api'
import CustomPickerView from '@/pages-sub/components/CustomPickerView.vue' import CustomPickerView from '@/pages-sub/components/CustomPickerView.vue'
import { useUserStore } from '@/store' import { useUserStore } from '@/store'
@ -65,14 +72,6 @@ let pickType = 1
const tableData = ref([]) const tableData = ref([])
const columns = [
{ name: '院校名称', key: 'universityName', width: '25%' },
{ name: '招生专业', key: 'major', width: '37%' },
{ name: '计划数', key: 'plancount', width: '13%' },
{ name: '学制', key: 'academic', width: '10%' },
{ name: '学费', key: 'fee', width: '15%' },
]
let isFirst = true let isFirst = true
watch( watch(
() => props.id, () => props.id,
@ -101,20 +100,22 @@ const getPlanProListData = async (newVal) => {
batchName: batche.value === '全部分类' ? '' : batche.value, batchName: batche.value === '全部分类' ? '' : batche.value,
locationCode: userStore.userInfo.estimatedAchievement.provinceCode, locationCode: userStore.userInfo.estimatedAchievement.provinceCode,
}).then((resp) => { }).then((resp) => {
const _res = resp.result as { if (resp.code === 200) {
batches: { batchName: string }[] const _res = resp.result as {
yearsDtos: string[] batches: { batchName: string }[]
plans: any[] yearsDtos: string[]
} plans: any[]
yearList.value = ['全部年份', ..._res.yearsDtos] }
batches.value = ['全部分类', ..._res.batches.map((item) => item.batchName)] yearList.value = ['全部年份', ..._res.yearsDtos]
tableData.value = _res.plans batches.value = ['全部分类', ..._res.batches.map((item) => item.batchName)]
tableData.value = _res.plans
if (isFirst) { if (isFirst) {
year.value = yearList.value[0] year.value = yearList.value[0]
batche.value = batches.value[0] batche.value = batches.value[0]
}
isFirst = false
} }
isFirst = false
}) })
} }

View File

@ -6,14 +6,14 @@
<text class="text-[22rpx] font-normal text-[#636363] my-[24rpx] line-clamp-3"> <text class="text-[22rpx] font-normal text-[#636363] my-[24rpx] line-clamp-3">
{{ subjectIntroduceList.join(',') }} {{ subjectIntroduceList.join(',') }}
</text> </text>
<wd-button <button
block block
custom-class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]!" class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]! text-[28rpx]! flex! items-center! justify-center! gap-[12rpx]!"
@click="handleFullFun(1)" @click="handleFullFun(1)"
> >
查看全部 查看全部
<wd-icon name="arrow-right"></wd-icon> <view class="i-carbon-chevron-down rotate-270"></view>
</wd-button> </button>
</view> </view>
<view <view
class="flex flex-col p-[32rpx] bg-[#fff] mt-[16rpx]" class="flex flex-col p-[32rpx] bg-[#fff] mt-[16rpx]"
@ -25,14 +25,14 @@
<text class="text-[22rpx] font-normal text-[#636363] my-[24rpx] line-clamp-3"> <text class="text-[22rpx] font-normal text-[#636363] my-[24rpx] line-clamp-3">
{{ assessmentSubjectList.join(',') }} {{ assessmentSubjectList.join(',') }}
</text> </text>
<wd-button <button
block block
custom-class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]!" class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]! text-[28rpx]! flex! items-center! justify-center! gap-[12rpx]!"
@click="handleFullFun(2)" @click="handleFullFun(2)"
> >
查看全部 查看全部
<wd-icon name="arrow-right"></wd-icon> <view class="i-carbon-chevron-down rotate-270"></view>
</wd-button> </button>
</view> </view>
<view class="flex flex-col p-[32rpx] bg-[#fff] mt-[16rpx]"> <view class="flex flex-col p-[32rpx] bg-[#fff] mt-[16rpx]">
<text class="text-[32rpx] font-semibold text-[#333]"> <text class="text-[32rpx] font-semibold text-[#333]">
@ -41,14 +41,14 @@
<text class="text-[22rpx] font-normal text-[#636363] my-[24rpx]"> <text class="text-[22rpx] font-normal text-[#636363] my-[24rpx]">
{{ featureSubjectList.join(',') }} {{ featureSubjectList.join(',') }}
</text> </text>
<wd-button <button
block block
custom-class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]!" class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]! text-[28rpx]! flex! items-center! justify-center! gap-[12rpx]!"
@click="handleFullFun(3)" @click="handleFullFun(3)"
> >
查看全部 查看全部
<wd-icon name="arrow-right"></wd-icon> <view class="i-carbon-chevron-down rotate-270"></view>
</wd-button> </button>
</view> </view>
<MessageBox v-model:show="show" :title="title"> <MessageBox v-model:show="show" :title="title">

View File

@ -26,14 +26,14 @@
<view class="line-clamp-4 mt-[14rpx] text-[22rpx] text-[#636363]"> <view class="line-clamp-4 mt-[14rpx] text-[22rpx] text-[#636363]">
{{ universityResult?.detail }} {{ universityResult?.detail }}
</view> </view>
<wd-button <button
block block
custom-class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]!" class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]! text-[28rpx]! flex! items-center! justify-center! gap-[16rpx]"
@click="show = true" @click="show = true"
> >
查看全部 查看全部
<wd-icon name="arrow-right"></wd-icon> <view class="i-carbon-chevron-down rotate-270"></view>
</wd-button> </button>
<MessageBox v-model:show="show" title="院校简介"> <MessageBox v-model:show="show" title="院校简介">
<template> <template>
@ -47,7 +47,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { UniversityResult } from '@/types/app-type' import { UniversityResult } from '@/types/app-type'
import wdButton from 'wot-design-uni/components/wd-button/wd-button.vue'
import MessageBox from '../../components/MessageBox.vue' import MessageBox from '../../components/MessageBox.vue'
defineProps({ defineProps({

View File

@ -6,19 +6,26 @@
class="px-[24rpx] py-[8rpx] bg-[#f8f8f8] rounded-[8rpx] flex justify-between items-center text-[24rpx]" class="px-[24rpx] py-[8rpx] bg-[#f8f8f8] rounded-[8rpx] flex justify-between items-center text-[24rpx]"
> >
{{ year }} {{ year }}
<wd-icon name="arrow-down" size="16rpx" custom-class="ml-[80rpx]"></wd-icon> <view class="i-carbon-chevron-down"></view>
</view> </view>
<view <view
@click="handleShow(2)" @click="handleShow(2)"
class="px-[24rpx] py-[8rpx] bg-[#f8f8f8] rounded-[8rpx] flex justify-between items-center text-[24rpx]" class="px-[24rpx] py-[8rpx] bg-[#f8f8f8] rounded-[8rpx] flex justify-between items-center text-[24rpx]"
> >
{{ provinceName || '请选择省份' }} {{ provinceName || '请选择省份' }}
<wd-icon name="arrow-down" size="16rpx" custom-class="ml-[80rpx]"></wd-icon> <view class="i-carbon-chevron-down"></view>
</view> </view>
</view> </view>
<scroll-view class="mt-[38rpx] flex-1 pb-safe"> <scroll-view class="mt-[38rpx] flex-1 pb-safe">
<WXXTable :columns="columns" :tableData="tableData"></WXXTable> <WXXTable :data="tableData">
<WXXTableCol prop="years" label="年份" width="10%"></WXXTableCol>
<WXXTableCol prop="batchName" label="院校/批次" width="19%"></WXXTableCol>
<WXXTableCol prop="selectsubject" label="选考要求" width="16%"></WXXTableCol>
<WXXTableCol prop="plancount" label="录取数" width="13%"></WXXTableCol>
<WXXTableCol prop="lowscore" label="分数" width="24%"></WXXTableCol>
<WXXTableCol prop="lowscorerank" label="最低位次" width="18%"></WXXTableCol>
</WXXTable>
</scroll-view> </scroll-view>
<wd-action-sheet v-model="show" title=""> <wd-action-sheet v-model="show" title="">
@ -45,6 +52,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import WXXTable from '@/pages-sub/components/table/Table.vue' import WXXTable from '@/pages-sub/components/table/Table.vue'
import WXXTableCol from '@/pages-sub/components/table/TableCol.vue'
import { getPlanProList } from '@/service/index/api' import { getPlanProList } from '@/service/index/api'
import { useUserStore } from '@/store' import { useUserStore } from '@/store'
import Region from '@/pages-sub/home/components/Region.vue' import Region from '@/pages-sub/home/components/Region.vue'
@ -71,15 +79,6 @@ let pickType = 1
const tableData = ref([]) const tableData = ref([])
const columns = [
{ name: '年份', key: 'years', width: '10%' },
{ name: '院校/批次', key: 'batchName', width: '19%' },
{ name: '选考要求', key: 'selectsubject', width: '16%' },
{ name: '录取数', key: 'plancount', width: '13%' },
{ name: '分数', key: 'lowscore', width: '24%' },
{ name: '最低位次', key: 'lowscorerank', width: '18%' },
]
let isFirst = true let isFirst = true
watch( watch(
() => props.id, () => props.id,
@ -108,19 +107,21 @@ const getPlanProListData = async (newVal) => {
batchName: '', batchName: '',
locationCode: userStore.userInfo.estimatedAchievement.provinceCode, locationCode: userStore.userInfo.estimatedAchievement.provinceCode,
}).then((resp) => { }).then((resp) => {
const _res = resp.result as { if (resp.code === 200) {
batches: { batchName: string }[] const _res = resp.result as {
yearsDtos: string[] batches: { batchName: string }[]
plans: any[] yearsDtos: string[]
} plans: any[]
yearList.value = ['全部年份', ..._res.yearsDtos] }
yearList.value = ['全部年份', ..._res.yearsDtos]
tableData.value = _res.plans // tableData.value = _res.plans
if (isFirst) { if (isFirst) {
year.value = yearList.value[0] year.value = yearList.value[0]
}
isFirst = false
} }
isFirst = false
}) })
} }

View File

@ -47,7 +47,7 @@
@open="handleOpenSubMenu(item.id)" @open="handleOpenSubMenu(item.id)"
custom-class="flex items-center" custom-class="flex items-center"
> >
<view class="pt-[32rpx]"> <view class="">
<Region v-if="currentMenu === 1" @changeName="handleRegionChange" /> <Region v-if="currentMenu === 1" @changeName="handleRegionChange" />
<Nature v-if="currentMenu === 2" @changeName="handleNatureChange" /> <Nature v-if="currentMenu === 2" @changeName="handleNatureChange" />
<UniType v-if="currentMenu === 3" @changeName="handleUniTypeChange" /> <UniType v-if="currentMenu === 3" @changeName="handleUniTypeChange" />

View File

@ -41,14 +41,11 @@
{{ universityBaseInfo?.universityResult.features.slice(0, 4).join('/&nbsp;') }} {{ universityBaseInfo?.universityResult.features.slice(0, 4).join('/&nbsp;') }}
</text> </text>
</view> </view>
<wd-button <button class="collect-btn" plain @click="handleStar">
:icon="startFlag ? 'star-filled' : 'star'" <view class="i-carbon-star-filled" v-if="startFlag"></view>
custom-class="collect-btn" <view class="i-carbon-star" v-else></view>
plain
@click="handleStar"
>
收藏 收藏
</wd-button> </button>
</view> </view>
<view class="card-swiper mb-[32rpx]"> <view class="card-swiper mb-[32rpx]">
@ -199,6 +196,8 @@ const handleStar = () => {
display: flex !important; display: flex !important;
justify-content: space-between !important; justify-content: space-between !important;
align-items: center !important; align-items: center !important;
font-size: 24rpx !important;
} }
:deep(.wd-button__icon) { :deep(.wd-button__icon) {

View File

@ -19,9 +19,24 @@
</view> </view>
<view class="flex-1 pb-[24rpx] h-[50vh] overflow-y-auto"> <view class="flex-1 pb-[24rpx] h-[50vh] overflow-y-auto">
<Phase v-show="currentMenu === 1" /> <Phase v-show="currentMenu === 1" />
<Region class="custom-wrapper" v-show="currentMenu === 2" /> <Region
<UniType class="custom-wrapper" v-show="currentMenu === 3" /> width="240rpx"
<Nature class="custom-wrapper" v-show="currentMenu === 4" /> height="60rpx"
class="justify-center!"
v-show="currentMenu === 2"
/>
<UniType
width="240rpx"
height="60rpx"
class="justify-center!"
v-show="currentMenu === 3"
/>
<Nature
width="240rpx"
height="60rpx"
class="justify-center!"
v-show="currentMenu === 4"
/>
</view> </view>
</view> </view>
<view class="pt-[32rpx] px-[32rpx] wei-xin-pt box-shadow"> <view class="pt-[32rpx] px-[32rpx] wei-xin-pt box-shadow">
@ -32,21 +47,22 @@
:key="item" :key="item"
> >
<text class="text-[#303030] text-[24rpx] font-medium mr-[16rpx]">中外合作</text> <text class="text-[#303030] text-[24rpx] font-medium mr-[16rpx]">中外合作</text>
<wd-icon name="close-outline" size="24rpx" color="#cbcbcb"></wd-icon> <view class="i-carbon-close-filled"></view>
</view> </view>
</view> --> </view> -->
<view class="flex items-center"> <view class="flex items-center">
<wd-button <button
plain plain
custom-class="border-[#f5f5f5]! px-[134rpx]! py-[26rpx]! bg-[#f5f5f5]! rounded-[8rpx]! text-[#1580FF]! text-[32rpx]! font-normal! mr-[22rpx]" class="border-[#f5f5f5]! flex-auto bg-[#f5f5f5]! rounded-[8rpx]! text-[#1580FF]! text-[32rpx]! font-normal! mr-[22rpx]"
> >
清空 清空
</wd-button> </button>
<wd-button <button
custom-class="border-[#1580FF]! px-[134rpx]! py-[26rpx]! bg-[#1580FF]! rounded-[8rpx]! text-[#fff]! text-[32rpx]! font-normal!" class="border-[#1580FF]! flex-auto bg-[#1580FF]! rounded-[8rpx]! text-[#fff]! text-[32rpx]! font-normal!"
> >
查看结果 查看结果
</wd-button> </button>
</view> </view>
</view> </view>
</view> </view>
@ -106,9 +122,10 @@ const changeMenu = (item: { id: number; name: string }) => {
</style> </style>
<style lang="scss"> <style lang="scss">
.checkbox { .large-checkbox {
width: 240rpx !important; :deep(.custom-checkbox) {
height: 60rpx !important; --checkbox-width: 240rpx;
background: #f7f8fa !important; --checkbox-height: 60rpx;
}
} }
</style> </style>

View File

@ -5,12 +5,11 @@
<text class="text-[36rpx] text-[#303030] font-bold text-center"> <text class="text-[36rpx] text-[#303030] font-bold text-center">
{{ title }} {{ title }}
</text> </text>
<wd-icon
name="close" <view
size="40rpx" class="i-carbon-close absolute right-[40rpx] text-[40rpx]"
custom-class="absolute right-[40rpx]"
@click="emits('update:show', false)" @click="emits('update:show', false)"
></wd-icon> ></view>
</view> </view>
<view class="min-h-[200rpx] h-max-content overflow-y-auto px-[32rpx]"> <view class="min-h-[200rpx] h-max-content overflow-y-auto px-[32rpx]">
<slot></slot> <slot></slot>

View File

@ -1,7 +1,5 @@
<!-- 大学甄别 --> <!-- 大学甄别 -->
<template> <template></template>
<text>大学甄别</text>
</template>
<script lang="ts" setup></script> <script lang="ts" setup></script>

View File

@ -1,5 +1,171 @@
<route lang="json5" type="page">
{
layout: 'page',
style: {
navigationStyle: 'custom',
},
}
</route>
<template> <template>
<text>查扩缩招</text> <view class="flex flex-col h-screen">
<view class="relative">
<Navbar
safeAreaInsetTop
bg-color="transparent"
:bordered="false"
left-arrow
title="查扩缩招"
@click-left="navigatorBack"
/>
<view class="custom-background h-[200rpx] w-full absolute top-0 left-0 z-[-1]"></view>
</view>
<drop-menu>
<drop-menu-item
:key="1"
:title="searchParams.locationName || '省份'"
custom-class="flex items-center"
>
<Region
:defaultValue="searchParams.locationCode ? [searchParams.locationCode] : []"
:max="1"
@changeName="handleRegionChange"
@change="handleRegionChangeCode"
/>
</drop-menu-item>
<drop-menu-item
:key="2"
:title="searchParams.searchNature || '层次'"
custom-class="flex items-center"
>
<Nature @changeName="handleNatureChange" />
</drop-menu-item>
<drop-menu-item :key="3" title="类别" custom-class="flex items-center">
<UniType
@change="handleUniTypeChange"
:max="1"
:default-value="searchParams.type ? [searchParams.type] : []"
/>
</drop-menu-item>
</drop-menu>
<view class="px-32rpx">
<view class="flex items-center justify-between input-wrapper-class">
<input
v-model="searchParams.Score"
type="number"
placeholder="请输入你的高考分数"
confirm-type="done"
input-mode="numeric"
class="flex-auto"
/>
<view class="text-[#1580FF] text-[24rpx] search-text" @click="handleConfirm"></view>
</view>
<view class="text-[#636363] text-[20rpx] mt-[24rpx]">分数范围{{ betweenScores }}</view>
</view>
<view class="bg-[#F8F8F8] h-[16rpx] mt-[40rpx]"></view>
</view>
</template> </template>
<script lang="ts" setup></script> <script lang="ts" setup>
import Navbar from '@/pages-sub/components/navbar/Navbar.vue'
import { useUserStore } from '@/store'
import DropMenu from '@/pages-sub/components/drop-menu/DropMenu.vue'
import DropMenuItem from '@/pages-sub/components/drop-menu/DropMenuItem.vue'
import Region from '@/pages-sub/home/components/Region.vue'
import UniType from '@/pages-sub/home/components/UniType.vue'
import Nature from '@/pages-sub/home/components/Nature.vue'
import { getBatchList } from '@/service/index/api'
const userStore = useUserStore()
const searchParams = ref({
locationCode: userStore.userInfo.estimatedAchievement.provinceCode || '370000',
locationName: userStore.userInfo.estimatedAchievement.provinceName || '山东省',
type: '',
searchNature: '',
Score: '',
})
const handleConfirm = () => {
getBatchListData()
}
const betweenScores = ref('')
const checkYearList = ref([])
const navigatorBack = () => {
uni.navigateBack()
}
const handleRegionChange = (val) => {
searchParams.value.locationName = val.join(',')
}
const handleRegionChangeCode = (val) => {
searchParams.value.locationCode = val[0]
getBatchListData()
}
const handleUniTypeChange = (val) => {
searchParams.value.type = val[0]
getBatchListData()
}
const handleNatureChange = (val) => {}
type LineItem = {
batch_id: number
batch_name: string
province_code: number
province_name: string
score: string
subject_id: number
subject_name: string
year: number
}
const lineList = ref<LineItem[]>([])
const getBatchListData = () => {
getBatchList({
locationCode: searchParams.value.locationCode,
year: '',
type: searchParams.value.type,
}).then((resp) => {
if (resp.code === 200 && resp.result !== '暂无数据') {
const _result = resp.result as {
configList: { yearList: { year: string; check: boolean }[] }
list: LineItem[]
}
checkYearList.value = _result.configList.yearList
lineList.value = _result.list
} else if (resp.code === 200 && resp.result === '暂无数据') {
lineList.value = []
}
})
}
onBeforeMount(() => {
getBatchListData()
})
</script>
<style lang="scss" scoped>
@import '@/pages-sub/home/styles/navbar-background.scss';
.input-wrapper-class {
border-radius: 8rpx;
border: 2rpx solid #ededed;
padding: 10rpx 24rpx;
margin-top: 48rpx;
.search-text {
border-left: 2rpx solid #ededed;
padding-left: 24rpx;
}
}
</style>

View File

@ -86,14 +86,14 @@
</Checkbox> </Checkbox>
</CheckboxGroup> </CheckboxGroup>
</view> </view>
<wd-button <button
block block
custom-class="mt-auto mb-[32rpx] rounded-[8rpx]! bg-[#1580FF]! mx-[32rpx]" class="mt-auto mb-[32rpx] rounded-[8rpx]! bg-[#1580FF]! mx-[32rpx]! text-[32rpx]! text-[#fff]! font-normal"
@click="saveScore" @click="saveScore"
:disabled="btnFlag < 3" :disabled="btnFlag < 3"
> >
保存 保存
</wd-button> </button>
<view class="bg-white pb-safe" hover-class="none"></view> <view class="bg-white pb-safe" hover-class="none"></view>
</view> </view>
</template> </template>

View File

@ -15,7 +15,7 @@
bg-color="transparent" bg-color="transparent"
:bordered="false" :bordered="false"
left-arrow left-arrow
:title="`近4年批次线(${userStore.userInfo.estimatedAchievement.provinceName})`" :title="`近4年批次线(${searchParams.locationName})`"
@click-left="navigatorBack" @click-left="navigatorBack"
/> />
<view class="custom-background h-[200rpx] w-full absolute top-0 left-0 z-[-1]"></view> <view class="custom-background h-[200rpx] w-full absolute top-0 left-0 z-[-1]"></view>
@ -55,11 +55,13 @@
/> />
</drop-menu-item> </drop-menu-item>
</drop-menu> </drop-menu>
<WXXTable <WXXTable :data="lineList" class="px-[32rpx] mt-[16rpx] pb-safe">
:columns="columns" <WXXTableCol prop="province_name" label="地区" width="14%"></WXXTableCol>
:tableData="lineList" <WXXTableCol prop="year" label="年份" width="23%"></WXXTableCol>
class="px-[32rpx] mt-[16rpx] pb-safe" <WXXTableCol prop="subject_name" label="类别" width="23%"></WXXTableCol>
></WXXTable> <WXXTableCol prop="batch_name" label="批次" width="23%"></WXXTableCol>
<WXXTableCol prop="score" label="分数线" width="17%"></WXXTableCol>
</WXXTable>
</view> </view>
</template> </template>
@ -73,14 +75,15 @@ import UniType from '@/pages-sub/home/components/UniType.vue'
import CheckGroup from '@/pages-sub/components/check-group/CheckGroup.vue' import CheckGroup from '@/pages-sub/components/check-group/CheckGroup.vue'
import WXXTable from '@/pages-sub/components/table/Table.vue' import WXXTable from '@/pages-sub/components/table/Table.vue'
import WXXTableCol from '@/pages-sub/components/table/TableCol.vue'
import { getBatchList } from '@/service/index/api' import { getBatchList } from '@/service/index/api'
const userStore = useUserStore() const userStore = useUserStore()
const searchParams = ref({ const searchParams = ref({
locationCode: userStore.userInfo.estimatedAchievement.provinceCode, locationCode: userStore.userInfo.estimatedAchievement.provinceCode || '370000',
locationName: userStore.userInfo.estimatedAchievement.provinceName, locationName: userStore.userInfo.estimatedAchievement.provinceName || '山东省',
year: '', year: '',
type: '', type: '',
}) })
@ -117,14 +120,6 @@ const handleYearChange = (val) => {
getBatchListData() getBatchListData()
} }
const columns = [
{ name: '地区', key: 'province_name', width: '14%' },
{ name: '年份', key: 'year', width: '23%' },
{ name: '类别', key: 'subject_name', width: '23%' },
{ name: '批次', key: 'batch_name', width: '23%' },
{ name: '分数线', key: 'score', width: '17%' },
]
type LineItem = { type LineItem = {
batch_id: number batch_id: number
batch_name: string batch_name: string

View File

@ -4,14 +4,14 @@
<text class="text-[22rpx] font-normal text-[#636363] my-[24rpx] line-clamp-3"> <text class="text-[22rpx] font-normal text-[#636363] my-[24rpx] line-clamp-3">
{{ careerInfo.jobs || '暂无' }} {{ careerInfo.jobs || '暂无' }}
</text> </text>
<wd-button <button
block block
custom-class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]!" class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]! text-[28rpx]! flex! items-center! justify-center! gap-[16rpx]"
@click="handleFullFun(1)" @click="handleFullFun(1)"
> >
查看全部 查看全部
<wd-icon name="arrow-right"></wd-icon> <view class="i-carbon-chevron-down rotate-270"></view>
</wd-button> </button>
</view> </view>
<view class="h-[16rpx] bg-[#f8f8f8]"></view> <view class="h-[16rpx] bg-[#f8f8f8]"></view>
<view class="flex flex-col py-[32rpx] px-[24rpx] bg-[#fff]"> <view class="flex flex-col py-[32rpx] px-[24rpx] bg-[#fff]">
@ -19,14 +19,14 @@
<text class="text-[22rpx] font-normal text-[#636363] my-[24rpx] line-clamp-3"> <text class="text-[22rpx] font-normal text-[#636363] my-[24rpx] line-clamp-3">
{{ careerInfo.profession || '暂无' }} {{ careerInfo.profession || '暂无' }}
</text> </text>
<wd-button <button
block block
custom-class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]!" class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]! text-[28rpx]! flex! items-center! justify-center! gap-[16rpx]"
@click="handleFullFun(2)" @click="handleFullFun(2)"
> >
查看全部 查看全部
<wd-icon name="arrow-right"></wd-icon> <view class="i-carbon-chevron-down rotate-270"></view>
</wd-button> </button>
</view> </view>
<view class="h-[16rpx] bg-[#f8f8f8]"></view> <view class="h-[16rpx] bg-[#f8f8f8]"></view>

View File

@ -5,14 +5,14 @@
<text class="text-[22rpx] font-normal text-[#636363] my-[24rpx] line-clamp-3"> <text class="text-[22rpx] font-normal text-[#636363] my-[24rpx] line-clamp-3">
{{ zyjx || '暂无' }} {{ zyjx || '暂无' }}
</text> </text>
<wd-button <button
block block
custom-class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]!" class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]! text-[28rpx]! flex! items-center! justify-center! gap-[16rpx]"
@click="handleFullFun(1)" @click="handleFullFun(1)"
> >
查看全部 查看全部
<wd-icon name="arrow-right"></wd-icon> <view class="i-carbon-chevron-down rotate-270"></view>
</wd-button> </button>
</view> </view>
<view class="h-[16rpx] bg-[#f8f8f8]"></view> <view class="h-[16rpx] bg-[#f8f8f8]"></view>
<view class="flex flex-col py-[32rpx] px-[24rpx] bg-[#fff]"> <view class="flex flex-col py-[32rpx] px-[24rpx] bg-[#fff]">
@ -21,33 +21,34 @@
<text class="text-[22rpx] font-normal text-[#636363] my-[24rpx] line-clamp-3"> <text class="text-[22rpx] font-normal text-[#636363] my-[24rpx] line-clamp-3">
{{ kyfx.map((item) => item.zymc).join(',') || '暂无' }} {{ kyfx.map((item) => item.zymc).join(',') || '暂无' }}
</text> </text>
<wd-button
<button
block block
custom-class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]!" class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]! text-[28rpx]! flex! items-center! justify-center! gap-[16rpx]"
@click="handleFullFun(2)" @click="handleFullFun(2)"
> >
查看全部 查看全部
<wd-icon name="arrow-right"></wd-icon> <view class="i-carbon-chevron-down rotate-270"></view>
</wd-button> </button>
</view> </view>
<view class="h-[16rpx] bg-[#f8f8f8]"></view> <view class="h-[16rpx] bg-[#f8f8f8]"></view>
<view class="flex flex-col py-[32rpx] px-[24rpx] bg-[#fff]"> <view class="flex flex-col py-[32rpx] px-[24rpx] bg-[#fff]">
<text class="text-[32rpx] font-semibold text-[#333]">课程列表</text> <text class="text-[32rpx] font-semibold text-[#333]">课程列表</text>
<view class="my-[24rpx]"> <view class="my-[24rpx]">
<WXXTable <WXXTable :data="courseInfo.slice(0, 4)" class="my-[24rpx]">
:columns="columns" <WXXTableCol prop="kcmc" label="课程名称" width="50%"></WXXTableCol>
:tableData="courseInfo.slice(0, 4)" <WXXTableCol prop="difficulty" label="课程难易度" width="25%"></WXXTableCol>
class="my-[24rpx]" <WXXTableCol prop="practicality" label="课程实用度" width="25%"></WXXTableCol>
></WXXTable> </WXXTable>
</view> </view>
<wd-button <button
block block
custom-class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]!" class="mt-[24rpx] rounded-[8rpx]! bg-[#f8f8f8]! w-full text-[#303030]! text-[28rpx]! flex! items-center! justify-center! gap-[16rpx]"
@click="handleFullFun(3)" @click="handleFullFun(3)"
> >
查看全部 查看全部
<wd-icon name="arrow-right"></wd-icon> <view class="i-carbon-chevron-down rotate-270"></view>
</wd-button> </button>
</view> </view>
<MessageBox v-model:show="show" :title="title"> <MessageBox v-model:show="show" :title="title">
@ -55,12 +56,14 @@
<view class="text-[22rpx] text-[#636363] max-h-600rpx mb-[32rpx]" v-show="showType !== 3"> <view class="text-[22rpx] text-[#636363] max-h-600rpx mb-[32rpx]" v-show="showType !== 3">
{{ innerContent }} {{ innerContent }}
</view> </view>
<WXXTable <scroll-view class="max-h-600rpx mb-[32rpx] overflow-y-auto" :scroll-y="true">
:columns="columns" <WXXTable :data="courseInfo" class="my-[24rpx]" v-show="showType === 3">
:tableData="courseInfo" >
class="my-[24rpx]" <WXXTableCol prop="kcmc" label="课程名称" width="50%"></WXXTableCol>
v-show="showType === 3" <WXXTableCol prop="difficulty" label="课程难易度" width="25%"></WXXTableCol>
></WXXTable> <WXXTableCol prop="practicality" label="课程实用度" width="25%"></WXXTableCol>
</WXXTable>
</scroll-view>
</template> </template>
</MessageBox> </MessageBox>
</template> </template>
@ -68,6 +71,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import MessageBox from '@/pages-sub/home/components/MessageBox.vue' import MessageBox from '@/pages-sub/home/components/MessageBox.vue'
import WXXTable from '@/pages-sub/components/table/Table.vue' import WXXTable from '@/pages-sub/components/table/Table.vue'
import WXXTableCol from '@/pages-sub/components/table/TableCol.vue'
import { getMajorCourse } from '@/service/index/api' import { getMajorCourse } from '@/service/index/api'
const props = defineProps({ const props = defineProps({
@ -85,12 +89,6 @@ const props = defineProps({
}, },
}) })
const columns = [
{ name: '课程名称', key: 'kcmc', width: '50%' },
{ name: '课程难易度', key: 'difficulty', width: '25%' },
{ name: '课程实用度', key: 'practicality', width: '25%' },
]
const courseInfo = ref<any[]>([]) const courseInfo = ref<any[]>([])
watch( watch(

View File

@ -22,8 +22,11 @@
> >
{{ item.childMajors.length }} {{ item.childMajors.length }}
</text> </text>
<wd-icon name="arrow-up" size="16rpx" v-if="expanded" color="#1580FF"></wd-icon> <view
<wd-icon name="arrow-down" size="16rpx" v-else></wd-icon> class="i-carbon-chevron-down rotate-180 text-[16rpx] text-[#1580FF]"
v-if="expanded"
></view>
<view class="i-carbon-chevron-down text-[16rpx]" v-else></view>
</view> </view>
</view> </view>
</template> </template>

View File

@ -29,7 +29,7 @@
class="px-[24rpx] py-[8rpx] bg-[#f8f8f8] rounded-[8rpx] flex justify-between items-center text-[24rpx] w-[144rpx] mt-[30rpx]" class="px-[24rpx] py-[8rpx] bg-[#f8f8f8] rounded-[8rpx] flex justify-between items-center text-[24rpx] w-[144rpx] mt-[30rpx]"
> >
{{ provinceName || '不限' }} {{ provinceName || '不限' }}
<wd-icon name="arrow-down" size="16rpx" custom-class="ml-[80rpx]"></wd-icon> <view class="i-carbon-chevron-down text-[16rpx]"></view>
</view> </view>
<scroll-view :scroll-x="true" class=""> <scroll-view :scroll-x="true" class="">
<view <view

View File

@ -8,7 +8,7 @@
</route> </route>
<template> <template>
<view class="pb-safe flex flex-col h-screen"> <view class="flex flex-col h-screen">
<view class="relative"> <view class="relative">
<Navbar <Navbar
safeAreaInsetTop safeAreaInsetTop

View File

@ -191,7 +191,11 @@
}, },
{ {
"path": "home/expand/index", "path": "home/expand/index",
"type": "page" "type": "page",
"layout": "page",
"style": {
"navigationStyle": "custom"
}
}, },
{ {
"path": "home/inputScore/index", "path": "home/inputScore/index",
@ -275,6 +279,20 @@
{ {
"path": "index", "path": "index",
"type": "page" "type": "page"
},
{
"path": "rank/index",
"type": "page",
"layout": "page",
"style": {
"navigationStyle": "custom"
},
"usingComponents": {
"LEchart": "../uni_modules/lime-echart/components/l-echart/l-echart"
},
"componentPlaceholder": {
"LEchart": "view"
}
} }
] ]
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<scroll-view class="" :scroll-y="true"> <scroll-view class="" :scroll-y="true">
<view class="gradient-background relative"> <view class="gradient-background relative">
<Navbar safeAreaInsetTop bg-color="transparent" :bordered="false"> <Navbar safeAreaInsetTop bg-color="transparent" placeholder :bordered="false">
<template #left> <template #left>
<navigator open-type="navigate" class="left-icon" url="/pages-sub/home/city/index"> <navigator open-type="navigate" class="left-icon" url="/pages-sub/home/city/index">
<text <text

View File

@ -182,3 +182,12 @@ export const getProfessionInfo = (params: { id: string }) => {
export const getBatchList = (params: { locationCode: string; year: string; type: string }) => { export const getBatchList = (params: { locationCode: string; year: string; type: string }) => {
return http.get('/api/zhiYuan/batchList', params) return http.get('/api/zhiYuan/batchList', params)
} }
export const getScoreSection = (params: {
locationCode: string
year: string
type: string
Score: string
}) => {
return http.get('/api/ScoreSection/scoreSection/V2', params)
}

View File

@ -30,7 +30,8 @@ interface NavigateToOptions {
"/pages-sub/home/rank/index" | "/pages-sub/home/rank/index" |
"/pages-sub/home/schoolRank/index" | "/pages-sub/home/schoolRank/index" |
"/login-sub/index" | "/login-sub/index" |
"/pages-evaluation-sub/index"; "/pages-evaluation-sub/index" |
"/pages-evaluation-sub/rank/index";
} }
interface RedirectToOptions extends NavigateToOptions {} interface RedirectToOptions extends NavigateToOptions {}

View File

@ -1,5 +1,8 @@
import { CustomRequestOptions } from '@/interceptors/request' import { CustomRequestOptions } from '@/interceptors/request'
import { staticBaseUrl, baseUrl } from '@/utils/index' import { staticBaseUrl, baseUrl } from '@/utils/index'
import { useUserStore } from '@/store'
const userStore = useUserStore()
export const http = <T>(options: CustomRequestOptions) => { export const http = <T>(options: CustomRequestOptions) => {
// 1. 返回 Promise 对象 // 1. 返回 Promise 对象
@ -14,13 +17,15 @@ export const http = <T>(options: CustomRequestOptions) => {
// 响应成功 // 响应成功
success(res) { success(res) {
// 状态码 2xx参考 axios 的设计 // 状态码 2xx参考 axios 的设计
if (res.statusCode >= 200 && res.statusCode < 300) { if ((res.data as IResData<T>).code === 401) {
uni.navigateTo({ url: '/login-sub/index' })
reject(res)
} else if (res.statusCode < 300 && res.statusCode >= 200) {
// 2.1 提取核心数据 res.data // 2.1 提取核心数据 res.data
resolve(res.data as IResData<T>) resolve(res.data as IResData<T>)
} else if (res.statusCode === 401) { } else if (res.statusCode === 401) {
// 401错误 -> 清理用户信息,跳转到登录页 // 401错误 -> 清理用户信息,跳转到登录页
// userStore.clearUserInfo() uni.navigateTo({ url: '/login-sub/index' })
// uni.navigateTo({ url: '/pages/login/login' })
reject(res) reject(res)
} else { } else {
// 其他错误 -> 根据后端错误信息轻提示 // 其他错误 -> 根据后端错误信息轻提示