Compare commits
No commits in common. "ce32206709e14f4a9e2e1b57a07433a0093feda3" and "0d59ff4f74daf2510aa43a53218742b9fa6a8a5f" have entirely different histories.
ce32206709
...
0d59ff4f74
|
|
@ -2,23 +2,7 @@ VITE_APP_TITLE = '六纬中考通'
|
|||
VITE_APP_PORT = 9000
|
||||
|
||||
VITE_UNI_APPID = 'H57F2ACE4'
|
||||
# VITE_WX_APPID = 'wxc48ad15d58a3e417' 六纬中考通
|
||||
# VITE_WX_APPID = 'wx4b925e36c17dd54a' 智能中专学校的
|
||||
# wx487ac749c0e10be5 深泉外国语的
|
||||
VITE_WX_APPID = 'wx487ac749c0e10be5'
|
||||
# VITE_WX_VIDEO_ID= 'sphju9MCfZetYHP' 智能中专学校的
|
||||
# VITE_WX_VIDEO_ID= 'spht0MPpWjxEKb4' 深泉外国语
|
||||
# spheuUaMulnlpHH 深泉外国语学院 认证的
|
||||
VITE_WX_VIDEO_ID= 'spht0MPpWjxEKb4'
|
||||
|
||||
# 微信小程序 AI
|
||||
# 智能中专学校的
|
||||
# VITE_CLOUD_ENV_ID= 'cloud1-d3g5q6bq61a240786',
|
||||
# VITE_CLOUD_BOT_ID= 'agent-wxai-4gl75um61026324f',
|
||||
|
||||
# 深泉外国语学院的
|
||||
VITE_CLOUD_ENV_ID='cloud1-d9g4odcaqf6a2114f'
|
||||
VITE_CLOUD_BOT_ID='agent-wxai-9gi3rts96061202f'
|
||||
VITE_WX_APPID = 'wxc48ad15d58a3e417'
|
||||
|
||||
# h5部署网站的base,配置到 manifest.config.ts 里的 h5.router.base
|
||||
# https://uniapp.dcloud.net.cn/collocation/manifest.html#h5-router
|
||||
|
|
|
|||
|
|
@ -107,7 +107,6 @@
|
|||
"pinia": "2.0.36",
|
||||
"pinia-plugin-persistedstate": "3.2.1",
|
||||
"sard-uniapp": "^1.22.1",
|
||||
"uqrcodejs": "^4.0.7",
|
||||
"vue": "^3.4.21",
|
||||
"z-paging": "^2.8.8"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,10 +8,6 @@ export default defineUniPages({
|
|||
navigationBarBackgroundColor: '#FFFFFF',
|
||||
navigationBarTextStyle: 'black',
|
||||
backgroundColor: '#FFFFFF',
|
||||
// 全局注册 markdown 渲染组件,自定义聊天 UI 使用
|
||||
usingComponents: {
|
||||
'markdown-preview': '/wxcomponents/agent-ui/wd-markdown/index',
|
||||
},
|
||||
},
|
||||
easycom: {
|
||||
autoscan: true,
|
||||
|
|
@ -27,7 +23,7 @@ export default defineUniPages({
|
|||
preloadRule: {
|
||||
'pages/index/index': {
|
||||
network: 'all',
|
||||
packages: ['chart-sub', 'pages-ai'],
|
||||
packages: ['chart-sub'],
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@
|
|||
</text>
|
||||
<view class="mt-[20rpx] text-center">
|
||||
<view class="text-[#000] text-[26rpx] font-700">学习风格表现</view>
|
||||
<view class="mt-[10rpx]" v-for="(sonItem, index) in item.learning_performance" :key="index">
|
||||
{{ sonItem }}
|
||||
<view class="mt-[10rpx]" v-for="(item, index) in item.learning_performance" :key="index">
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-[20rpx] text-center">
|
||||
<view class="text-[#000] text-[26rpx] font-700">学习风格特点</view>
|
||||
<view class="mt-[10rpx]" v-for="(sonItem, index) in item.features" :key="index">
|
||||
{{ sonItem }}
|
||||
<view class="mt-[10rpx]" v-for="(item, index) in item.features" :key="index">
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,37 @@
|
|||
避免过度放松,保持适度的学习节奏。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="flex flex-col gap-[12rpx]">
|
||||
<view class="flex items-center gap-[10rpx]">
|
||||
<view class="w-[38rpx] h-[38rpx]">
|
||||
<image
|
||||
src="https://api.static.ycymedu.com/src/images/home/diet-icon.png"
|
||||
mode="scaleToFill"
|
||||
class="w-[38rpx] h-[38rpx]"
|
||||
/>
|
||||
</view>
|
||||
<text class="text-[32rpx] text-[#000] font-700">饮食建议</text>
|
||||
</view>
|
||||
<view class="text-[26rpx] text-[#666] font-400">
|
||||
保持规律作息,早睡早起,避免熬夜。 每天适当运动(如散步、跑步),保持精力充沛。
|
||||
避免过度放松,保持适度的学习节奏。
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex flex-col gap-[12rpx]">
|
||||
<view class="flex items-center gap-[10rpx]">
|
||||
<view class="w-[38rpx] h-[38rpx]">
|
||||
<image
|
||||
src="https://api.static.ycymedu.com/src/images/home/learn-icon.png"
|
||||
mode="scaleToFill"
|
||||
class="w-[38rpx] h-[38rpx]"
|
||||
/>
|
||||
</view>
|
||||
<text class="text-[32rpx] text-[#000] font-700">学习建议</text>
|
||||
</view>
|
||||
<view class="text-[26rpx] text-[#666] font-400">
|
||||
保持规律作息,早睡早起,避免熬夜。 每天适当运动(如散步、跑步),保持精力充沛。
|
||||
避免过度放松,保持适度的学习节奏。
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
</template>
|
||||
</Navbar>
|
||||
|
||||
<view class="flex-1 overflow-auto relative flex flex-col">
|
||||
<view class="flex-1 overflow-auto relative">
|
||||
<view class="flex flex-col flex-1 overflow-auto pb-[20rpx]">
|
||||
<!-- 顶部卡片 -->
|
||||
<view class="mt-[30rpx] mx-[24rpx]">
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
</template>
|
||||
</Navbar>
|
||||
|
||||
<view class="flex-1 overflow-auto relative flex flex-col">
|
||||
<view class="flex-1 overflow-auto relative">
|
||||
<view class="flex flex-col flex-1 overflow-auto pb-[20rpx]">
|
||||
<!-- 顶部卡片 -->
|
||||
<view class="mt-[30rpx] mx-[24rpx]">
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ interface ImportMetaEnv {
|
|||
readonly VITE_SERVER_PORT: string
|
||||
/** 后台接口地址 */
|
||||
readonly VITE_SERVER_BASEURL: string
|
||||
/** 微信视频号 ID */
|
||||
readonly VITE_WX_VIDEO_ID: string
|
||||
/** H5是否需要代理 */
|
||||
readonly VITE_APP_PROXY_ENABLE: 'true' | 'false'
|
||||
/** H5是否需要代理,需要的话有个前缀 */
|
||||
|
|
|
|||
|
|
@ -1,258 +0,0 @@
|
|||
<script lang="ts" setup>
|
||||
import type { AgentConfig, ModelConfig } from '../components/agent-config'
|
||||
import type { AiMessage } from '@/store/ai'
|
||||
import { useAiStore } from '@/store'
|
||||
import {
|
||||
defaultModelAgentConfig,
|
||||
defaultModelConfig,
|
||||
generateMessageId,
|
||||
} from '../components/agent-config'
|
||||
import { fetchRecommendQuestions, streamMessage } from '../components/agent-service'
|
||||
import AgentHeader from '../components/AgentHeader.vue'
|
||||
import AgentInput from '../components/AgentInput.vue'
|
||||
import AgentMessage from '../components/AgentMessage.vue'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: 'AI助手',
|
||||
},
|
||||
})
|
||||
|
||||
const agentConfig = reactive<AgentConfig>({
|
||||
// 当前页面默认走模型直连;如需切回 bot,改成 ...defaultAgentConfig
|
||||
...defaultModelAgentConfig,
|
||||
})
|
||||
const modelConfig = reactive<ModelConfig>({ ...defaultModelConfig })
|
||||
|
||||
const aiStore = useAiStore()
|
||||
|
||||
const paging = ref<any>(null)
|
||||
const messages = ref<AiMessage[]>([])
|
||||
const loading = ref(false)
|
||||
const initQuestionCapsules = computed(() => agentConfig.initQuestions.slice(0, 3))
|
||||
const shouldShowInitQuestionCapsules = computed(() => aiStore.messages.length === 0 && initQuestionCapsules.value.length > 0)
|
||||
|
||||
// 用于停止流:在新一轮发送时把上一轮的 controller 标记为 cancelled
|
||||
let cancelFlag = false
|
||||
|
||||
onLoad(() => {
|
||||
// #ifdef MP-WEIXIN
|
||||
if (typeof wx !== 'undefined' && wx.cloud) {
|
||||
wx.cloud.init({
|
||||
env: agentConfig.cloudEnvId,
|
||||
traceUser: true,
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
|
||||
aiStore.ensureThreadId()
|
||||
})
|
||||
|
||||
// z-paging 聊天模式:第一页直接把 store 里的历史灌给它
|
||||
// 聊天模式数据约定:数组下标 0 = 视觉最底部(最新消息),所以要倒序传入
|
||||
function queryList() {
|
||||
const welcomeMsg = agentConfig.welcomeMsg?.trim()
|
||||
|
||||
if (aiStore.messages.length === 0 && welcomeMsg) {
|
||||
aiStore.addMessage({
|
||||
id: generateMessageId(),
|
||||
role: 'assistant',
|
||||
content: welcomeMsg,
|
||||
createdAt: Date.now(),
|
||||
})
|
||||
}
|
||||
paging.value?.complete(aiStore.messages.slice().reverse())
|
||||
}
|
||||
|
||||
async function handleSend(text: string) {
|
||||
if (loading.value) {
|
||||
return
|
||||
}
|
||||
cancelFlag = false
|
||||
loading.value = true
|
||||
|
||||
const userMsg: AiMessage = {
|
||||
id: generateMessageId(),
|
||||
role: 'user',
|
||||
content: text,
|
||||
createdAt: Date.now(),
|
||||
}
|
||||
const aiMsg: AiMessage = {
|
||||
id: generateMessageId(),
|
||||
role: 'assistant',
|
||||
content: '',
|
||||
pending: true,
|
||||
// +1 防止与 userMsg 同毫秒下时间戳相等
|
||||
createdAt: Date.now() + 1,
|
||||
}
|
||||
|
||||
// store 顺序:旧 → 新;z-paging 聊天模式 addChatRecordData 内部会反转 + 前插,
|
||||
// 最终 totalData = [aiMsg, userMsg, ...历史],下标 0 = 视觉最底,符合"用户问 → AI 答在下方"
|
||||
aiStore.addMessage(userMsg)
|
||||
aiStore.addMessage(aiMsg)
|
||||
paging.value?.addChatRecordData([userMsg, aiMsg])
|
||||
|
||||
try {
|
||||
await streamMessage({
|
||||
chatMode: agentConfig.chatMode,
|
||||
// bot 模式参数
|
||||
botId: agentConfig.botId,
|
||||
threadId: aiStore.ensureThreadId(),
|
||||
// model 模式参数
|
||||
modelProvider: modelConfig.modelProvider,
|
||||
quickResponseModel: modelConfig.quickResponseModel,
|
||||
// 倒数第二条之前是历史;当前 aiMsg 是占位,不传
|
||||
history: aiStore.messages.slice(0, -1),
|
||||
prompt: text,
|
||||
onDelta: (delta) => {
|
||||
if (cancelFlag) {
|
||||
return
|
||||
}
|
||||
aiStore.appendDelta(aiMsg.id, delta)
|
||||
},
|
||||
onError: (msg) => {
|
||||
aiStore.updateMessage(aiMsg.id, {
|
||||
error: true,
|
||||
pending: false,
|
||||
content: msg,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
aiStore.updateMessage(aiMsg.id, { pending: false })
|
||||
|
||||
// 当前 V2 agent 后端不支持 getRecommendQuestions(端点 404),先关掉这一调用。
|
||||
// 等切换到 bot-xxx 旧版 agent 或后端补上对应路由再开启。
|
||||
if (!cancelFlag) {
|
||||
void loadRecommendQuestions(aiMsg.id, text)
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
aiStore.updateMessage(aiMsg.id, {
|
||||
pending: false,
|
||||
error: true,
|
||||
content: aiStore.messages.find(m => m.id === aiMsg.id)?.content
|
||||
|| (err instanceof Error ? err.message : '生成失败'),
|
||||
})
|
||||
}
|
||||
finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleStop() {
|
||||
cancelFlag = true
|
||||
loading.value = false
|
||||
// 把仍在 pending 的消息收尾
|
||||
const pending = aiStore.messages.find(m => m.pending)
|
||||
if (pending) {
|
||||
aiStore.updateMessage(pending.id, { pending: false })
|
||||
}
|
||||
}
|
||||
|
||||
function handleRetry(id: string) {
|
||||
const failedIdx = aiStore.messages.findIndex(m => m.id === id)
|
||||
if (failedIdx <= 0) {
|
||||
return
|
||||
}
|
||||
const userMsg = aiStore.messages[failedIdx - 1]
|
||||
if (!userMsg || userMsg.role !== 'user') {
|
||||
return
|
||||
}
|
||||
aiStore.removeMessage(id)
|
||||
handleSend(userMsg.content)
|
||||
}
|
||||
|
||||
function handleClickQuestion(question: string) {
|
||||
handleSend(question)
|
||||
}
|
||||
|
||||
/** 请求追问建议,结果挂到对应 AI 消息的 recommendQuestions */
|
||||
async function loadRecommendQuestions(aiMsgId: string, prompt: string) {
|
||||
const last = aiStore.messages.slice(-2).map(m => ({
|
||||
role: m.role === 'user' ? ('user' as const) : ('assistant' as const),
|
||||
content: m.content,
|
||||
}))
|
||||
try {
|
||||
const questions = await fetchRecommendQuestions({
|
||||
botId: agentConfig.botId,
|
||||
lastPair: last,
|
||||
prompt,
|
||||
max: 3,
|
||||
onProgress: (qs) => {
|
||||
aiStore.updateMessage(aiMsgId, { recommendQuestions: qs })
|
||||
},
|
||||
})
|
||||
aiStore.updateMessage(aiMsgId, { recommendQuestions: questions })
|
||||
}
|
||||
catch (error) {
|
||||
console.error('[recommend]', error)
|
||||
}
|
||||
}
|
||||
|
||||
function handleClear() {
|
||||
aiStore.clear()
|
||||
paging.value?.reload()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="h-screen w-full flex flex-col bg-[#F4F6FA]">
|
||||
<!-- 消息列表(聊天模式) -->
|
||||
<view class="min-h-0 flex-1">
|
||||
<z-paging
|
||||
ref="paging"
|
||||
v-model="messages"
|
||||
:default-page-size="50"
|
||||
:auto-show-system-loading="false"
|
||||
:loading-more-enabled="false"
|
||||
:show-refresher-when-reload="false"
|
||||
:show-loading-more-no-more-view="false"
|
||||
use-chat-record-mode
|
||||
auto-adjust-position-when-chat
|
||||
auto-to-bottom-when-chat
|
||||
:paging-style="{ backgroundColor: '#F4F6FA' }"
|
||||
@query="queryList"
|
||||
>
|
||||
<!-- 首屏推荐问题 -->
|
||||
<template v-if="shouldShowInitQuestionCapsules" #top>
|
||||
<agent-header
|
||||
:questions="initQuestionCapsules"
|
||||
@pick="handleClickQuestion"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #default>
|
||||
<agent-message
|
||||
v-for="item in messages"
|
||||
:key="item.id"
|
||||
:message="item"
|
||||
:bot-name="agentConfig.botName"
|
||||
@retry="handleRetry"
|
||||
@pick-recommend="handleClickQuestion"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #bottom>
|
||||
<view>
|
||||
<view class="text-[24rpx] text-[#999] text-center my-[16rpx]">AI建议仅供参考,请以官方政策为准</view>
|
||||
<agent-input
|
||||
:placeholder="agentConfig.placeholder"
|
||||
:loading="loading"
|
||||
@send="handleSend"
|
||||
@stop="handleStop"
|
||||
@clear="handleClear"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
<template #empty>
|
||||
<view />
|
||||
</template>
|
||||
</z-paging>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
//
|
||||
</style>
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
<script lang="ts" setup>
|
||||
import {defaultAgentConfig} from "./agent-config"
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
questions?: string[]
|
||||
}>(), {
|
||||
questions: () => [],
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'pick', question: string): void
|
||||
}>()
|
||||
|
||||
function handlePick(question: string) {
|
||||
emit('pick', question)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="mt-[110rpx] box-border w-full px-[34rpx]">
|
||||
<view
|
||||
class="relative z-0 mb-[-108rpx] h-[210rpx] border-[2rpx] border-white rounded-[100rpx_26rpx_26rpx_26rpx] border-solid bg-[#B0E4FF] bg-opacity-80">
|
||||
<view
|
||||
class="agent-hello__glow absolute bottom-[46rpx] left-[12rpx] z-[2] h-[64rpx] w-[266rpx] rounded-[40rpx] blur-[20rpx]" />
|
||||
<image class="absolute bottom-[70rpx] h-[246rpx] w-[240rpx]"
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/ai_zanyong.png" mode="aspectFit" />
|
||||
<view class="mr-[28rpx] mt-[30rpx] text-right text-[32rpx] text-[#000] font-500 leading-[1.4]">
|
||||
你好,我是你的{{ defaultAgentConfig.botName }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="relative z-[1] box-border border-[2rpx] border-white rounded-[26rpx] border-solid bg-white bg-opacity-70 px-[34rpx] pb-[36rpx] pt-[32rpx] backdrop-blur-[20rpx]">
|
||||
<view class="text-[28rpx] text-[#1F2329] leading-[1.5]">
|
||||
你好,我可以帮你解读济南中考政策、分数线和志愿填报问题。
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="props.questions.length" class="mt-[28rpx] flex flex-wrap gap-[16rpx]">
|
||||
<view v-for="item in props.questions" :key="item"
|
||||
class="border-[1rpx] border-[#E8E8E8] rounded-full border-solid bg-white px-[32rpx] py-[16rpx] text-[30rpx] text-[#000] active:opacity-60"
|
||||
@click="handlePick(item)">
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.agent-hello__glow {
|
||||
background: radial-gradient(ellipse at top, #1580ff, #fff);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
placeholder?: string
|
||||
loading?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'send', text: string): void
|
||||
(event: 'stop'): void
|
||||
(event: 'clear'): void
|
||||
}>()
|
||||
|
||||
const inputValue = ref('')
|
||||
const showActions = ref(false)
|
||||
|
||||
function handleSend() {
|
||||
const text = inputValue.value.trim()
|
||||
if (!text || props.loading) {
|
||||
return
|
||||
}
|
||||
emit('send', text)
|
||||
inputValue.value = ''
|
||||
}
|
||||
|
||||
function toggleActions() {
|
||||
showActions.value = !showActions.value
|
||||
}
|
||||
|
||||
function handleClickClear() {
|
||||
showActions.value = false
|
||||
uni.showModal({
|
||||
title: '清空对话',
|
||||
content: '将删除所有对话记录,确认继续?',
|
||||
confirmColor: '#EB5241',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
emit('clear')
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="flex flex-col bg-white pb-safe">
|
||||
<!-- 输入区 -->
|
||||
<view class="flex items-center gap-[16rpx] px-[24rpx] py-[18rpx]">
|
||||
<view class="flex flex-1 items-center rounded-full bg-[#F5F6F8] p-[16rpx]">
|
||||
<textarea v-model="inputValue" class="max-h-[200rpx] w-full bg-transparent text-[28rpx] text-[#1F2329] ml-[14rpx]"
|
||||
:placeholder="props.placeholder || '有中考问题,直接问我!'" placeholder-style="color:#A6AFBD;font-size:28rpx;"
|
||||
auto-height :show-confirm-bar="false" :adjust-position="true" :cursor-spacing="20" confirm-type="send"
|
||||
@confirm="handleSend" @focus="showActions = false" />
|
||||
<!-- 发送 / 停止 / 展开更多 -->
|
||||
<view v-if="!props.loading && !inputValue.trim()"
|
||||
class="h-[52rpx] w-[52rpx] flex items-center justify-center rounded-full "
|
||||
:class="showActions ? 'rotate-45' : ''" @click="toggleActions">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/ai_tianjia.png"
|
||||
mode="scaleToFill"
|
||||
class="w-[52rpx] h-[52rpx]"
|
||||
/>
|
||||
</view>
|
||||
<view v-else-if="!props.loading"
|
||||
class="h-[52rpx] w-[52rpx] flex items-center justify-center rounded-[36rpx] "
|
||||
@click="handleSend">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/ai_fasong.png"
|
||||
mode="scaleToFill"
|
||||
class="h-[52rpx] w-[52rpx]"
|
||||
/>
|
||||
</view>
|
||||
<view v-else
|
||||
class="h-[52rpx] w-[52rpx] flex items-center justify-center"
|
||||
@click="emit('stop')">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/ai_zanting.png"
|
||||
mode="scaleToFill"
|
||||
class="h-[52rpx] w-[52rpx]"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
<!-- 展开的操作面板 -->
|
||||
<view v-if="showActions" class="flex gap-[16rpx] px-[24rpx] pb-[24rpx] pt-[12rpx]">
|
||||
<view class="flex items-center justify-center p-[20rpx] bg-[#F5F6F8] active:opacity-60"
|
||||
@click="handleClickClear">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/ai_qingkong.png"
|
||||
mode="scaleToFill"
|
||||
class="h-[52rpx] w-[52rpx]"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.rotate-45 {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
<script lang="ts" setup>
|
||||
import type { AiMessage } from '@/store/ai'
|
||||
|
||||
const props = defineProps<{
|
||||
message: AiMessage
|
||||
botName?: string
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
(event: 'retry', id: string): void
|
||||
(event: 'pickRecommend', question: string): void
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="cell-flip flex px-[24rpx] py-[16rpx]"
|
||||
:class="props.message.role === 'user' ? 'justify-end' : 'justify-start'">
|
||||
<!-- AI 头像 -->
|
||||
<!-- <view v-if="props.message.role !== 'user'"
|
||||
class="mr-[16rpx] h-[64rpx] w-[64rpx] flex shrink-0 items-center justify-center rounded-full bg-[#1580FF] text-[24rpx] text-white">
|
||||
AI
|
||||
</view> -->
|
||||
|
||||
<view class="max-w-[90%] flex flex-col gap-[8rpx]">
|
||||
<view class="break-all rounded-[16rpx] px-[24rpx] py-[18rpx] text-[28rpx] leading-[1.6]" :class="props.message.role === 'user'
|
||||
? 'bg-[#1580FF] text-white rounded-tr-[4rpx]'
|
||||
: 'rounded-tl-[4rpx] bg-white text-[#1F2329] shadow-[0_2rpx_12rpx_rgba(0,0,0,0.04)]'">
|
||||
<!-- AI 回复用 markdown 渲染(仅微信小程序) -->
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<markdown-preview v-if="props.message.role !== 'user'"
|
||||
:markdown="props.message.content || (props.message.pending ? '' : '')" :font-size="28" />
|
||||
<text v-else class="select-text">
|
||||
{{ props.message.content }}
|
||||
</text>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- 其它端 fallback -->
|
||||
<!-- #ifndef MP-WEIXIN -->
|
||||
<text class="select-text">
|
||||
{{ props.message.content || (props.message.pending ? '...' : '') }}
|
||||
</text>
|
||||
<!-- #endif -->
|
||||
|
||||
<text v-if="props.message.pending" class="ml-[6rpx] animate-pulse">
|
||||
▍
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view v-if="props.message.error" class="self-start text-[24rpx] text-[#EB5241] leading-[1.4] active:opacity-60"
|
||||
@click="$emit('retry', props.message.id)">
|
||||
生成失败,点击重试
|
||||
</view>
|
||||
|
||||
<!-- 追问建议(仅 AI 消息且生成结束后展示) -->
|
||||
<view
|
||||
v-if="props.message.role === 'assistant' && !props.message.pending && props.message.recommendQuestions && props.message.recommendQuestions.length"
|
||||
class="mt-[8rpx] flex flex-col gap-[12rpx]">
|
||||
<view v-for="q in props.message.recommendQuestions" :key="q"
|
||||
class="self-start border-1 border-[#1580FF] rounded-[24rpx] border-solid bg-white px-[20rpx] py-[10rpx] text-[24rpx] text-[#1580FF] active:opacity-60"
|
||||
@click="$emit('pickRecommend', q)">
|
||||
{{ q }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 用户头像 -->
|
||||
<!-- <view v-if="props.message.role === 'user'"
|
||||
class="ml-[16rpx] h-[64rpx] w-[64rpx] flex shrink-0 items-center justify-center rounded-full bg-[#FFA94D] text-[28rpx] text-white">
|
||||
U
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* z-paging 聊天模式整体 scaleY(-1),cell 必须再反转一次回正 */
|
||||
.cell-flip {
|
||||
transform: scaleY(-1);
|
||||
}
|
||||
|
||||
.animate-pulse {
|
||||
animation: pulse 1.4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
|
||||
0%,
|
||||
80%,
|
||||
100% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
40% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
// AI Agent 相关运行时配置(页面、组件共享)
|
||||
|
||||
/** 组件对接的 AI 类型 */
|
||||
export type ChatMode = 'bot' | 'model'
|
||||
|
||||
export interface AgentConfig {
|
||||
/** 必填:组件对接的 AI 类型;'bot' 走 agent 能力,'model' 走大模型能力 */
|
||||
chatMode: ChatMode
|
||||
/** 微信云开发环境 ID,用于 wx.cloud.init */
|
||||
cloudEnvId: string
|
||||
/** Agent ID,对应 wx.cloud.extend.AI.bot.sendMessage 的 botId(chatMode=bot 必填) */
|
||||
botId: string
|
||||
/** 首屏欢迎语;不设置或留空时不插入欢迎消息 */
|
||||
welcomeMsg?: string
|
||||
/** 输入框 placeholder */
|
||||
placeholder: string
|
||||
/** 显示在 AI 头像位置的图标 / 文字 */
|
||||
botName: string
|
||||
/** 默认推荐问题,点击后直接发送 */
|
||||
initQuestions: string[]
|
||||
}
|
||||
|
||||
export interface ModelConfig {
|
||||
/** createModel 的 provider / GroupName,如 'cloudbase' / 'hunyuan-exp' / 'custom-xxx' */
|
||||
modelProvider: string
|
||||
/** 具体的模型 ID */
|
||||
quickResponseModel: string
|
||||
/** logo 图,可选 */
|
||||
logo: string
|
||||
}
|
||||
|
||||
export const defaultAgentConfig: AgentConfig = {
|
||||
chatMode: 'bot',
|
||||
cloudEnvId: import.meta.env.VITE_CLOUD_ENV_ID,
|
||||
botId: import.meta.env.VITE_CLOUD_BOT_ID,
|
||||
placeholder: '有中考问题,直接问我!',
|
||||
botName: '中考小助手',
|
||||
initQuestions: [
|
||||
'济南500分还能上哪些高中?',
|
||||
'第二批志愿怎么填最稳',
|
||||
'指标生和统招生区别',
|
||||
],
|
||||
}
|
||||
|
||||
/**
|
||||
* model 模式配置示例:
|
||||
* 1. 把 defaultAgentConfig.chatMode 改成 'model'
|
||||
* 2. createModel 传 provider / GroupName,具体模型写在 quickResponseModel
|
||||
*
|
||||
* 对应调用示例:
|
||||
* wx.cloud.extend.AI.createModel('cloudbase').streamText({
|
||||
* data: { model: 'hy3-preview', messages: [...] },
|
||||
* })
|
||||
*/
|
||||
export const defaultModelConfig: ModelConfig = {
|
||||
modelProvider: 'hunyuan-v3',
|
||||
quickResponseModel: 'hy3-preview',
|
||||
logo: '',
|
||||
}
|
||||
|
||||
/** 切换到 model 模式时可直接复用的示例 */
|
||||
export const defaultModelAgentConfig: AgentConfig = {
|
||||
...defaultAgentConfig,
|
||||
chatMode: 'bot',
|
||||
botName: 'AI 模型助手',
|
||||
}
|
||||
|
||||
export function generateMessageId() {
|
||||
const timestamp = Date.now().toString().slice(-8)
|
||||
const random = Math.floor(Math.random() * 10000).toString().padStart(4, '0')
|
||||
return `${timestamp}${random}`
|
||||
}
|
||||
|
|
@ -1,242 +0,0 @@
|
|||
// 与 wx.cloud.extend.AI 通讯的服务层
|
||||
// 根据 chatMode 自动分流:'bot' 走 ai.bot.sendMessage,'model' 走 ai.createModel().streamText
|
||||
// UI 层只关心 onDelta 增量与最终错误,不感知具体走哪条链路
|
||||
|
||||
import type { ChatMode } from './agent-config'
|
||||
import type { AiMessage } from '@/store/ai'
|
||||
import { generateMessageId } from './agent-config'
|
||||
|
||||
interface BotEventData {
|
||||
type: string
|
||||
delta?: string
|
||||
message?: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
interface ModelEventData {
|
||||
id?: string
|
||||
choices?: {
|
||||
delta?: {
|
||||
content?: string
|
||||
reasoning_content?: string
|
||||
role?: string
|
||||
}
|
||||
finish_reason?: string
|
||||
}[]
|
||||
}
|
||||
|
||||
export interface SendMessageOptions {
|
||||
/** 'bot' | 'model' */
|
||||
chatMode: ChatMode
|
||||
/** 历史消息(最近若干轮) */
|
||||
history: AiMessage[]
|
||||
/** 当前用户输入 */
|
||||
prompt: string
|
||||
/** 流式增量回调 */
|
||||
onDelta: (delta: string) => void
|
||||
/** 错误回调,会拿到服务端返回的 message 字段 */
|
||||
onError?: (message: string) => void
|
||||
|
||||
/** chatMode = 'bot' 时必传 */
|
||||
botId?: string
|
||||
/** chatMode = 'bot' 时必传 */
|
||||
threadId?: string
|
||||
|
||||
/** chatMode = 'model' 时必传 */
|
||||
modelProvider?: string
|
||||
/** chatMode = 'model' 时必传 */
|
||||
quickResponseModel?: string
|
||||
}
|
||||
|
||||
export async function streamMessage(options: SendMessageOptions): Promise<string> {
|
||||
if (options.chatMode === 'model') {
|
||||
return streamModel(options)
|
||||
}
|
||||
|
||||
return streamBot(options)
|
||||
}
|
||||
|
||||
function isValidHistoryMessage(message: AiMessage) {
|
||||
return !message.error
|
||||
&& (message.role === 'user' || message.role === 'assistant')
|
||||
&& message.content.trim().length > 0
|
||||
}
|
||||
|
||||
// ---------- bot 模式:wx.cloud.extend.AI.bot.sendMessage ----------
|
||||
|
||||
async function streamBot(options: SendMessageOptions): Promise<string> {
|
||||
const { botId, threadId, history, prompt, onDelta, onError } = options
|
||||
|
||||
if (!botId || !threadId) {
|
||||
throw new Error('chatMode=bot 时必须提供 botId 与 threadId')
|
||||
}
|
||||
|
||||
const messages = [
|
||||
...history
|
||||
.filter(isValidHistoryMessage)
|
||||
.map(m => ({ id: m.id, role: m.role, content: m.content })),
|
||||
{
|
||||
id: generateMessageId(),
|
||||
role: 'user',
|
||||
content: prompt,
|
||||
},
|
||||
]
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// @ts-expect-error wx.cloud.extend 由微信小程序基础库注入
|
||||
const res = await wx.cloud.extend.AI.bot.sendMessage({
|
||||
data: {
|
||||
botId,
|
||||
threadId,
|
||||
runId: `run_id_${generateMessageId()}`,
|
||||
messages,
|
||||
tools: [],
|
||||
context: [],
|
||||
state: {},
|
||||
forwardedProps: {},
|
||||
},
|
||||
})
|
||||
|
||||
let response = ''
|
||||
for await (const event of res.eventStream) {
|
||||
let data: BotEventData
|
||||
try {
|
||||
data = JSON.parse(event.data) as BotEventData
|
||||
}
|
||||
catch {
|
||||
continue
|
||||
}
|
||||
switch (data.type) {
|
||||
case 'TEXT_MESSAGE_CONTENT':
|
||||
if (data.delta) {
|
||||
response += data.delta
|
||||
onDelta(data.delta)
|
||||
}
|
||||
break
|
||||
case 'RUN_ERROR':
|
||||
onError?.(data.message || '请求出错,请稍后再试')
|
||||
throw new Error(data.message || 'RUN_ERROR')
|
||||
case 'RUN_FINISHED':
|
||||
break
|
||||
}
|
||||
}
|
||||
return response
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
throw new Error('AI 助手仅在微信小程序内可用')
|
||||
// #endif
|
||||
}
|
||||
|
||||
// ---------- model 模式:wx.cloud.extend.AI.createModel().streamText ----------
|
||||
|
||||
async function streamModel(options: SendMessageOptions): Promise<string> {
|
||||
const { modelProvider, quickResponseModel, history, prompt, onDelta, onError } = options
|
||||
|
||||
if (!modelProvider || !quickResponseModel) {
|
||||
throw new Error('chatMode=model 时必须提供 modelProvider 与 quickResponseModel')
|
||||
}
|
||||
|
||||
const messages = [
|
||||
...history
|
||||
.filter(isValidHistoryMessage)
|
||||
.map(m => ({ role: m.role, content: m.content })),
|
||||
{ role: 'user', content: prompt },
|
||||
]
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
const ai = wx.cloud.extend.AI
|
||||
const aiModel = ai.createModel(modelProvider)
|
||||
console.log('aimodel创建', aiModel)
|
||||
|
||||
const res = await aiModel.streamText({
|
||||
data: {
|
||||
model: quickResponseModel,
|
||||
messages,
|
||||
},
|
||||
})
|
||||
|
||||
let response = ''
|
||||
try {
|
||||
for await (const event of res.eventStream) {
|
||||
let data: ModelEventData
|
||||
try {
|
||||
data = JSON.parse(event.data) as ModelEventData
|
||||
}
|
||||
catch {
|
||||
continue
|
||||
}
|
||||
const choice = data.choices?.[0]
|
||||
if (choice?.finish_reason === 'stop') {
|
||||
break
|
||||
}
|
||||
const content = choice?.delta?.content
|
||||
if (content) {
|
||||
response += content
|
||||
onDelta(content)
|
||||
}
|
||||
}
|
||||
return response
|
||||
}
|
||||
catch (err) {
|
||||
const message = err instanceof Error ? err.message : '请求出错,请稍后再试'
|
||||
onError?.(message)
|
||||
throw err
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
throw new Error('AI 助手仅在微信小程序内可用')
|
||||
// #endif
|
||||
}
|
||||
|
||||
// ---------- 追问建议(仅 bot 模式且后端支持时使用) ----------
|
||||
|
||||
interface RecommendOptions {
|
||||
botId: string
|
||||
/** 最近一对 user/assistant 消息,用于上下文 */
|
||||
lastPair: { role: 'user' | 'assistant', content: string }[]
|
||||
/** 触发追问的用户原问题 */
|
||||
prompt: string
|
||||
/** 最多返回多少条 */
|
||||
max?: number
|
||||
/** 流式返回时增量更新(用来做"边收边渲染"),可选 */
|
||||
onProgress?: (questions: string[]) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 wx.cloud.extend.AI.bot.getRecommendQuestions 拿追问建议。
|
||||
* 注意:仅旧版 bot-xxx 支持;agent-xxx 调用会 404。
|
||||
*/
|
||||
export async function fetchRecommendQuestions(options: RecommendOptions): Promise<string[]> {
|
||||
const { botId, lastPair, prompt, max = 3, onProgress } = options
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// @ts-expect-error wx.cloud.extend 由微信小程序基础库注入
|
||||
const res = await wx.cloud.extend.AI.bot.getRecommendQuestions({
|
||||
data: {
|
||||
botId,
|
||||
history: lastPair
|
||||
.filter(item => item.content.trim().length > 0)
|
||||
.map(item => ({ role: item.role, content: item.content })),
|
||||
msg: prompt,
|
||||
agentSetting: '',
|
||||
introduction: '',
|
||||
name: '',
|
||||
},
|
||||
})
|
||||
|
||||
let buffer = ''
|
||||
for await (const chunk of res.textStream) {
|
||||
buffer += chunk
|
||||
const questions = buffer.split('\n').map(s => s.trim()).filter(Boolean).slice(0, max)
|
||||
onProgress?.(questions)
|
||||
}
|
||||
|
||||
return buffer.split('\n').map(s => s.trim()).filter(Boolean).slice(0, max)
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
return []
|
||||
// #endif
|
||||
}
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
<script lang="ts" setup>
|
||||
import { useLogin } from '@/pages-fg/hooks/useUserInfo'
|
||||
|
||||
import {
|
||||
getSessionKey,
|
||||
getWxUserInfo,
|
||||
setWxInfo,
|
||||
} from '@/service/'
|
||||
import { useTokenStore, useUserStore } from '@/store'
|
||||
import Checkbox from '../components/check-group/Checkbox.vue'
|
||||
import CheckboxGroup from '../components/check-group/CheckboxGroup.vue'
|
||||
import { useLogin } from '@/pages-fg/hooks/useUserInfo'
|
||||
import { useTokenStore, useUserStore } from '@/store'
|
||||
|
||||
const checked = ref([]) // 是否同意条款
|
||||
const getPhoneInfo = ref(null)
|
||||
|
|
@ -15,8 +16,8 @@ const getPhoneInfo = ref(null)
|
|||
const tokenStore = useTokenStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
async function getPhoneNumber(e: any) {
|
||||
if (e.detail.errMsg === 'getPhoneNumber:ok') {
|
||||
const getPhoneNumber = async (e: any) => {
|
||||
if (e.detail.errMsg == 'getPhoneNumber:ok') {
|
||||
const detail = e.detail
|
||||
const _getPhoneInfo = {
|
||||
iv: detail.iv,
|
||||
|
|
@ -25,14 +26,12 @@ async function getPhoneNumber(e: any) {
|
|||
}
|
||||
getPhoneInfo.value = _getPhoneInfo
|
||||
await getUserInfo(detail.code)
|
||||
}
|
||||
else if (e.detail.errMsg === 'getPhoneNumber:fail not login') {
|
||||
} else if (e.detail.errMsg == 'getPhoneNumber:fail not login') {
|
||||
uni.showToast({
|
||||
title: '请先登录',
|
||||
icon: 'none',
|
||||
})
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '获取手机号失败',
|
||||
icon: 'none',
|
||||
|
|
@ -40,7 +39,7 @@ async function getPhoneNumber(e: any) {
|
|||
}
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
const handleClick = () => {
|
||||
if (!checked.value) {
|
||||
uni.showToast({
|
||||
title: '您需先同意《服务条款》和《隐私条款》',
|
||||
|
|
@ -61,46 +60,49 @@ function handleClick() {
|
|||
}
|
||||
|
||||
// 授权完成之后返回到上一个目录去
|
||||
function handleAuthReady() {
|
||||
const handleAuthReady = () => {
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
function handleClickUserAgreement() {
|
||||
|
||||
|
||||
const handleClickUserAgreement = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages-fg/login/userAgreement',
|
||||
})
|
||||
}
|
||||
|
||||
function handleClickPrivacyPolicy() {
|
||||
const handleClickPrivacyPolicy = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages-fg/login/privacyPolicy',
|
||||
})
|
||||
}
|
||||
|
||||
async function getUserInfo(_code: string) {
|
||||
const userInfo = (await useLogin()) as { code: string, errMsg: string }
|
||||
|
||||
if (userInfo.errMsg === 'login:ok') {
|
||||
|
||||
const getUserInfo = async (_code: string) => {
|
||||
const userInfo = (await useLogin()) as { code: string; errMsg: string }
|
||||
|
||||
if (userInfo.errMsg == 'login:ok') {
|
||||
const resp = await getSessionKey({ query: { JsCode: userInfo.code } })
|
||||
if (resp.code !== 200) {
|
||||
uni.showModal({ title: '登陆失败', content: resp.message })
|
||||
uni.navigateBack()
|
||||
if(resp.code !== 200){
|
||||
uni.showModal({title:'登陆失败',content:resp.message})
|
||||
uni.navigateBack();
|
||||
}
|
||||
|
||||
|
||||
tokenStore.setTokenInfo({ token: resp.result.accessToken, expiresIn: 7 * 24 * 60 * 60 })
|
||||
userStore.setUserOpenId(resp.result.openId)
|
||||
setWxInfo({ options: { query: { code: _code, openId: resp.result.openId } } })
|
||||
getWxUserInfo().then((resp) => {
|
||||
if (resp.code === 200) {
|
||||
setWxInfo({options:{query:{code:_code, openId:resp.result.openId}}})
|
||||
getWxUserInfo().then(resp => {
|
||||
if(resp.code == 200){
|
||||
userStore.setUserExtend(resp.result.userExtend)
|
||||
userStore.setUserInfo({ nickName: resp.result.nickName, mobile: resp.result.mobile })
|
||||
userStore.setUserInfo({nickName:resp.result.nickName,mobile:resp.result.mobile})
|
||||
userStore.setSex(resp.result.sex)
|
||||
userStore.setUserAvatar(resp.result.avatar)
|
||||
}
|
||||
})
|
||||
uni.navigateBack()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '您需先授权',
|
||||
icon: 'none',
|
||||
|
|
@ -111,36 +113,35 @@ async function getUserInfo(_code: string) {
|
|||
|
||||
<template>
|
||||
<view class="h-screen flex flex-col bg-white">
|
||||
<view class="mt-[-100px] flex flex-1 flex-col items-center justify-center pb-safe">
|
||||
<view class="h-[424rpx] w-[424rpx]">
|
||||
<image class="h-[424rpx] w-[424rpx]" src="https://lwzk.ycymedu.com/img/home/logo.png" mode="aspectFit" />
|
||||
<view class="flex flex-col justify-center items-center flex-1 pb-safe mt-[-100px]">
|
||||
<view class="w-[424rpx] h-[424rpx]">
|
||||
<image class="w-[424rpx] h-[424rpx]" src="https://lwzk.ycymedu.com/img/home/logo.png" mode="aspectFit">
|
||||
</image>
|
||||
</view>
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<button
|
||||
class="mb-[40rpx] flex items-center justify-center rounded-[44rpx] text-[32rpx] text-white h-[88rpx]! w-[493rpx]!"
|
||||
:class="checked.length > 0 ? 'bg-[#1580FF]' : 'bg-[#BFBFBF]'" open-type="getPhoneNumber"
|
||||
:disabled="checked.length === 0" @click.stop="handleClick" @getphonenumber="getPhoneNumber"
|
||||
>
|
||||
class="w-[493rpx]! mb-[40rpx] h-[88rpx]! rounded-[44rpx] text-[32rpx] text-white flex items-center justify-center "
|
||||
:class="checked.length > 0 ? 'bg-[#1580FF]' : 'bg-[#BFBFBF]'" @click.stop="handleClick"
|
||||
open-type="getPhoneNumber" @getphonenumber="getPhoneNumber" :disabled="checked.length === 0">
|
||||
一键登录
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- #ifdef MP-ALIPAY -->
|
||||
<button
|
||||
class="mb-[40rpx] flex items-center justify-center rounded-[44rpx] text-[32rpx] text-white h-[88rpx]! w-[493rpx]!"
|
||||
:class="checked.length > 0 ? 'bg-[#1580FF]' : 'bg-[#BFBFBF]'" @click.stop="handleClick"
|
||||
>
|
||||
class="w-[493rpx]! mb-[40rpx] h-[88rpx]! rounded-[44rpx] text-[32rpx] text-white flex items-center justify-center "
|
||||
:class="checked.length > 0 ? 'bg-[#1580FF]' : 'bg-[#BFBFBF]'" @click.stop="handleClick">
|
||||
一键登录
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
|
||||
<view class="flex flex-nowrap items-center">
|
||||
<view class="flex items-center flex-nowrap">
|
||||
<CheckboxGroup v-model="checked" class="check-class mr-[10rpx]">
|
||||
<Checkbox name="1" cell shape="button" class="custom-checkbox" />
|
||||
<Checkbox name="1" cell shape="button" class="custom-checkbox"></Checkbox>
|
||||
</CheckboxGroup>
|
||||
|
||||
<view class="flex items-center">
|
||||
<text class="whitespace-nowrap text-[24rpx]">
|
||||
<text class="text-[24rpx] whitespace-nowrap">
|
||||
已阅读并同意
|
||||
<text class="text-[#1580FF]" @click.stop="handleClickUserAgreement">
|
||||
<text>《用户协议》</text>
|
||||
|
|
|
|||
|
|
@ -1,50 +1,53 @@
|
|||
<script lang="ts" setup>
|
||||
import { useUserStore,useTokenStore } from '@/store'
|
||||
|
||||
import { getAssistant } from '@/service'
|
||||
|
||||
import { useTokenStore, useUserStore } from '@/store'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '六纬AI小助手',
|
||||
},
|
||||
excludeLoginPath: true,
|
||||
style: {
|
||||
navigationBarTitleText: '六纬AI小助手',
|
||||
},
|
||||
excludeLoginPath: true,
|
||||
})
|
||||
|
||||
const userStore = useUserStore()
|
||||
const tokenStore = useTokenStore()
|
||||
|
||||
// chat.ycymedu.com
|
||||
// chatv2.ycymedu.com
|
||||
|
||||
//chat.ycymedu.com
|
||||
//chatv2.ycymedu.com
|
||||
const url = ref(``)
|
||||
|
||||
function handleChildMessage(event) {
|
||||
console.log('子应用传递的消息', event)
|
||||
const handleChildMessage = (event) => {
|
||||
console.log('子应用传递的消息', event)
|
||||
}
|
||||
|
||||
onLoad((options) => {
|
||||
getAssistant().then((res) => {
|
||||
if (res.code === 200) {
|
||||
const data = res.result as unknown as string
|
||||
url.value = `${data}?userId=${userStore.userInfo.userExtend.wxId}&token=${tokenStore.validToken}×tamp=${new Date().getTime()}`
|
||||
}
|
||||
if (options.id) {
|
||||
url.value += `&reportId=${options.id}`
|
||||
}
|
||||
if (options.type) {
|
||||
url.value += `&reportType=${options.type}`
|
||||
}
|
||||
if (options.fileId) {
|
||||
url.value += `&fileId=${options.fileId}`
|
||||
}
|
||||
if (options.talentTypeId) {
|
||||
url.value += `&talentTypeId=${options.talentTypeId}`
|
||||
}
|
||||
})
|
||||
getAssistant().then((res) => {
|
||||
if (res.code === 200) {
|
||||
const data = res.result as unknown as string
|
||||
url.value = `${data}?userId=${userStore.userInfo.userExtend.wxId}&token=${tokenStore.validToken}×tamp=${new Date().getTime()}`
|
||||
}
|
||||
if (options.id) {
|
||||
url.value += `&reportId=${options.id}`
|
||||
}
|
||||
if (options.type) {
|
||||
url.value += `&reportType=${options.type}`
|
||||
}
|
||||
if (options.fileId) {
|
||||
url.value += `&fileId=${options.fileId}`
|
||||
}
|
||||
if (options.talentTypeId){
|
||||
url.value +=`&talentTypeId=${options.talentTypeId}`
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<web-view :src="url" :update-title="false" @message="handleChildMessage" />
|
||||
<web-view :src="url" @message="handleChildMessage" :update-title="false" />
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
|||
|
|
@ -35,10 +35,6 @@ const props = defineProps({
|
|||
readonly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
inputDirection: {
|
||||
type: String as PropType<'text-left' | 'text-right' | 'text-center'>,
|
||||
default: 'text-left'
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -56,7 +52,7 @@ const innerValue = computed({
|
|||
<template>
|
||||
<view class="relative w-full" :class="rootClass">
|
||||
<input :type="type" v-model="innerValue" :placeholder="placeholder" confirm-type="done" :disabled="readonly"
|
||||
:placeholder-style="`color:#C5C8D1;font-size:30rpx;${inputDirection === 'text-right' ? 'text-align:right;' : inputDirection === 'text-center' ? 'text-align:center;' : 'text-align:left;'} `" />
|
||||
placeholder-style="color:#C5C8D1;font-size:30rpx;text-align:left;" class="text-left" />
|
||||
<view class="absolute top-0 left-0 w-full h-full" v-if="readonly"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,89 +1,78 @@
|
|||
<script setup lang="ts">
|
||||
type RadioValue = string | number | null | undefined
|
||||
type RadioOptionValue = string | number | null | undefined
|
||||
type RadioOption = Record<string, RadioOptionValue>
|
||||
|
||||
interface RadioProps {
|
||||
value?: RadioValue
|
||||
options?: RadioOption[]
|
||||
valueKey?: string
|
||||
labelKey?: string
|
||||
customRootClass?: string
|
||||
customRootWidth?: string
|
||||
customRootColsClass?: string
|
||||
customItemClass?: string
|
||||
defaultItemClass?: string
|
||||
activeItemClass?: string
|
||||
}
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: [String,Number],
|
||||
default: ""
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
valueKey: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
labelKey: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
|
||||
const props = withDefaults(defineProps<RadioProps>(), {
|
||||
value: '',
|
||||
options: () => [],
|
||||
valueKey: '',
|
||||
labelKey: '',
|
||||
customRootClass: '',
|
||||
customRootWidth: '',
|
||||
customRootColsClass: 'grid gap-[20rpx] grid-cols-3',
|
||||
customItemClass: '',
|
||||
defaultItemClass: 'bg-[#F3F4F8] border-[#F3F4F8]',
|
||||
activeItemClass: 'bg-white text-[#1580FF] border-[#1580FF]',
|
||||
customRootClass: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
|
||||
customRootWidth:{
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
|
||||
customRootColsClass:{
|
||||
type: String,
|
||||
default: "grid gap-[20rpx] grid-cols-3"
|
||||
},
|
||||
|
||||
customItemClass:{
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
|
||||
defaultItemClass:{
|
||||
type: String,
|
||||
default: "bg-[#F3F4F8] border-[#F3F4F8]"
|
||||
},
|
||||
|
||||
activeItemClass:{
|
||||
type:String,
|
||||
default: "bg-white text-[#1580FF] border-[#1580FF]"
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits<{
|
||||
'update:value': [value: RadioValue]
|
||||
'update:label': [label: string]
|
||||
'change': []
|
||||
}>()
|
||||
|
||||
type ToggleFn = (value: RadioValue) => void
|
||||
|
||||
const getOptionValue = (option: RadioOption): RadioValue => option[props.valueKey]
|
||||
|
||||
function getOptionLabel(option: RadioOption): string {
|
||||
const label = option[props.labelKey]
|
||||
|
||||
return label == null ? '' : String(label)
|
||||
}
|
||||
|
||||
function getOptionKey(option: RadioOption, index: number): string | number {
|
||||
const value = getOptionValue(option)
|
||||
|
||||
return value ?? index
|
||||
}
|
||||
|
||||
const innerValue = computed({
|
||||
get: () => props.value,
|
||||
set: val => emits('update:value', val),
|
||||
get: () => props.value,
|
||||
set: (val) => emits("update:value",val)
|
||||
})
|
||||
const emits = defineEmits(["update:value","update:label","change"])
|
||||
|
||||
function handleToggle(val: RadioValue) {
|
||||
const chooseItem = props.options.find(item => getOptionValue(item) === val)
|
||||
|
||||
emits('update:value', val)
|
||||
emits('update:label', chooseItem ? getOptionLabel(chooseItem) : '')
|
||||
emits('change')
|
||||
}
|
||||
|
||||
function handleOptionClick(option: RadioOption, toggle: ToggleFn) {
|
||||
const value = getOptionValue(option)
|
||||
|
||||
toggle(value)
|
||||
handleToggle(value)
|
||||
const handleToggle = (val:any) => {
|
||||
const chooseItem = props.options.filter(item => item[props.valueKey] === val)
|
||||
emits("update:value",val)
|
||||
emits("update:label",chooseItem[0][props.labelKey])
|
||||
emits("change")
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<sar-radio-group v-model="innerValue">
|
||||
<template #custom="{ toggle, value: currentValue }">
|
||||
<view :class="`bg-white rounded-[0_0_12rpx_12rpx] ${customRootClass} ${customRootColsClass}`">
|
||||
<view
|
||||
v-for="(option, index) in options" :key="getOptionKey(option, index)"
|
||||
:class="`${getOptionValue(option) === currentValue ? activeItemClass : defaultItemClass} ${customItemClass} rounded-[12rpx] text-[28rpx]`"
|
||||
@click="handleOptionClick(option, toggle)"
|
||||
>
|
||||
{{ getOptionLabel(option) }}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</sar-radio-group>
|
||||
</template>
|
||||
<sar-radio-group v-model="innerValue">
|
||||
<template #custom="{ toggle, value }">
|
||||
<view :class="`bg-white rounded-[0_0_12rpx_12rpx] ${customRootClass} ${customRootColsClass}`">
|
||||
<view v-for="val in options" :key="val[valueKey]"
|
||||
:class="`${val[valueKey] === value ? activeItemClass : defaultItemClass} ${customItemClass} rounded-[12rpx] text-[28rpx]`"
|
||||
@click="() => {toggle(val[valueKey]); handleToggle(val[valueKey])}">
|
||||
{{ val[labelKey] }}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</sar-radio-group>
|
||||
</template>
|
||||
|
|
@ -1,18 +1,17 @@
|
|||
<template>
|
||||
<view class="flex items-center bg-gray-100 rounded-full" :class="rootClass" :style="rootStyle">
|
||||
<view class="flex items-center bg-gray-100 rounded-full px-[30rpx] py-[20rpx]" :class="rootClass" :style="rootStyle">
|
||||
|
||||
<view class="w-[32rpx] h-[32rpx] mr-2 flex items-center">
|
||||
<image :src="searchIconUrl" class="w-[32rpx] h-[32rpx]" mode="aspectFit" />
|
||||
<view class="w-[36rpx] h-[36rpx] mr-2 flex items-center">
|
||||
<image :src="searchIconUrl" class="w-[36rpx] h-[36rpx]" mode="aspectFit" />
|
||||
</view>
|
||||
|
||||
<input :value="searchInnerText" :type="inputType" :placeholder="placeholder"
|
||||
<input :value="searchInnerText" type="text" :placeholder="placeholder"
|
||||
class="flex-1 bg-transparent text-sm text-gray-800 outline-none text-start" :class="inputClass" @input="handleInput" @confirm="handleChange" @blur="handleChange"/>
|
||||
|
||||
<view class="w-5 h-5 ml-2 flex items-center" v-if="clearIcon">
|
||||
<image v-if="searchInnerText" src="" class="w-5 h-5" mode="aspectFit" @tap="clearInput" />
|
||||
</view>
|
||||
|
||||
<view v-if="searchIcon" class="text-[30rpx] px-[48rpx] py-[12rpx] bg-[#1580FF] text-[#fff] rounded-full" @click="handleSubmit">查询</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
|
@ -45,17 +44,9 @@ const props = defineProps({
|
|||
type:String,
|
||||
default:''
|
||||
},
|
||||
inputType:{
|
||||
type:String,
|
||||
default:'text'
|
||||
},
|
||||
clearIcon:{
|
||||
type:Boolean,
|
||||
default: true
|
||||
},
|
||||
searchIcon:{
|
||||
type:Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -85,8 +76,4 @@ const handleChange = (event) => {
|
|||
emit('update:searchText', event.detail.value);
|
||||
emit("complete",event.detail.value)
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
emit("submit",searchInnerText.value)
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,40 +1,37 @@
|
|||
<script lang="ts" setup>
|
||||
// code here
|
||||
import RequestComp from './components/request.vue'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '分包页面',
|
||||
},
|
||||
})
|
||||
|
||||
function navigateToVideoFn() {
|
||||
uni.openChannelsLive({
|
||||
finderUserName: 'sphju9MCfZetYHP',
|
||||
success: () => {
|
||||
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('跳转失败:', err)
|
||||
},
|
||||
function gotoScroll() {
|
||||
uni.navigateTo({
|
||||
url: '/pages-sub/demo/scroll',
|
||||
})
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
uni.getChannelsLiveNoticeInfo({
|
||||
finderUserName: 'sphju9MCfZetYHP',
|
||||
success: (res) => {
|
||||
console.log('res', res)
|
||||
},
|
||||
fail: (res) => {
|
||||
console.log(res)
|
||||
},
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="text-center">
|
||||
<button @click="navigateToVideoFn">
|
||||
点击跳视频号
|
||||
<view class="m-8">
|
||||
http://localhost:9000/#/pages-sub/demo/index
|
||||
</view>
|
||||
<view class="my-4 text-green-500">
|
||||
分包页面demo
|
||||
</view>
|
||||
<view class="text-blue-500">
|
||||
分包页面里面的components示例
|
||||
</view>
|
||||
<button class="my-4" type="primary" size="mini" @click="gotoScroll">
|
||||
跳转到上拉刷新和下拉加载更多
|
||||
</button>
|
||||
<view>
|
||||
<RequestComp />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,131 +0,0 @@
|
|||
<script lang="ts" setup>
|
||||
import { systemInfo } from '@/utils/systemInfo'
|
||||
import MxRadioGroup from "@/pages-sub/components/radio/index.vue?async"
|
||||
import { getAreaList, getHistoryYearList, getBatchLine } from "@/service"
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
definePage({
|
||||
style: {
|
||||
navigationStyle: 'custom',
|
||||
},
|
||||
excludeLoginPath: false,
|
||||
})
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
definePage({
|
||||
style: {
|
||||
navigationStyle: 'custom',
|
||||
transparentTitle: 'always',
|
||||
navigationBarTitleText: ''
|
||||
},
|
||||
excludeLoginPath: false,
|
||||
})
|
||||
// #endif
|
||||
|
||||
const handleBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const areaList = ref<any[]>([])
|
||||
|
||||
|
||||
|
||||
|
||||
const searchParams = ref({
|
||||
keyword: '',
|
||||
region: null,
|
||||
nature: null,
|
||||
natureLabel: "",
|
||||
year: null
|
||||
})
|
||||
|
||||
const visibleFlag1 = ref(false)
|
||||
const visibleFlag3 = ref(false)
|
||||
|
||||
const partialData = ref<any[]>([])
|
||||
const yearList = ref<any[]>([])
|
||||
|
||||
const handleChange = () => {
|
||||
visibleFlag1.value = false;
|
||||
visibleFlag3.value = false;
|
||||
getBatchLine({
|
||||
query: {
|
||||
Area: searchParams.value.region,
|
||||
Year: searchParams.value.year
|
||||
}
|
||||
}).then(resp => {
|
||||
partialData.value = resp.result.items
|
||||
})
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
|
||||
Promise.all([
|
||||
getAreaList().then(resp => {
|
||||
if (resp.code === 200) {
|
||||
areaList.value = [{ value: '', label: '不限' }, ...resp.result]
|
||||
}
|
||||
}),
|
||||
getHistoryYearList().then(resp => {
|
||||
if (resp.code === 200) {
|
||||
yearList.value = [...resp.result]
|
||||
searchParams.value.year = yearList.value[yearList.value.length - 1]?.value
|
||||
}
|
||||
})
|
||||
]).then(() => {
|
||||
handleChange()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="gradient-custom flex flex-col h-screen">
|
||||
<sar-navbar title="批次线" :show-back="true" @back="handleBack"
|
||||
:root-style="{ '--sar-navbar-bg': `rgba(255, 255, 255, 0)`, 'padding-top': `${systemInfo?.statusBarHeight}px`, '--sar-navbar-item-color': 'black' }">
|
||||
</sar-navbar>
|
||||
<sar-dropdown
|
||||
root-style="--sar-dropdown-placeholder-color:#666;--sar-dropdown-value-font-size:28rpx;--sar-dropdown-option-active-color:#1580FF;--sar-dropdown-box-shadow:0rpx 6rpx 8rpx 0rpx rgba(0,0,0,0.04);">
|
||||
<sar-dropdown-item v-model:visible="visibleFlag1" :title="searchParams.region || '区域'">
|
||||
<mx-radio-group v-model:value="searchParams.region" :options="areaList" label-key="label" value-key="value"
|
||||
custom-root-class="px-[32rpx] pt-[30rpx] pb-[40rpx]"
|
||||
active-item-class="bg-white text-[#1580FF] border-1 border-solid border-[#1580FF]!"
|
||||
default-item-class="bg-[#F3F4F8] border-[#F3F4F8]"
|
||||
custom-item-class="w-full py-[16rpx] text-center border-[1rpx] border-solid" @change="handleChange" />
|
||||
</sar-dropdown-item>
|
||||
<sar-dropdown-item v-model:visible="visibleFlag3" v-model="searchParams.year" :title="searchParams.year || '年份'">
|
||||
<mx-radio-group v-model:value="searchParams.year" :options="yearList" label-key="label" value-key="value"
|
||||
custom-root-class="px-[32rpx] pt-[30rpx] pb-[40rpx]"
|
||||
custom-item-class="w-full py-[16rpx] text-center border-[1rpx] border-solid"
|
||||
active-item-class="bg-white text-[#1580FF] border-1 border-solid border-[#1580FF]!"
|
||||
default-item-class="bg-[#F3F4F8] border-[#F3F4F8]" @change="handleChange" />
|
||||
</sar-dropdown-item>
|
||||
</sar-dropdown>
|
||||
|
||||
<scroll-view :scroll-y="true" class="flex-1 bg-[#f8f8f8]">
|
||||
<view class="p-[30rpx]">
|
||||
<view class="flex justify-between gap-[40rpx] bg-white rounded-[16rpx] mb-[20rpx] p-[30rpx]"
|
||||
v-for="(val, index) in partialData" :key="index">
|
||||
<view class="max-w-[502rpx]">
|
||||
<view class="text-[30rpx] text-wrap">{{ val.batch }}</view>
|
||||
<view class="flex flex-wrap gap-[10rpx] mt-[10rpx]">
|
||||
<view class="rounded-[8rpx] bg-[#F8F8F8] px-[10rpx] py-[4rpx] text-[24rpx] text-[#666] w-max">{{
|
||||
val.area }}</view>
|
||||
<view class="rounded-[8rpx] bg-[#F8F8F8] px-[10rpx] py-[4rpx] text-[24rpx] text-[#666] w-max">{{ val.year
|
||||
}}</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex text-[#1E40AF] items-center min-w-[100rpx]">
|
||||
<view class="text-[40rpx] font-[DinBold]">
|
||||
{{ val.score }}
|
||||
</view>
|
||||
<view class="text-[24rpx]">分</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -20,7 +20,7 @@ const userStore = useUserStore();
|
|||
const { userInfo } = storeToRefs(userStore)
|
||||
const isStar = ref(false)
|
||||
|
||||
const handlePreviewImage = (src: string, index: number|string) => {
|
||||
const handlePreviewImage = (src: string, index: number) => {
|
||||
uni.previewImage({
|
||||
urls: props.schoolDetail.imageList,
|
||||
current: index,
|
||||
|
|
@ -44,7 +44,7 @@ const starSchool = () => {
|
|||
onLoad(() => {
|
||||
getSchoolCollection().then((resp) => {
|
||||
if (resp.code === 200) {
|
||||
isStar.value = resp.result.some((school:any) => school.id === props.schoolDetail.id)
|
||||
isStar.value = resp.result.some(school => school.id === props.schoolDetail.id)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
@ -57,16 +57,9 @@ onLoad(() => {
|
|||
<view class="flex flex-col">
|
||||
<text class="font-600 text-[40rpx] text-[#000]">{{ schoolDetail.schoolName }}</text>
|
||||
<view class="flex items-center gap-[10rpx] my-[14rpx] flex-wrap" v-if="schoolDetail.tags">
|
||||
<view class="rounded-[8rpx] bg-[#E03C331A] px-[10rpx] py-[4rpx] text-[24rpx] text-[#E03C33] flex items-center gap-[4rpx]" v-if="schoolDetail.schoolName === '济南市深泉外国语学校'">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/xuexiao_remen.png"
|
||||
mode="widthFix"
|
||||
class="w-[24rpx] h-[24rpx]"
|
||||
/>
|
||||
{{ new Date().getFullYear() - 1 }}招生计划完成率100%</view>
|
||||
<view
|
||||
class="bg-[#F8F8F8] px-[10rpx] py-[4rpx] text-[24rpx] text-[#666]"
|
||||
v-for="feature in schoolDetail.tags.split(/[\s,,、]+/)" :key="feature">{{ feature }}</view>
|
||||
class="rounded-[8rpx] bg-[#F8F8F8] px-[10rpx] py-[4rpx] text-[24rpx] text-[#666] first:border-solid border-red border-[1rpx]"
|
||||
v-for="feature in schoolDetail.tags.split('、')" :key="feature">{{ feature }}</view>
|
||||
</view>
|
||||
<view class="text-[#303030] text-[24rpx] mb-[10rpx]">{{ schoolDetail.region }}·{{
|
||||
schoolDetail.schoolNature }}</view>
|
||||
|
|
@ -79,7 +72,7 @@ onLoad(() => {
|
|||
收藏
|
||||
</view>
|
||||
</view>
|
||||
<swiper class="basis-full h-[126rpx] grid grid-cols-3" circular :autoplay="true" :indicator="false" v-if="schoolDetail.imageList"
|
||||
<swiper class="basis-full h-[126rpx]" circular :autoplay="true" :indicator="false" v-if="schoolDetail.imageList"
|
||||
:display-multiple-items="schoolDetail.imageList.length > 2 ? 3 : 1">
|
||||
<swiper-item v-for="(item, index) in schoolDetail.imageList" :key="item" class="flex justify-center">
|
||||
<image :src="item" mode="scaleToFill" class="w-full h-full mx-[4rpx] rounded-[8rpx]"
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ definePage({
|
|||
excludeLoginPath: false,
|
||||
})
|
||||
// #endif
|
||||
const regions = ref<any[]>([])
|
||||
const natureList = ref<any[]>([])
|
||||
const regions = ref([])
|
||||
const natureList = ref([])
|
||||
|
||||
const schoolTypeList = ref<any[]>([])
|
||||
const schoolTypeList = ref([])
|
||||
|
||||
const searchParams = ref({
|
||||
region: null,
|
||||
|
|
@ -68,8 +68,8 @@ onLoad(() => {
|
|||
})
|
||||
})
|
||||
|
||||
const paging = ref<any>(null)
|
||||
const schoolList = ref<any[]>([])
|
||||
const paging = ref(null)
|
||||
const schoolList = ref([])
|
||||
const queryList = (page: number, pageSize: number) => {
|
||||
getBusHightSchoolList({
|
||||
data: {
|
||||
|
|
@ -86,7 +86,7 @@ const queryList = (page: number, pageSize: number) => {
|
|||
}
|
||||
})
|
||||
}
|
||||
const virtualListChange = (_vList:any) => {
|
||||
const virtualListChange = (_vList) => {
|
||||
schoolList.value = _vList
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ const handleComplete = () => {
|
|||
:root-style="{ '--sar-navbar-bg': `rgba(255, 255, 255, 0)`, '--sar-navbar-item-color': 'black', '--sar-navbar-title-max-width': '100%' }">
|
||||
<template #title>
|
||||
<view class="w-[448rpx] ml-[90rpx]">
|
||||
<mx-search root-class="pl-[30rpx] py-[20rpx]" v-model:searchText="searchParams.keyword" placeholder="输入高中名称" @complete="handleComplete"/>
|
||||
<mx-search v-model:searchText="searchParams.keyword" placeholder="输入高中名称" @complete="handleComplete"/>
|
||||
</view>
|
||||
</template>
|
||||
</sar-navbar>
|
||||
|
|
@ -146,16 +146,9 @@ const handleComplete = () => {
|
|||
<view v-for="(val, index) in schoolList" :key="index" class="py-[30rpx] border-b-[#ededed] border-1 border-b-solid"
|
||||
@click="navigateToDetail(val.id)">
|
||||
<view class="text-[#000] text-[32rpx] font-600">{{ val.schoolName }}</view>
|
||||
<view class="flex items-center flex-wrap gap-[12rpx] my-[10rpx]">
|
||||
<view class="rounded-[8rpx] bg-[#E03C331A] px-[10rpx] py-[4rpx] text-[24rpx] text-[#E03C33] flex items-center gap-[4rpx]" v-if="val.schoolName === '济南市深泉外国语学校'">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/xuexiao_remen.png"
|
||||
mode="widthFix"
|
||||
class="w-[24rpx] h-[24rpx]"
|
||||
/>
|
||||
{{ new Date().getFullYear() - 1 }}招生计划完成率100%</view>
|
||||
<view class="flex items-center gap-[12rpx] my-[10rpx]">
|
||||
<view class="rounded-[8rpx] bg-[#F8F8F8] px-[10rpx] py-[4rpx] text-[24rpx] text-[#666]"
|
||||
v-for="feature in val.tags.split(/[\s,,、]+/).slice(0, 2)" :key="feature">{{ feature }}</view>
|
||||
v-for="feature in val.tags.split('、').slice(0, 2)" :key="feature">{{ feature }}</view>
|
||||
</view>
|
||||
<view class="text-[#666] text-[24rpx]">{{ val.region }}·{{val.schoolNature }}</view>
|
||||
</view>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
<script lang="ts" setup>
|
||||
import HighSchoolDetailHeader from './components/HighSchoolDetailHeader.vue'
|
||||
import MxTabs from "@/pages-sub/components/tabs/index.vue"
|
||||
import { systemInfo } from '@/utils/systemInfo'
|
||||
import SchoolIntroduce from './components/SchoolIntroduce.vue'
|
||||
import EnrollmentIntroDetail from './components/EnrollmentIntroDetail.vue'
|
||||
import QuotaAndScore from './components/QuotaAndScore.vue'
|
||||
import { getSchoolInfo } from '@/service'
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
|
|
@ -29,7 +32,7 @@ const handleBack = () => {
|
|||
}
|
||||
|
||||
|
||||
const tabs = [{ name: '院校简介' },]
|
||||
const tabs = [{ name: '院校简介' }, { name: "招生简章" }, { name: '名额分数' }]
|
||||
const activeIndex = ref(0)
|
||||
const handleChange = (val: number) => {
|
||||
activeIndex.value = val
|
||||
|
|
@ -38,7 +41,7 @@ const handleChange = (val: number) => {
|
|||
const schoolDetail = ref({})
|
||||
|
||||
onLoad((options) => {
|
||||
if(options?.id){
|
||||
if(options.id){
|
||||
getSchoolInfo({query:{id:options.id}}).then(resp => {
|
||||
if(resp.code == 200){
|
||||
schoolDetail.value = resp.result
|
||||
|
|
@ -56,9 +59,13 @@ onLoad((options) => {
|
|||
:root-style="{ '--sar-navbar-bg': `rgba(255, 255, 255, 0)`, 'padding-top': `${systemInfo?.statusBarHeight}px`, '--sar-navbar-item-color': 'black' }">
|
||||
</sar-navbar>
|
||||
<HighSchoolDetailHeader :schoolDetail="schoolDetail"/>
|
||||
<mx-tabs :tabsList="tabs" @tab-change="handleChange" />
|
||||
<view class="bg-[#f8f8f8] h-[20rpx]"></view>
|
||||
<SchoolIntroduce :schoolDetail="schoolDetail" v-if="activeIndex === 0" />
|
||||
<EnrollmentIntroDetail :schoolDetail="schoolDetail" v-if="activeIndex === 1" />
|
||||
<QuotaAndScore :schoolDetail="schoolDetail" v-if="activeIndex === 2" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped>
|
||||
//</style>
|
||||
|
|
|
|||
|
|
@ -1,47 +1,39 @@
|
|||
<script lang="ts" setup>
|
||||
import { getNewsDetail } from '@/service'
|
||||
import { getNewsDetail } from "@/service"
|
||||
|
||||
const newsDetail = ref({ title: '', publishTime: '', remark: '', content: '' })
|
||||
const newsDetail = ref({ title: '', publishTime: "", remark: "",content:"" })
|
||||
|
||||
onLoad((options) => {
|
||||
if (options.id) {
|
||||
getNewsDetail({ query: { id: options.id } }).then((resp) => {
|
||||
if (resp.code === 200) {
|
||||
newsDetail.value = resp.result
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
uni.showModal({ title: '没有获取到新闻ID' })
|
||||
}
|
||||
onLoad(options => {
|
||||
if (options.id) {
|
||||
getNewsDetail({ query: { id: options.id } }).then(resp => {
|
||||
if (resp.code == 200) {
|
||||
newsDetail.value = resp.result
|
||||
}
|
||||
})
|
||||
} else {
|
||||
uni.showModal({ title: "没有获取到新闻ID" })
|
||||
}
|
||||
})
|
||||
|
||||
function navigateToCustom() {
|
||||
uni.navigateTo({ url: '/pages-sub/about/onlineCustom' })
|
||||
const navigateToCustom = () => {
|
||||
uni.navigateTo({url:"/pages-sub/about/onlineCustom"})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="px-[30rpx] pt-[30rpx] pb-safe">
|
||||
<view class="text-[40rpx] text-[#000] font-600">
|
||||
{{ newsDetail.title }}
|
||||
</view>
|
||||
<view class="mt-[8rpx] text-[28rpx] text-[#999]">
|
||||
发布时间: {{ newsDetail.publishTime }}
|
||||
</view>
|
||||
<view class="mb-[30rpx] mt-[20rpx] border-b-[2rpx] border-b-[#D8D8D8] border-b-dashed" />
|
||||
<view class="pt-[30rpx]">
|
||||
<!-- <view v-html="newsDetail.content" /> -->
|
||||
<rich-text :nodes="newsDetail.content" />
|
||||
</view>
|
||||
<view class="pt-[30rpx] px-[30rpx] pb-safe">
|
||||
<view class="text-[40rpx] font-600 text-[#000]">{{ newsDetail.title }}</view>
|
||||
<view class="text-[#999] text-[28rpx] mt-[8rpx]">发布时间: {{ newsDetail.publishTime }}</view>
|
||||
<view class="border-b-[2rpx] border-b-dashed border-b-[#D8D8D8] mt-[20rpx] mb-[30rpx]"></view>
|
||||
<view class="pt-[30rpx]">
|
||||
<view v-html="newsDetail.content"></view>
|
||||
</view>
|
||||
|
||||
<view class="fixed bottom-[120rpx] right-[20rpx] h-[160rpx] w-[160rpx]" @click="navigateToCustom">
|
||||
<image
|
||||
src="https://lwzk.ycymedu.com/img/qt/qt_more.png" mode="scaleToFill"
|
||||
class="h-[160rpx] w-[160rpx]"
|
||||
/>
|
||||
<view class="fixed right-[20rpx] bottom-[120rpx] w-[160rpx] h-[160rpx]" @click="navigateToCustom">
|
||||
<image src="https://lwzk.ycymedu.com/img/qt/qt_more.png" mode="scaleToFill"
|
||||
class="w-[160rpx] h-[160rpx]" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -24,8 +24,8 @@ definePage({
|
|||
})
|
||||
// #endif
|
||||
|
||||
const tabs = ref<any[]>([])
|
||||
const articles = ref<any[]>([])
|
||||
const tabs = ref([])
|
||||
const articles = ref([])
|
||||
const handleBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ const toDetailPage = (id: number) => {
|
|||
|
||||
const searchParams = ref({ keyword: "", activeTab: '' })
|
||||
|
||||
const paging = ref<any>(null)
|
||||
const paging = ref(null)
|
||||
|
||||
const queryList = (page: number, pageSize: number) => {
|
||||
if (searchParams.value.activeTab === "") {
|
||||
|
|
@ -69,7 +69,7 @@ const queryList = (page: number, pageSize: number) => {
|
|||
}
|
||||
|
||||
}
|
||||
const virtualListChange = (_vList:any) => {
|
||||
const virtualListChange = (_vList) => {
|
||||
articles.value = _vList
|
||||
}
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ const handleComplete = () => {
|
|||
<sar-navbar title="中考资讯" :show-back="true" @back="handleBack"
|
||||
:root-style="{ '--sar-navbar-bg': `rgba(255, 255, 255, 0)`, 'padding-top': `${systemInfo?.statusBarHeight}px`, '--sar-navbar-item-color': 'black' }">
|
||||
</sar-navbar>
|
||||
<mx-search v-model:searchText="searchParams.keyword" rootStyle="margin: 16rpx 30rpx 0;" root-class="pl-[30rpx] py-[20rpx]" @complete="handleComplete"/>
|
||||
<mx-search v-model:searchText="searchParams.keyword" rootStyle="margin: 16rpx 30rpx 0;" @complete="handleComplete"/>
|
||||
<mx-tabs :tabsList="tabs" rootClass="shadow-md mb-[20rpx]" @tab-change="handleChange" />
|
||||
</view>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<script lang="ts" setup>
|
||||
import MxRadioGroup from '@/pages-sub/components/radio/index.vue?async'
|
||||
import MxSearch from '@/pages-sub/components/search/index.vue?async'
|
||||
import { getAreaList, getHistoryYearList, getSchoolHistoricalScores, getSchoolNature } from '@/service'
|
||||
import { systemInfo } from '@/utils/systemInfo'
|
||||
import MxSearch from "@/pages-sub/components/search/index.vue?async"
|
||||
import MxRadioGroup from "@/pages-sub/components/radio/index.vue?async"
|
||||
import { getAreaList, getHistoryYearList, getSchoolHistoricalScores, getSchoolNature } from "@/service"
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
definePage({
|
||||
|
|
@ -18,211 +18,165 @@ definePage({
|
|||
style: {
|
||||
navigationStyle: 'custom',
|
||||
transparentTitle: 'always',
|
||||
navigationBarTitleText: '',
|
||||
navigationBarTitleText: ''
|
||||
},
|
||||
excludeLoginPath: false,
|
||||
})
|
||||
// #endif
|
||||
|
||||
function handleBack() {
|
||||
const handleBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const areaList = ref<any[]>([])
|
||||
const natureList = ref<any[]>()
|
||||
const areaList = ref([])
|
||||
const natureList = ref([])
|
||||
|
||||
|
||||
|
||||
|
||||
const searchParams = ref({
|
||||
keyword: '',
|
||||
region: null,
|
||||
nature: null,
|
||||
natureLabel: '',
|
||||
year: null,
|
||||
natureLabel: "",
|
||||
year: null
|
||||
})
|
||||
|
||||
const partialColumns = [
|
||||
{
|
||||
title: '院校名称',
|
||||
prop: 'schoolName',
|
||||
width: '32%',
|
||||
align: "left"
|
||||
},
|
||||
{
|
||||
title: '所在区',
|
||||
prop: 'region',
|
||||
width: '16%',
|
||||
align: "center"
|
||||
|
||||
},
|
||||
{
|
||||
title: '统招位次',
|
||||
prop: 'ranking',
|
||||
width: '18%',
|
||||
align: "center"
|
||||
},
|
||||
{
|
||||
title: '办学性质',
|
||||
prop: 'schoolNature',
|
||||
width: '18%',
|
||||
align: "center"
|
||||
},
|
||||
{
|
||||
title: '分数',
|
||||
prop: 'admissionScore',
|
||||
width: '15%',
|
||||
align: "center"
|
||||
},
|
||||
] as const
|
||||
|
||||
const visibleFlag1 = ref(false)
|
||||
const visibleFlag2 = ref(false)
|
||||
const visibleFlag3 = ref(false)
|
||||
|
||||
interface HistoricalScore {
|
||||
schoolName?: string
|
||||
region?: string
|
||||
schoolNature?: string
|
||||
tags?: string
|
||||
ranking?: number | string | null
|
||||
admissionScore?: number | string | null
|
||||
}
|
||||
|
||||
interface PagingRef {
|
||||
reload: () => void
|
||||
complete: (data: HistoricalScore[] | false) => void
|
||||
}
|
||||
|
||||
const paging = ref<PagingRef | null>(null)
|
||||
const partialData = ref<HistoricalScore[]>([])
|
||||
const yearList = ref<any[]>([])
|
||||
|
||||
function handleChange() {
|
||||
visibleFlag1.value = false
|
||||
visibleFlag2.value = false
|
||||
visibleFlag3.value = false
|
||||
paging.value?.reload()
|
||||
}
|
||||
|
||||
function queryList(page: number, _pageSize: number) {
|
||||
if (page > 1) {
|
||||
paging.value?.complete([])
|
||||
return
|
||||
}
|
||||
const partialData = ref([])
|
||||
const yearList = ref([])
|
||||
|
||||
const handleChange = () => {
|
||||
visibleFlag1.value = false;
|
||||
visibleFlag2.value = false;
|
||||
visibleFlag3.value = false;
|
||||
getSchoolHistoricalScores({
|
||||
query: {
|
||||
SchoolName: searchParams.value.keyword,
|
||||
Region: searchParams.value.region,
|
||||
SchoolType: searchParams.value.nature,
|
||||
Year: searchParams.value.year,
|
||||
},
|
||||
}).then((resp) => {
|
||||
if (resp.code === 200) {
|
||||
paging.value?.complete(Array.isArray(resp.result) ? resp.result : [])
|
||||
Year: searchParams.value.year
|
||||
}
|
||||
else {
|
||||
paging.value?.complete(false)
|
||||
}
|
||||
}).catch(() => {
|
||||
paging.value?.complete(false)
|
||||
}).then(resp => {
|
||||
partialData.value = resp.result
|
||||
})
|
||||
}
|
||||
|
||||
function virtualListChange(_vList: HistoricalScore[]) {
|
||||
partialData.value = _vList
|
||||
}
|
||||
|
||||
function getTagList(tags?: string) {
|
||||
return (tags || '').split(/[\s,,、]+/).filter(Boolean).slice(0, 2)
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
Promise.all([
|
||||
getAreaList().then((resp) => {
|
||||
if (resp.code === 200) {
|
||||
areaList.value = [{ value: '', label: '不限' }, ...resp.result]
|
||||
}
|
||||
}),
|
||||
getSchoolNature().then((resp) => {
|
||||
if (resp.code === 200) {
|
||||
natureList.value = [{ value: '', label: '不限' }, ...resp.result]
|
||||
}
|
||||
}),
|
||||
getHistoryYearList().then((resp) => {
|
||||
if (resp.code === 200) {
|
||||
yearList.value = [...resp.result]
|
||||
searchParams.value.year = yearList.value[yearList.value.length - 1]?.value
|
||||
}
|
||||
}),
|
||||
]).then(() => {
|
||||
handleChange()
|
||||
|
||||
getAreaList().then(resp => {
|
||||
if (resp.code === 200) {
|
||||
areaList.value = [{ value: '', label: '不限' }, ...resp.result]
|
||||
}
|
||||
})
|
||||
|
||||
getSchoolNature().then(resp => {
|
||||
if (resp.code === 200) {
|
||||
natureList.value = [{ value: '', label: '不限' }, ...resp.result]
|
||||
}
|
||||
})
|
||||
getHistoryYearList().then(resp => {
|
||||
if (resp.code === 200) {
|
||||
yearList.value = [{ value: '', label: '不限' }, ...resp.result]
|
||||
}
|
||||
})
|
||||
handleChange()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<z-paging
|
||||
ref="paging" use-virtual-list :force-close-inner-list="true" cell-height-mode="dynamic"
|
||||
:auto="false" :auto-show-system-loading="false" :safe-area-inset-bottom="true" :paging-style="{ backgroundColor: '#f8f8f8' }"
|
||||
@virtual-list-change="virtualListChange" @query="queryList"
|
||||
>
|
||||
<template #top>
|
||||
<view class="gradient-custom" :style="{ 'padding-top': `${systemInfo?.statusBarHeight}px` }">
|
||||
<sar-navbar
|
||||
title="历年分数" :show-back="true" :root-style="{ '--sar-navbar-bg': `rgba(255, 255, 255, 0)`, '--sar-navbar-item-color': 'black', '--sar-navbar-title-max-width': '100%' }"
|
||||
@back="handleBack"
|
||||
>
|
||||
<template #title>
|
||||
<view class="ml-[90rpx] w-[448rpx]">
|
||||
<mx-search v-model:search-text="searchParams.keyword" root-class="py-[20rpx] pl-[30rpx]" @complete="handleChange" />
|
||||
</view>
|
||||
</template>
|
||||
</sar-navbar>
|
||||
<view class="gradient-custom flex flex-col h-screen">
|
||||
<sar-navbar title="历年分数" :show-back="true" @back="handleBack"
|
||||
:root-style="{ '--sar-navbar-bg': `rgba(255, 255, 255, 0)`, 'padding-top': `${systemInfo?.statusBarHeight}px`, '--sar-navbar-item-color': 'black' }">
|
||||
</sar-navbar>
|
||||
<mx-search v-model:searchText="searchParams.keyword" rootStyle="margin: 16rpx 30rpx 0;" @complete="handleChange" />
|
||||
<sar-dropdown
|
||||
root-style="--sar-dropdown-placeholder-color:#666;--sar-dropdown-value-font-size:28rpx;--sar-dropdown-option-active-color:#1580FF;--sar-dropdown-box-shadow:0rpx 6rpx 8rpx 0rpx rgba(0,0,0,0.04);">
|
||||
<sar-dropdown-item v-model:visible="visibleFlag1" :title="searchParams.region || '区域'">
|
||||
<mx-radio-group v-model:value="searchParams.region" :options="areaList" label-key="label" value-key="value"
|
||||
custom-root-class="px-[32rpx] pt-[30rpx] pb-[40rpx]"
|
||||
active-item-class="bg-white text-[#1580FF] border-1 border-solid border-[#1580FF]!"
|
||||
default-item-class="bg-[#F3F4F8] border-[#F3F4F8]"
|
||||
custom-item-class="w-full py-[16rpx] text-center border-[1rpx] border-solid" @change="handleChange" />
|
||||
</sar-dropdown-item>
|
||||
<sar-dropdown-item v-model:visible="visibleFlag2" :title="searchParams.natureLabel || '办学性质'">
|
||||
<mx-radio-group v-model:value="searchParams.nature" v-model:label="searchParams.natureLabel"
|
||||
:options="natureList" label-key="label" value-key="value" custom-root-class="px-[32rpx] pt-[30rpx] pb-[40rpx]"
|
||||
active-item-class="bg-white text-[#1580FF] border-1 border-solid border-[#1580FF]!"
|
||||
default-item-class="bg-[#F3F4F8] border-[#F3F4F8]"
|
||||
custom-item-class="w-full py-[16rpx] text-center border-[1rpx] border-solid" @change="handleChange" />
|
||||
</sar-dropdown-item>
|
||||
<sar-dropdown-item v-model:visible="visibleFlag3" v-model="searchParams.year" :title="searchParams.year || '年份'">
|
||||
<mx-radio-group v-model:value="searchParams.year" :options="yearList" label-key="label" value-key="value"
|
||||
custom-root-class="px-[32rpx] pt-[30rpx] pb-[40rpx]"
|
||||
custom-item-class="w-full py-[16rpx] text-center border-[1rpx] border-solid"
|
||||
active-item-class="bg-white text-[#1580FF] border-1 border-solid border-[#1580FF]!"
|
||||
default-item-class="bg-[#F3F4F8] border-[#F3F4F8]" @change="handleChange" />
|
||||
</sar-dropdown-item>
|
||||
</sar-dropdown>
|
||||
|
||||
<sar-dropdown
|
||||
root-style="--sar-dropdown-placeholder-color:#666;--sar-dropdown-value-font-size:28rpx;--sar-dropdown-option-active-color:#1580FF;--sar-dropdown-box-shadow:0rpx 6rpx 8rpx 0rpx rgba(0,0,0,0.04);"
|
||||
>
|
||||
<sar-dropdown-item v-model:visible="visibleFlag1" :title="searchParams.region || '区域'">
|
||||
<mx-radio-group
|
||||
v-model:value="searchParams.region" :options="areaList" label-key="label" value-key="value"
|
||||
custom-root-class="px-[32rpx] pt-[30rpx] pb-[40rpx]"
|
||||
active-item-class="bg-white text-[#1580FF] border-1 border-solid border-[#1580FF]!"
|
||||
default-item-class="bg-[#F3F4F8] border-[#F3F4F8]"
|
||||
custom-item-class="w-full py-[16rpx] text-center border-[1rpx] border-solid" @change="handleChange"
|
||||
/>
|
||||
</sar-dropdown-item>
|
||||
<sar-dropdown-item v-model:visible="visibleFlag2" :title="searchParams.natureLabel || '办学性质'">
|
||||
<mx-radio-group
|
||||
v-model:value="searchParams.nature" v-model:label="searchParams.natureLabel"
|
||||
:options="natureList" label-key="label" value-key="value" custom-root-class="px-[32rpx] pt-[30rpx] pb-[40rpx]"
|
||||
active-item-class="bg-white text-[#1580FF] border-1 border-solid border-[#1580FF]!"
|
||||
default-item-class="bg-[#F3F4F8] border-[#F3F4F8]"
|
||||
custom-item-class="w-full py-[16rpx] text-center border-[1rpx] border-solid" @change="handleChange"
|
||||
/>
|
||||
</sar-dropdown-item>
|
||||
<sar-dropdown-item v-model:visible="visibleFlag3" v-model="searchParams.year" :title="searchParams.year || '年份'">
|
||||
<mx-radio-group
|
||||
v-model:value="searchParams.year" :options="yearList" label-key="label" value-key="value"
|
||||
custom-root-class="px-[32rpx] pt-[30rpx] pb-[40rpx]"
|
||||
custom-item-class="w-full py-[16rpx] text-center border-[1rpx] border-solid"
|
||||
active-item-class="bg-white text-[#1580FF] border-1 border-solid border-[#1580FF]!"
|
||||
default-item-class="bg-[#F3F4F8] border-[#F3F4F8]" @change="handleChange"
|
||||
/>
|
||||
</sar-dropdown-item>
|
||||
</sar-dropdown>
|
||||
<scroll-view :scroll-y="true" class="flex-1">
|
||||
<view class="p-[30rpx]">
|
||||
<sar-table bordered>
|
||||
<sar-table-row>
|
||||
<sar-table-cell v-for="item in partialColumns" :key="item.prop" bold :width="item.width">
|
||||
<view
|
||||
:class="`${item.align === 'center' ? '' : 'pl-[20rpx]'} py-[13rpx] text-[#333] text-[24rpx] font-500 bg-[#F3F4F8]`"
|
||||
:style="{ 'text-align': item.align }">{{ item.title }}</view>
|
||||
</sar-table-cell>
|
||||
</sar-table-row>
|
||||
<sar-table-row v-for="record in partialData" :key="record.id">
|
||||
<sar-table-cell v-for="item in partialColumns" :key="item.prop" :width="item.width">
|
||||
<view :class="`${item.align === 'center' ? '' : 'pl-[20rpx]'} text-[24rpx] text-[#333] py-[13rpx]`"
|
||||
:style="{ 'text-align': item.align }">{{ record[item.prop] }}</view>
|
||||
</sar-table-cell>
|
||||
</sar-table-row>
|
||||
<sar-table-row v-if="partialData.length === 0">
|
||||
<sar-table-cell :colspan="partialColumns.length">
|
||||
<view class="text-center text-[24rpx] text-[#999] py-[20rpx]">暂无数据</view>
|
||||
</sar-table-cell>
|
||||
</sar-table-row>
|
||||
</sar-table>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view class="p-[30rpx]">
|
||||
<view
|
||||
v-for="(val, index) in partialData"
|
||||
:key="index" class="mb-[20rpx] flex justify-between gap-[40rpx] rounded-[16rpx] bg-white p-[30rpx]"
|
||||
>
|
||||
<view class="">
|
||||
<view class="max-w-[408rpx] text-wrap text-[30rpx]">
|
||||
{{ val.schoolName }}
|
||||
</view>
|
||||
<view class="mt-[10rpx] flex flex-wrap gap-[10rpx]">
|
||||
<view class="w-max px-[10rpx] py-[4rpx] text-[24rpx] text-[#666]">
|
||||
{{
|
||||
val.region }}·{{ val.schoolNature }}
|
||||
</view>
|
||||
<view
|
||||
v-for="feature in getTagList(val.tags)"
|
||||
:key="feature" class="rounded-[8rpx] bg-[#F8F8F8] px-[10rpx] py-[4rpx] text-[24rpx] text-[#666]"
|
||||
>
|
||||
{{ feature }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex items-center gap-[30rpx]">
|
||||
<view class="flex flex-col items-end text-[#1E40AF]">
|
||||
<view class="text-[40rpx] font-[DinBold]">
|
||||
{{ val.ranking ?? '--' }}
|
||||
</view>
|
||||
<view class="mt-[10rpx] w-max text-[24rpx]">
|
||||
位次
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex flex-col items-end text-[#1E40AF]">
|
||||
<view class="text-[40rpx] font-[DinBold]">
|
||||
{{ val.admissionScore ?? '--' }}
|
||||
</view>
|
||||
<view class="mt-[10rpx] w-max text-[24rpx]">
|
||||
分数
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import url('@/style/index.scss');
|
||||
</style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ const handleBack = () => {
|
|||
}
|
||||
|
||||
const regionVisible = ref(false)
|
||||
const regions = ref<{label:string;value:string|number}[]>([])
|
||||
const regions = ref([])
|
||||
|
||||
const schools = ref<{schoolName:string}[]>([])
|
||||
const schools = ref([])
|
||||
const searchParams = ref({
|
||||
keyword: "",
|
||||
region: "",
|
||||
|
|
@ -75,7 +75,7 @@ onLoad(() => {
|
|||
</view>
|
||||
</view>
|
||||
<view class="flex-1 ml-[30rpx]">
|
||||
<mx-search root-class="pl-[30rpx] py-[20rpx] mr-[40rpx]" placeholder="输入学校名称" v-model:searchText="searchParams.keyword"
|
||||
<mx-search root-class="mr-[40rpx]" placeholder="输入学校名称" v-model:searchText="searchParams.keyword"
|
||||
@complete="handleChange" />
|
||||
</view>
|
||||
</view>
|
||||
|
|
|
|||
|
|
@ -1,199 +0,0 @@
|
|||
<script lang="ts" setup>
|
||||
import { systemInfo } from '@/utils/systemInfo'
|
||||
import MxRadioGroup from "@/pages-sub/components/radio/index.vue?async"
|
||||
import MxSearch from "@/pages-sub/components/search/index.vue?async"
|
||||
import { getAreaList, getHistoryYearList, getRankTable } from "@/service"
|
||||
import { useUserStore } from "@/store"
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
definePage({
|
||||
style: {
|
||||
navigationStyle: 'custom',
|
||||
},
|
||||
excludeLoginPath: true,
|
||||
})
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
definePage({
|
||||
style: {
|
||||
navigationStyle: 'custom',
|
||||
transparentTitle: 'always',
|
||||
navigationBarTitleText: ''
|
||||
},
|
||||
excludeLoginPath: true,
|
||||
})
|
||||
// #endif
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const handleBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const areaList = ref<any[]>([])
|
||||
|
||||
const searchParams = ref({
|
||||
score: userStore.userInfo.userExtend.expectedScore || '',
|
||||
region: userStore.userInfo.userExtend.area || null,
|
||||
nature: null,
|
||||
natureLabel: "",
|
||||
year: null
|
||||
})
|
||||
|
||||
const visibleFlag1 = ref(false)
|
||||
const visibleFlag3 = ref(false)
|
||||
|
||||
const partialData = ref<any[]>([])
|
||||
const yearList = ref<any[]>([])
|
||||
|
||||
const minScore = ref(0)
|
||||
const maxScore = ref(0)
|
||||
const exceedRatioText = ref("0%")
|
||||
const estimatedRank = ref(0)
|
||||
const nearbyItems = ref<any[]>([])
|
||||
const areaName = ref("")
|
||||
|
||||
const handleChange = () => {
|
||||
visibleFlag1.value = false;
|
||||
visibleFlag3.value = false;
|
||||
getRankTable({
|
||||
query: {
|
||||
Area: searchParams.value.region,
|
||||
Year: searchParams.value.year,
|
||||
Score: searchParams.value.score || 0
|
||||
}
|
||||
}).then(resp => {
|
||||
partialData.value = resp.result.items
|
||||
minScore.value = resp.result.minScore
|
||||
maxScore.value = resp.result.maxScore
|
||||
exceedRatioText.value = resp.result.exceedRatioText
|
||||
estimatedRank.value = resp.result.estimatedRank
|
||||
yearList.value = [...resp.result.years]
|
||||
searchParams.value.year = yearList.value[yearList.value.length - 1]?.value
|
||||
nearbyItems.value = [...resp.result.nearbyItems.reverse()]
|
||||
areaName.value=resp.result.selectedArea
|
||||
|
||||
if (searchParams.value.score === '') {
|
||||
searchParams.value.score = resp.result.minScore
|
||||
handleChange();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleComplete = () => {
|
||||
if(searchParams.value.score === '' || searchParams.value.score < minScore.value){
|
||||
searchParams.value.score = minScore.value
|
||||
} else if(searchParams.value.score > maxScore.value){
|
||||
searchParams.value.score = maxScore.value
|
||||
}
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
|
||||
Promise.all([
|
||||
getAreaList().then(resp => {
|
||||
if (resp.code === 200) {
|
||||
areaList.value = [...resp.result]
|
||||
if(!searchParams.value.region){
|
||||
searchParams.value.region = areaList.value[0]?.value || null
|
||||
}
|
||||
}
|
||||
}),
|
||||
]).then(() => {
|
||||
handleChange()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="gradient-custom flex flex-col h-screen">
|
||||
<sar-navbar title="中考位次" :show-back="true" @back="handleBack"
|
||||
:root-style="{ '--sar-navbar-bg': `rgba(255, 255, 255, 0)`, 'padding-top': `${systemInfo?.statusBarHeight}px`, '--sar-navbar-item-color': 'black' }">
|
||||
</sar-navbar>
|
||||
<sar-dropdown
|
||||
root-style="--sar-dropdown-placeholder-color:#666;--sar-dropdown-value-font-size:28rpx;--sar-dropdown-option-active-color:#1580FF;--sar-dropdown-box-shadow:0rpx 6rpx 8rpx 0rpx rgba(0,0,0,0.04);">
|
||||
<sar-dropdown-item v-model:visible="visibleFlag1" :title="searchParams.region || '区域'">
|
||||
<mx-radio-group v-model:value="searchParams.region" :options="areaList" label-key="label"
|
||||
value-key="value" custom-root-class="px-[32rpx] pt-[30rpx] pb-[40rpx]"
|
||||
active-item-class="bg-white text-[#1580FF] border-1 border-solid border-[#1580FF]!"
|
||||
default-item-class="bg-[#F3F4F8] border-[#F3F4F8]"
|
||||
custom-item-class="w-full py-[16rpx] text-center border-[1rpx] border-solid"
|
||||
@change="handleChange" />
|
||||
</sar-dropdown-item>
|
||||
<sar-dropdown-item v-model:visible="visibleFlag3" v-model="searchParams.year"
|
||||
:title="searchParams.year || '年份'">
|
||||
<mx-radio-group v-model:value="searchParams.year" :options="yearList" label-key="label"
|
||||
value-key="value" custom-root-class="px-[32rpx] pt-[30rpx] pb-[40rpx]"
|
||||
custom-item-class="w-full py-[16rpx] text-center border-[1rpx] border-solid"
|
||||
active-item-class="bg-white text-[#1580FF] border-1 border-solid border-[#1580FF]!"
|
||||
default-item-class="bg-[#F3F4F8] border-[#F3F4F8]" @change="handleChange" />
|
||||
</sar-dropdown-item>
|
||||
</sar-dropdown>
|
||||
<view class="bg-[#F8F8F8] flex-1">
|
||||
<mx-search v-model:searchText="searchParams.score" input-type="number" :searchIcon="true"
|
||||
rootStyle="margin: 32rpx 30rpx 0;background-color:#fff;" root-class="pl-[30rpx]" @complete="handleComplete" @submit="handleChange" />
|
||||
<view class="text-[#9E9E9E] text-[24rpx] bg-[#F8F8F8] ml-[50rpx] my-[20rpx]">支持查询180-660分</view>
|
||||
|
||||
<view class="mx-[30rpx] bg-white px-[30rpx] pt-[30rpx] pb-[20rpx] rounded-[20rpx]">
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="flex flex-col">
|
||||
<view class="text-[#333] font-500 text-[28rpx]">你的预估位次</view>
|
||||
<view class="flex items-baseline text-[#333] text-[28rpx] mt-[20rpx]">
|
||||
<view>约</view>
|
||||
<view class="font-[DinBold] text-[68rpx] font-900 text-[#000] mx-[10rpx]">{{ estimatedRank }}</view>
|
||||
<view>位</view>
|
||||
</view>
|
||||
<view class="text-[24rpx] text-[#666] mt-[20rpx]">超过了{{ areaName }}{{ exceedRatioText }}的学生</view>
|
||||
</view>
|
||||
<image src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/sy_weicichaxun.png"
|
||||
mode="scaleToFill" class="w-[208rpx] h-[208rpx]" />
|
||||
</view>
|
||||
<view class="mt-[30rpx] min-h-[300rpx]">
|
||||
<view class="text-[28rpx] font-500 text-[#333] mb-[10rpx]">附近分数段</view>
|
||||
<view class="">
|
||||
<view class="grid grid-cols-4 bg-[#F3F4F8] text-[24prx] text-[#333] font-500 py-[14rpx]">
|
||||
<view class="flex items-center justify-center">分数</view>
|
||||
<view class="flex items-center justify-center">人数</view>
|
||||
<view class="flex items-center justify-center">累计人数</view>
|
||||
<view class="flex items-center justify-center">超越比例</view>
|
||||
</view>
|
||||
<view class="grid grid-cols-4 py-[8rpx]"
|
||||
:class="searchParams.score === val.score ? 'text-[#1580FF] bg-[#F3F4F8] text-[26prx] font-500' : 'text-[24prx] text-[#666] bg-[#fff]'"
|
||||
v-for="(val, index) in nearbyItems" :key="index">
|
||||
<view class="flex items-center justify-center">{{ val.score }}</view>
|
||||
<view class="flex items-center justify-center">{{ val.currentCount }}</view>
|
||||
<view class="flex items-center justify-center">{{ val.cumulativeCount }}</view>
|
||||
<view class="flex items-center justify-center">{{ val.exceedRatioText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-[#9E9E9E] text-[24rpx] mt-[20rpx] ml-[50rpx]">注:本表数据为累计人数:即分数{{'>'}}该分数的考生总数。</view>
|
||||
<view class="mx-[40rpx] mt-[68rpx] bg-[#FEF6F6] rounded-[16rpx]">
|
||||
<view class="h-[52rpx] w-[178rpx] flex items-center m-[-8rpx] ml-[20rpx]">
|
||||
<image src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/tb_weicishuoming.png" mode="scaleToFill"
|
||||
class="h-[52rpx] w-[178rpx]" />
|
||||
</view>
|
||||
|
||||
<view class="flex flex-col text-[#E03C33] p-[20rpx]">
|
||||
<view class="text-[24rpx] mt-[4rpx]">
|
||||
<view>位次比分数更重要!建议结合近年各高中录取位次,科学填报志愿。 </view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.gradient-custom {
|
||||
background: linear-gradient(180deg, #ecf2ff 0%, #f8f8f8 40rpx, #fff 128rpx);
|
||||
background-position: 50% 50%;
|
||||
background-origin: padding-box;
|
||||
background-clip: border-box;
|
||||
background-size: auto auto;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
<script lang="ts" setup>
|
||||
import { getLiveLinks, trackPromoterRedirect } from '@/service'
|
||||
|
||||
let referralCode = ''
|
||||
let weChatLiveId = import.meta.env.VITE_WX_VIDEO_ID || ''
|
||||
let douyinLiveUrl = ''
|
||||
|
||||
onLoad((options) => {
|
||||
referralCode = options?.referralCode || ''
|
||||
|
||||
getLiveLinks().then((resp) => {
|
||||
douyinLiveUrl = resp?.douyinLiveUrl || ''
|
||||
}).catch((error) => {
|
||||
console.error('[live-links]', error)
|
||||
})
|
||||
})
|
||||
|
||||
function navigateToVideoFn() {
|
||||
if (!weChatLiveId) {
|
||||
uni.showToast({ title: '直播链接获取中,请稍后再试', icon: 'none' })
|
||||
return
|
||||
}
|
||||
uni.openChannelsLive({
|
||||
finderUserName: weChatLiveId,
|
||||
success: () => {
|
||||
if (!referralCode) {
|
||||
return
|
||||
}
|
||||
trackPromoterRedirect(referralCode).catch((error) => {
|
||||
console.error('[redirect]', error)
|
||||
})
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('跳转失败:', err)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function navigateToDouyinFn() {
|
||||
if (!douyinLiveUrl) {
|
||||
uni.showToast({ title: '直播链接获取中,请稍后再试', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!referralCode) {
|
||||
return
|
||||
}
|
||||
trackPromoterRedirect(referralCode).catch((error) => {
|
||||
console.error('[redirect]', error)
|
||||
})
|
||||
uni.setClipboardData({
|
||||
data: douyinLiveUrl,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
uni.showModal({
|
||||
title: '链接已复制',
|
||||
content: '请打开抖音 App 粘贴查看直播',
|
||||
showCancel: false,
|
||||
confirmText: '我知道了',
|
||||
})
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({ title: '复制失败,请稍后重试', icon: 'none' })
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="h-screen w-screen flex flex-col bg-[#F4F6FA]">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/ZZBG.png"
|
||||
mode="widthFix"
|
||||
class="w-full"
|
||||
/>
|
||||
|
||||
<view class="mt-[80rpx] px-[54rpx]">
|
||||
<view class="w-full flex items-center justify-center gap-[16rpx] rounded-[210rpx] bg-[#1580FF] py-[30rpx] text-white font-500" @click="navigateToVideoFn">
|
||||
<view class="h-[52rpx] w-[46rpx] rounded-[210rpx] text-[32rpx]">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/shipin.png"
|
||||
mode="widthFix"
|
||||
/>
|
||||
</view>
|
||||
视频号查看
|
||||
</view>
|
||||
|
||||
<view class="mt-[48rpx] w-full flex items-center justify-center gap-[16rpx] border-1 border-[#1580FF] rounded-[210rpx] border-solid bg-white py-[30rpx] text-[#1580FF] font-500" @click="navigateToDouyinFn">
|
||||
<view class="h-[52rpx] w-[46rpx] rounded-[210rpx] text-[32rpx]">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/douyin.png"
|
||||
mode="widthFix"
|
||||
/>
|
||||
</view>
|
||||
抖音查看
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
<template>
|
||||
<view class="relative min-h-screen flex flex-col bg-[#F6F8FB]">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/fenxiang.png"
|
||||
mode="widthFix"
|
||||
class="absolute left-0 top-0 aspect-[1.75/1] w-full"
|
||||
/>
|
||||
|
||||
<form
|
||||
class="relative z-1 mx-[30rpx] mt-[280rpx] h-max flex flex-col rounded-[20rpx] bg-[#fff] px-[30rpx] pb-[60rpx] pt-[30rpx]"
|
||||
@submit="handleSubmit"
|
||||
>
|
||||
<label class="block">
|
||||
<view class="mb-[12rpx] block text-[28rpx] text-[#111111] font-500 leading-[1]">
|
||||
<text class="text-[#EB5241]">*</text>
|
||||
<text>教师姓名</text>
|
||||
</view>
|
||||
<view class="h-[88rpx] flex items-center gap-[18rpx] border border-[#D9D9D9] rounded-[10rpx] border-solid px-[20rpx]">
|
||||
<input
|
||||
v-model.trim="form.name"
|
||||
class="min-w-0 flex-1 select-text border-none bg-transparent p-0 text-[30rpx] text-[#1F2329] outline-none"
|
||||
type="text"
|
||||
placeholder="请填写教师姓名"
|
||||
confirm-type="next"
|
||||
placeholder-style="color:#A6AFBD;font-size:30rpx;text-align:left;"
|
||||
>
|
||||
</view>
|
||||
</label>
|
||||
|
||||
<label class="mt-[50rpx] block">
|
||||
<view class="mb-[12rpx] block text-[30rpx] text-[#111111] font-500 leading-[1]">
|
||||
<text class="text-[#EB5241]">*</text>
|
||||
<text>教师手机号</text>
|
||||
</view>
|
||||
<view class="h-[88rpx] flex items-center gap-[18rpx] border border-[#D9D9D9] rounded-[10rpx] border-solid px-[20rpx]">
|
||||
<input
|
||||
v-model.trim="form.phone"
|
||||
class="min-w-0 flex-1 select-text border-none bg-transparent p-0 text-[30rpx] text-[#1F2329] outline-none"
|
||||
type="number"
|
||||
:maxlength="11"
|
||||
inputmode="numeric"
|
||||
placeholder="请填写教师手机号"
|
||||
confirm-type="done"
|
||||
placeholder-style="color:#A6AFBD;font-size:30rpx;text-align:left;"
|
||||
@input="handlePhoneInput"
|
||||
>
|
||||
</view>
|
||||
</label>
|
||||
|
||||
<button
|
||||
form-type="submit"
|
||||
class="mx-auto mt-[60rpx] h-[88rpx] w-[480rpx] rounded-[12rpx] border-none bg-[#1580FF] text-[32rpx] text-[#fff] font-500 active:bg-[#1580FF] disabled:bg-[#A9D0FF]"
|
||||
:disabled="!canSubmit || loading"
|
||||
:loading="loading"
|
||||
>
|
||||
{{ loading ? '生成中...' : '生成' }}
|
||||
</button>
|
||||
|
||||
<view
|
||||
v-if="errorMessage"
|
||||
class="mb-0 mt-[24rpx] text-center text-[24rpx] text-[#EB5241] leading-[1.4]"
|
||||
>
|
||||
{{ errorMessage }}
|
||||
</view>
|
||||
</form>
|
||||
|
||||
<view class="mt-[50rpx] px-[30rpx] text-[26rpx] text-[#666] leading-[36rpx]">
|
||||
填写教师信息后,系统将生成专属直播二维码。教师可将二维码分享给学生或家长,学生扫码进入直播间后,系统会自动统计进入人数。
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { Promoter } from '@/service/invite'
|
||||
import { createPromoter } from '@/service'
|
||||
import { useInviteStore } from '@/store/invite'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '教师直播码',
|
||||
},
|
||||
})
|
||||
|
||||
const inviteStore = useInviteStore()
|
||||
|
||||
const loading = ref(false)
|
||||
const errorMessage = ref('')
|
||||
const promoter = ref<Promoter | null>(null)
|
||||
const form = reactive({
|
||||
name: '',
|
||||
phone: '',
|
||||
referralCode: '',
|
||||
})
|
||||
|
||||
onLoad((options) => {
|
||||
console.log('canshu', options)
|
||||
const referralCode = options?.referralCode || options?.code
|
||||
if (referralCode) {
|
||||
form.referralCode = decodeURIComponent(referralCode)
|
||||
}
|
||||
})
|
||||
|
||||
onShareAppMessage(() => {
|
||||
return {
|
||||
title: '六纬中考通',
|
||||
path: '/pages-sub/invite/login',
|
||||
imageUrl: 'https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/zhuanshumafenxiangtu.png',
|
||||
}
|
||||
})
|
||||
|
||||
const canSubmit = computed(() => {
|
||||
return form.name.trim().length > 0 && /^1[3-9]\d{9}$/.test(form.phone)
|
||||
})
|
||||
|
||||
function handlePhoneInput(event: { detail?: { value?: string } }) {
|
||||
form.phone = (event.detail?.value || '').replace(/\D/g, '').slice(0, 11)
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (loading.value) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!form.name.trim()) {
|
||||
uni.showToast({ title: '请填写教师姓名', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
if (!/^1[3-9]\d{9}$/.test(form.phone)) {
|
||||
uni.showToast({ title: '请填写正确手机号', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
errorMessage.value = ''
|
||||
|
||||
try {
|
||||
const result = await createPromoter({
|
||||
name: form.name.trim(),
|
||||
phone: form.phone,
|
||||
referralCode: form.referralCode || undefined,
|
||||
})
|
||||
|
||||
promoter.value = result
|
||||
inviteStore.setPromoter(result)
|
||||
|
||||
uni.showToast({ title: '生成成功', icon: 'success' })
|
||||
uni.navigateTo({ url: '/pages-sub/invite/qrcode' })
|
||||
}
|
||||
catch (error) {
|
||||
const message = error instanceof Error ? error.message : '提交失败,请稍后重试'
|
||||
errorMessage.value = message
|
||||
uni.showToast({ title: message, icon: 'none' })
|
||||
}
|
||||
finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* uni-app 中 button 默认带边框,使用原子化 border-none 已覆盖;如有需要可在此处补充覆盖样式 */
|
||||
button::after {
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
<template>
|
||||
<view class="min-h-screen flex flex-col items-center bg-[#313131]">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/zhuanshuyaoqing.png"
|
||||
mode="widthFix"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useInviteStore } from '@/store/invite'
|
||||
|
||||
const inviteStore = useInviteStore()
|
||||
const referralCode = inviteStore.currentPromoter?.referralCode
|
||||
onShareAppMessage(() => {
|
||||
return {
|
||||
title: '六纬中考通',
|
||||
path: `/pages-sub/invite/jump?referralCode=${referralCode}`,
|
||||
imageUrl: 'https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/yaoqingzhibotu.png',
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
//
|
||||
</style>
|
||||
|
|
@ -9,9 +9,9 @@ definePage({
|
|||
})
|
||||
const wishlistStore = useWishlistStore()
|
||||
|
||||
const wishlist = ref<any[]>([])
|
||||
const wishlist = ref([])
|
||||
|
||||
const handleDeleteWishlist = (val:any,index:number) => {
|
||||
const handleDeleteWishlist = (val,index) => {
|
||||
uni.showModal({
|
||||
title: "确认需要删除吗?", success: ({confirm,cancel}) => {
|
||||
if(confirm){
|
||||
|
|
@ -23,15 +23,15 @@ const handleDeleteWishlist = (val:any,index:number) => {
|
|||
})
|
||||
}
|
||||
|
||||
const getTag = (val:any) => {
|
||||
const getTag = (val) => {
|
||||
let content = JSON.parse(val.contents)
|
||||
let schools = content.schools
|
||||
let zbsTag = schools.some((item:{type:string}) => item.type === '指标生')
|
||||
let zbsTag = schools.some(item => item.type === '指标生')
|
||||
let adjustTag = content.adjust
|
||||
return zbsTag ? "指标生" : adjustTag ? "服从调剂" : false
|
||||
}
|
||||
|
||||
const navigateToDetail = (val:any) => {
|
||||
const navigateToDetail = (val) => {
|
||||
let content = JSON.parse(val.contents)
|
||||
wishlistStore.setExtendWishlist({title:val.title,contents:val.contents,adjust:content.adjust,batchName:val.batchName})
|
||||
uni.navigateTo({url:"/pages-sub/me/wishlistInfo"})
|
||||
|
|
|
|||
|
|
@ -25,12 +25,7 @@ const schools = ref(content.schools)
|
|||
<view v-for="(val, index) in schools" :key="index" class="flex mt-[26rpx]">
|
||||
<view
|
||||
class="py-[29rpx] text-[30rpx] text-[#333] grid gap-[8rpx] bg-white px-[30rpx] py-[20rpx] not-last:mb-[30rpx] rounded-[16rpx] w-full">
|
||||
<view class="text-[32rpx] font-600 flex items-center gap-[10rpx]">
|
||||
<view
|
||||
class="w-[44rpx] h-[44rpx] rounded-[8rpx] text-[26rpx] font-600 flex items-center justify-center"
|
||||
:class="`${val.tags === '稳' ? 'text-[#FA8E23] bg-[#ffeede]' : val.tags === '保' ? 'bg-[#dcf6f0] text-[#15C496]' : 'bg-[#fce5e3] text-[#EB5241]'}`">
|
||||
{{ val.tags }}</view>
|
||||
{{ val.schoolName }}</view>
|
||||
<view class="text-[32rpx] font-600">{{ val.schoolName }}</view>
|
||||
<view class="text-[24rpx] text-[#333]">{{new Date().getFullYear()}}计划招生:{{ val.planCount }}人</view>
|
||||
|
||||
<view class="text-[#333] text-[24rpx]">
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import MxSearch from "@/pages-sub/components/search/index.vue"
|
|||
import MxCheckbox from "@/pages-sub/components/checkbox/index.vue?async"
|
||||
import MxRadio from "@/pages-sub/components/radio/index.vue?async"
|
||||
import { getAreaList, getBusSchoolAdmission, getSchoolNature } from "@/service"
|
||||
import { useWishlistStore,useUserStore } from "@/store"
|
||||
import { useWishlistStore } from "@/store"
|
||||
|
||||
const tableData = ref<any[]>([])
|
||||
const tableData = ref([])
|
||||
const tableColumns = [
|
||||
{ title: '院校名称', prop: 'schoolName', width: '40%', align: 'left' },
|
||||
{ title: '冲稳保', prop: 'tags', width: "15%", align: "center" },
|
||||
|
|
@ -14,10 +14,10 @@ const tableColumns = [
|
|||
] as const
|
||||
|
||||
const wishlistStore = useWishlistStore()
|
||||
const chooseData = ref<any[]>([])
|
||||
const chooseData = ref([])
|
||||
const chooseDataMap = new Map()
|
||||
|
||||
const handleChoose = (val:any) => {
|
||||
const handleChoose = (val) => {
|
||||
|
||||
if (chooseData.value.includes(val.schoolId)) {
|
||||
const index = chooseData.value.indexOf(val.schoolId);
|
||||
|
|
@ -26,14 +26,14 @@ const handleChoose = (val:any) => {
|
|||
chooseDataMap.delete(val.schoolId)
|
||||
}
|
||||
} else {
|
||||
if (chooseData.value.length > 6) {
|
||||
uni.showToast({ title: "志愿最多只能7个", icon: "none" })
|
||||
if (chooseData.value.length > 2) {
|
||||
uni.showToast({ title: "第二志愿最多只能3个", icon: "none" })
|
||||
return;
|
||||
}
|
||||
chooseData.value.push(val.schoolId);
|
||||
chooseDataMap.set(val.schoolId, val)
|
||||
}
|
||||
let tempSchool:any[] = []
|
||||
let tempSchool = []
|
||||
chooseDataMap.forEach((val, key) => {
|
||||
tempSchool.push({ ...val, type: "secondBatch" })
|
||||
})
|
||||
|
|
@ -46,7 +46,6 @@ const cwbs = ref([{ value: '冲', label: '冲' }, { value: '稳', label: '稳' }
|
|||
const natureList = ref([])
|
||||
const totalCount = ref(0)
|
||||
const regions = ref([])
|
||||
const userStore = useUserStore();
|
||||
|
||||
const searchParams = ref({
|
||||
cwb: null,
|
||||
|
|
@ -75,8 +74,7 @@ const handleChangeSchool = () => {
|
|||
schoolName: searchParams.value.keyword,
|
||||
schoolNature: searchParams.value.nature,
|
||||
region: searchParams.value.region,
|
||||
tags: searchParams.value.cwb,
|
||||
score: userStore.userInfo.userExtend.expectedScore || 0
|
||||
tags: searchParams.value.cwb
|
||||
}
|
||||
}).then(resp => {
|
||||
popVisible.value = false;
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
import { systemInfo } from '@/utils/systemInfo'
|
||||
import MxRadio from "@/pages-sub/components/radio/index.vue"
|
||||
import MxInput from "@/pages-sub/components/input/index.vue"
|
||||
import { getGradeList, getAreaList, saveUserAreaScore } from "@/service"
|
||||
import { getGradeList, getAreaList, saveUserInfo } from "@/service"
|
||||
|
||||
import { useUserStore } from "@/store"
|
||||
import { storeToRefs } from "pinia";
|
||||
import { checkEmptyValues } from '@/utils'
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
definePage({
|
||||
|
|
@ -44,15 +45,22 @@ const userStore = useUserStore();
|
|||
const { userInfo } = storeToRefs(userStore)
|
||||
|
||||
const handleSubmit = () => {
|
||||
|
||||
let params = {
|
||||
areaName: userInfo.value.userExtend.area,
|
||||
totalScore: userInfo.value.userExtend.expectedScore,
|
||||
id: userInfo.value.userExtend.id
|
||||
if (!userInfo.value.nickName || !userInfo.value.sex || checkEmptyValues(userInfo.value.userExtend, ["gradeId", "schoolName", "area"])) {
|
||||
uni.showToast({ title: "完善所需信息", icon: "error" })
|
||||
return
|
||||
}
|
||||
saveUserAreaScore({ data: params }).then((resp) => {
|
||||
let params = {
|
||||
nickName: userInfo.value.nickName,
|
||||
gradeId: userInfo.value.userExtend.gradeId,
|
||||
gradeName: userInfo.value.userExtend.gradeName,
|
||||
areaName: userInfo.value.userExtend.area,
|
||||
schoolName: userInfo.value.userExtend.schoolName,
|
||||
sex: userInfo.value.sex,
|
||||
rank: userInfo.value.userExtend.rank
|
||||
}
|
||||
saveUserInfo({ data: params }).then((resp) => {
|
||||
if (resp.code === 200) {
|
||||
uni.navigateTo({ url: '/pages-sub/wishlist/create/secondBatch' })
|
||||
uni.navigateTo({ url: '/pages-sub/wishlist/create/second' })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -109,13 +117,16 @@ onShow(() => {
|
|||
</sar-navbar>
|
||||
|
||||
<view class="flex items-center mx-[30rpx] mb-[20rpx]">
|
||||
|
||||
<view class="w-[112rpx] h-[104rpx] flex items-center">
|
||||
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_01.png" mode="scaleToFill"
|
||||
class="w-[112rpx] h-[104rpx]" />
|
||||
</view>
|
||||
<view class="flex flex-col ml-[10rpx]">
|
||||
<view class="text-[44rpx] font-500 mb-[14rpx]">一键生成志愿表</view>
|
||||
<view class="text-[#B0B3B8] text-[30rpx]">生成我的专属志愿表</view>
|
||||
<view class="text-[44rpx] font-500 mb-[14rpx]">完善基础信息</view>
|
||||
<view class="text-[#B0B3B8] text-[30rpx]">详细的信息获取精准推荐</view>
|
||||
</view>
|
||||
<view class="w-[160rpx] h-[160rpx] ml-auto">
|
||||
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_zk03.png" mode="scaleToFill"
|
||||
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_zk01.png" mode="scaleToFill"
|
||||
class="w-[160rpx] h-[160rpx]" />
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -123,47 +134,86 @@ onShow(() => {
|
|||
|
||||
<form @submit="handleSubmit" class="flex-1 pb-safe">
|
||||
<view class="flex flex-col h-full">
|
||||
|
||||
<view
|
||||
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] px-[30rpx] bg-[#F7F8FA] mb-[20rpx]">
|
||||
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx] ">总分</view>
|
||||
<view class="flex-1 flex items-center">
|
||||
<MxInput type="number" v-model:value="userInfo.userExtend.expectedScore" placeholder="请填写"
|
||||
root-class="text-right" class="w-full" inputDirection="text-right"/>
|
||||
|
||||
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] border-b-1 border-b-[#eaeaea] border-b-solid">
|
||||
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx]">学生姓名</view>
|
||||
<view class="flex-1">
|
||||
<input type="text" v-model="userInfo.nickName" placeholder="请输入姓名" confirm-type="done"
|
||||
placeholder-style="color:#C5C8D1;font-size:30rpx;text-align:left;" class="text-left">
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] px-[30rpx] bg-[#F7F8FA]">
|
||||
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx] ">中考所在区</view>
|
||||
<view class="flex-1 flex items-center" @click="handleOpenPopup('examinationArea')">
|
||||
<MxInput v-model:value="userInfo.userExtend.area" placeholder="请选择您的中考所在区"
|
||||
root-class="text-right" class="w-full" inputDirection="text-right" :readonly="true" />
|
||||
|
||||
<view class="w-[18rpx] h-[36rpx] flex items-center ml-[10rpx]">
|
||||
<view
|
||||
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] border-b-1 border-b-[#eaeaea] border-b-solid">
|
||||
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx]">性别</view>
|
||||
<view class="flex-1 flex items-center" @click="handleOpenPopup('gender')">
|
||||
<MxInput v-model:value="formData.genderLabel" placeholder="请选择您的性别" root-class="text-left"
|
||||
:readonly="true" />
|
||||
|
||||
<view class="w-[18rpx] h-[36rpx] flex items-center ml-auto">
|
||||
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_jiantou.png"
|
||||
mode="scaleToFill" class="w-[18rpx] h-[36rpx]" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] border-b-1 border-b-[#eaeaea] border-b-solid">
|
||||
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx]">年级</view>
|
||||
<view class="flex-1 flex items-center" @click="handleOpenPopup('grade')">
|
||||
<MxInput v-model:value="userInfo.userExtend.gradeName" placeholder="请选择您的年级"
|
||||
root-class="text-left" :readonly="true" />
|
||||
|
||||
<view class="mx-[40rpx] mt-[68rpx] bg-[#FEF6F6] rounded-[16rpx]">
|
||||
<view class="h-[52rpx] w-[178rpx] flex items-center m-[-8rpx] ml-[20rpx]">
|
||||
<image src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/tb_shuoming.png" mode="scaleToFill"
|
||||
class="h-[52rpx] w-[178rpx]" />
|
||||
</view>
|
||||
|
||||
<view class="flex flex-col text-[#E03C33] m-[20rpx]">
|
||||
<view class="text-[24rpx] mt-[4rpx]">
|
||||
<view>根据济南2026年中考招生政策,进入模拟志愿填报阶段的考生,默认历史、生物、地理、道法等水平考试等级均已达到普通高中基础填报要求(C级及以上),本产品仅用于统招平行志愿的模拟。</view>
|
||||
<view class="w-[18rpx] h-[36rpx] flex items-center ml-auto">
|
||||
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_jiantou.png"
|
||||
mode="scaleToFill" class="w-[18rpx] h-[36rpx]" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] border-b-1 border-b-[#eaeaea] border-b-solid">
|
||||
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx] ">中考所在区</view>
|
||||
<view class="flex-1 flex items-center" @click="handleOpenPopup('examinationArea')">
|
||||
<MxInput v-model:value="userInfo.userExtend.area" placeholder="请选择您的中考所在区"
|
||||
root-class="text-left" :readonly="true" />
|
||||
|
||||
<view class="w-[18rpx] h-[36rpx] flex items-center ml-auto">
|
||||
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_jiantou.png"
|
||||
mode="scaleToFill" class="w-[18rpx] h-[36rpx]" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] border-b-1 border-b-[#eaeaea] border-b-solid">
|
||||
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx] ">就读学校</view>
|
||||
<view class="flex-1 flex items-center" @click="navigateToSchool">
|
||||
<view class="flex-1">
|
||||
<MxInput v-model:value="userInfo.userExtend.schoolName" placeholder="请选择您的就读学校"
|
||||
root-class="text-left" :readonly="true" />
|
||||
</view>
|
||||
|
||||
<view class="w-[18rpx] h-[36rpx] flex items-center ml-auto">
|
||||
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_jiantou.png"
|
||||
mode="scaleToFill" class="w-[18rpx] h-[36rpx]" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] border-b-1 border-b-[#eaeaea] border-b-solid">
|
||||
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx] ">校内名次</view>
|
||||
<view class="flex-1 flex items-center">
|
||||
<input type="number" inputmode="numeric" v-model="userInfo.userExtend.rank"
|
||||
placeholder="请输入您的校内名次" confirm-type="done"
|
||||
placeholder-style="color:#C5C8D1;font-size:30rpx;text-align:left;" class="text-left">
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="px-[30rpx] py-[16rpx] border-t-solid border-t-[#ededed] border-t-1 mt-auto">
|
||||
<button form-type="submit" class="rounded-[16rpx] bg-[#1580FF] text-[#fff] submit-btn">开始推荐</button>
|
||||
<button form-type="submit" class="rounded-[16rpx] bg-[#1580FF] text-[#fff] submit-btn">下一步</button>
|
||||
</view>
|
||||
</view>
|
||||
</form>
|
||||
|
|
@ -177,8 +227,19 @@ onShow(() => {
|
|||
mode="scaleToFill" class="w-[36rpx] h-[36rpx]" />
|
||||
</view>
|
||||
</view>
|
||||
<MxRadio v-model:value="userInfo.sex" v-model:label="formData.genderLabel" v-if="activeType == 'gender'"
|
||||
:options="genderClassification" label-key="label" value-key="value"
|
||||
custom-root-cols-class="grid grid-cols-2 items-center gap-[20rpx]"
|
||||
custom-root-class="pb-[20rpx]" custom-item-class="py-[12rpx] text-center "
|
||||
active-item-class="bg-white text-[#1580FF] border-[#1580FF] border-[2rpx] border-solid" @change="visible = false" />
|
||||
|
||||
|
||||
<MxRadio v-model:value="userInfo.userExtend.gradeId" v-model:label="userInfo.userExtend.gradeName"
|
||||
v-if="activeType == 'grade'" :options="gradeClassification" label-key="label" value-key="value"
|
||||
custom-root-cols-class="grid grid-cols-3 items-center gap-[20rpx]"
|
||||
custom-root-class="pb-[20rpx]" custom-item-class="py-[12rpx] text-center "
|
||||
active-item-class="bg-white text-[#1580FF] border-[#1580FF] border-[2rpx] border-solid" @change="visible = false"/>
|
||||
|
||||
<MxRadio v-model:value="userInfo.userExtend.area" v-if="activeType == 'examinationArea'"
|
||||
:options="areaList" label-key="label" value-key="value"
|
||||
custom-root-cols-class="grid grid-cols-3 items-center gap-[20rpx]"
|
||||
|
|
|
|||
|
|
@ -58,15 +58,10 @@ onBackPress(() => {
|
|||
<view v-for="(val, index) in schools" :key="index" class="flex mt-[26rpx]">
|
||||
<view
|
||||
class="py-[29rpx] text-[30rpx] text-[#333] grid gap-[8rpx] bg-white px-[30rpx] py-[20rpx] not-last:mb-[30rpx] rounded-[16rpx] w-full">
|
||||
<view class="text-[32rpx] font-600 flex items-center gap-[10rpx]">
|
||||
<view
|
||||
class="w-[44rpx] h-[44rpx] rounded-[8rpx] text-[26rpx] font-600 flex items-center justify-center"
|
||||
:class="`${val.tags === '稳' ? 'text-[#FA8E23] bg-[#ffeede]' : val.tags === '保' ? 'bg-[#dcf6f0] text-[#15C496]' : 'bg-[#fce5e3] text-[#EB5241]'}`">
|
||||
{{ val.tags }}</view>
|
||||
{{ val.schoolName }}</view>
|
||||
<view class="text-[32rpx] font-600">{{ val.schoolName }}</view>
|
||||
<view class="text-[24rpx] text-[#333]">{{new Date().getFullYear()}}计划招生:{{ val.planCount }}人</view>
|
||||
<!-- <view class="flex items-center">
|
||||
<view class="rgb(173 116 116) bg-[#F8F8F8] rounded-[8rpx] px-[10rpx] py-[4rpx]"
|
||||
<view class="text-[#666] bg-[#F8F8F8] rounded-[8rpx] px-[10rpx] py-[4rpx]"
|
||||
v-for="value in 2" :key="value">重点高中</view>
|
||||
</view> -->
|
||||
<view class="text-[#333] text-[24rpx]">
|
||||
|
|
@ -75,6 +70,24 @@ onBackPress(() => {
|
|||
</view>
|
||||
|
||||
</view>
|
||||
<view class=" bg-[#FEF6F6] rounded-[16rpx] mt-[30rpx]">
|
||||
<view class="h-[52rpx] w-[178rpx] flex items-center m-[-8rpx] ml-[20rpx]">
|
||||
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_shuoming.png"
|
||||
mode="scaleToFill" class="h-[52rpx] w-[178rpx]" />
|
||||
</view>
|
||||
|
||||
<view class="flex flex-col text-[#E03C33] py-[20rpx] pl-[26rpx] pr-[34rpx]">
|
||||
<view class="text-[26rpx] mt-[4rpx]">
|
||||
<view>
|
||||
“二志愿录取成功后,不再进入后续批次。”
|
||||
</view>
|
||||
<view>
|
||||
“建议选择目标明确的学校,同时关注第三批次平行志愿机会。”
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
<view class="grid grid-cols-2 gap-[20rpx] px-[28rpx] py-[16rpx]">
|
||||
<view class="rounded-[16rpx] bg-[#f5f5f5] text-[#333] text-[36rpx] py-[18rpx] text-center" @click="navigateToHome">重新测评</view>
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ const disableSubmit = computed(() => {
|
|||
<sar-navbar show-back @back="handleBack" :fixed="true" fixation-style="top:unset;"
|
||||
:root-style="{ '--sar-navbar-bg': `transparent`, '--sar-navbar-item-color': 'black', 'padding-top': `${systemInfo?.statusBarHeight}px` }">
|
||||
<template #title>
|
||||
<view class="flex justify-center">志愿表</view>
|
||||
<view class="flex justify-center">第二批次</view>
|
||||
</template>
|
||||
</sar-navbar>
|
||||
<view class="flex-1 overflow-y-auto">
|
||||
|
|
@ -93,11 +93,11 @@ const disableSubmit = computed(() => {
|
|||
</view>
|
||||
<view class="text-[30rpx] items-start mt-[50rpx]">
|
||||
<view class="text-[#333]">
|
||||
本工具用于模拟济南中考志愿填报。
|
||||
根据分数、区域和学校信息生成志愿表。
|
||||
结果仅供参考,最终以官方公布为准。
|
||||
未被第一批次录取的考生,可填报第二批次。 可选择3所普通高中。
|
||||
</view>
|
||||
<view class="my-[20rpx] text-[#333]">
|
||||
系统按分数优先投档,平行志愿3所学校并列,不分先后。
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view
|
||||
class="text-[34rpx] font-500 text-white bg-[#1580FF] rounded-full py-[20rpx] text-center mx-[40rpx] mt-[40rpx]"
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ const navigateToFirst = () => {
|
|||
|
||||
const totalScore = ref(0)
|
||||
onLoad(()=>{
|
||||
getMyScore().then(resp => {
|
||||
getMyScore().then(resp => {
|
||||
if (resp.code === 200 && resp.result) {
|
||||
totalScore.value = resp.result.totalScore
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,313 +0,0 @@
|
|||
import { ref } from 'vue'
|
||||
|
||||
type ChannelLiveStatus = 1 | 2 | 3 | 4
|
||||
type ChannelNoticeStatus = 0 | 1 | 2
|
||||
type ChannelVideoType = 'live' | 'notice'
|
||||
|
||||
interface ChannelLiveInfo {
|
||||
feedId?: string
|
||||
nonceId?: string
|
||||
description?: string
|
||||
status?: ChannelLiveStatus
|
||||
headUrl?: string
|
||||
nickname?: string
|
||||
replayStatus?: string
|
||||
otherInfos?: ChannelLiveInfo[]
|
||||
}
|
||||
|
||||
interface ChannelNoticeInfo {
|
||||
noticeId?: string
|
||||
status?: ChannelNoticeStatus
|
||||
startTime?: string
|
||||
headUrl?: string
|
||||
nickname?: string
|
||||
reservable?: boolean
|
||||
otherInfos?: ChannelNoticeInfo[]
|
||||
}
|
||||
|
||||
export interface ChannelVideoItem {
|
||||
id: string
|
||||
type: ChannelVideoType
|
||||
title: string
|
||||
coverUrl: string
|
||||
statusText: string
|
||||
buttonText: string
|
||||
nickname: string
|
||||
startTimeText: string
|
||||
startTimeStamp: number
|
||||
feedId?: string
|
||||
nonceId?: string
|
||||
noticeId?: string
|
||||
reservable?: boolean
|
||||
}
|
||||
|
||||
interface ChannelsQueryApi {
|
||||
getChannelsLiveInfo: (options: {
|
||||
finderUserName: string
|
||||
success: (res: ChannelLiveInfo) => void
|
||||
fail: (err: unknown) => void
|
||||
}) => void
|
||||
getChannelsLiveNoticeInfo: (options: {
|
||||
finderUserName: string
|
||||
success: (res: ChannelNoticeInfo) => void
|
||||
fail: (err: unknown) => void
|
||||
}) => void
|
||||
}
|
||||
|
||||
interface ChannelsActionApi {
|
||||
openChannelsLive: (options: {
|
||||
finderUserName: string
|
||||
feedId?: string
|
||||
nonceId?: string
|
||||
fail: (err: unknown) => void
|
||||
}) => void
|
||||
reserveChannelsLive: (options: {
|
||||
noticeId: string
|
||||
success: () => void
|
||||
fail: (err: unknown) => void
|
||||
}) => void
|
||||
}
|
||||
|
||||
const DEFAULT_CHANNEL_COVER = 'https://lwzk.ycymedu.com/img/home/sy_daoxiao.png'
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null
|
||||
}
|
||||
|
||||
function isFunction(value: unknown): value is (...args: unknown[]) => unknown {
|
||||
return typeof value === 'function'
|
||||
}
|
||||
|
||||
function getChannelsQueryApi(): ChannelsQueryApi | null {
|
||||
const api = uni as unknown
|
||||
|
||||
if (!isRecord(api)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const canGetLiveInfo = isFunction(api.getChannelsLiveInfo)
|
||||
const canGetNoticeInfo = isFunction(api.getChannelsLiveNoticeInfo)
|
||||
|
||||
if (!canGetLiveInfo || !canGetNoticeInfo) {
|
||||
return null
|
||||
}
|
||||
|
||||
return api as unknown as ChannelsQueryApi
|
||||
}
|
||||
|
||||
function getChannelsActionApi(): ChannelsActionApi | null {
|
||||
const api = uni as unknown
|
||||
|
||||
if (!isRecord(api)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const canOpenLive = isFunction(api.openChannelsLive)
|
||||
const canReserveLive = isFunction(api.reserveChannelsLive)
|
||||
|
||||
if (!canOpenLive || !canReserveLive) {
|
||||
return null
|
||||
}
|
||||
|
||||
return api as unknown as ChannelsActionApi
|
||||
}
|
||||
|
||||
function getStartTimeStamp(startTime?: string): number {
|
||||
if (!startTime) {
|
||||
return Number.MAX_SAFE_INTEGER
|
||||
}
|
||||
|
||||
const timestamp = Number(startTime)
|
||||
|
||||
if (Number.isFinite(timestamp)) {
|
||||
return String(Math.trunc(timestamp)).length === 10 ? timestamp * 1000 : timestamp
|
||||
}
|
||||
|
||||
const dateTime = new Date(startTime).getTime()
|
||||
|
||||
return Number.isFinite(dateTime) ? dateTime : Number.MAX_SAFE_INTEGER
|
||||
}
|
||||
|
||||
function formatStartTime(startTime?: string): string {
|
||||
const timestamp = getStartTimeStamp(startTime)
|
||||
|
||||
if (timestamp === Number.MAX_SAFE_INTEGER) {
|
||||
return startTime ? `${startTime}开播` : '直播预告'
|
||||
}
|
||||
|
||||
const date = new Date(timestamp)
|
||||
const month = date.getMonth() + 1
|
||||
const day = date.getDate()
|
||||
const hours = String(date.getHours()).padStart(2, '0')
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0')
|
||||
|
||||
return `${month}.${day} ${hours}:${minutes}开播`
|
||||
}
|
||||
|
||||
function flattenLiveInfo(info: ChannelLiveInfo): ChannelLiveInfo[] {
|
||||
return [info, ...(info.otherInfos ?? [])]
|
||||
}
|
||||
|
||||
function flattenNoticeInfo(info: ChannelNoticeInfo): ChannelNoticeInfo[] {
|
||||
return [info, ...(info.otherInfos ?? [])]
|
||||
}
|
||||
|
||||
function normalizeLiveInfo(info: ChannelLiveInfo, index: number): ChannelVideoItem {
|
||||
const id = info.feedId || info.nonceId || `live-${index}`
|
||||
|
||||
return {
|
||||
id: `live-${id}`,
|
||||
type: 'live',
|
||||
title: info.description || '视频号直播',
|
||||
coverUrl: info.headUrl || DEFAULT_CHANNEL_COVER,
|
||||
statusText: '正在直播',
|
||||
buttonText: '查看直播',
|
||||
nickname: info.nickname || '',
|
||||
startTimeText: '',
|
||||
startTimeStamp: 0,
|
||||
feedId: info.feedId,
|
||||
nonceId: info.nonceId,
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeNoticeInfo(info: ChannelNoticeInfo, index: number): ChannelVideoItem {
|
||||
const id = info.noticeId || `notice-${index}`
|
||||
const startTimeStamp = getStartTimeStamp(info.startTime)
|
||||
|
||||
return {
|
||||
id: `notice-${id}`,
|
||||
type: 'notice',
|
||||
title: info.nickname ? `${info.nickname}的直播预告` : '视频号直播预告',
|
||||
coverUrl: info.headUrl || DEFAULT_CHANNEL_COVER,
|
||||
statusText: formatStartTime(info.startTime),
|
||||
buttonText: info.reservable === false ? '直播预告' : '预约直播',
|
||||
nickname: info.nickname || '',
|
||||
startTimeText: formatStartTime(info.startTime),
|
||||
startTimeStamp,
|
||||
noticeId: info.noticeId,
|
||||
reservable: info.reservable,
|
||||
}
|
||||
}
|
||||
|
||||
function getLiveVideoList(finderUserName: string, channelsApi: ChannelsQueryApi): Promise<ChannelVideoItem[]> {
|
||||
return new Promise((resolve) => {
|
||||
channelsApi.getChannelsLiveInfo({
|
||||
finderUserName,
|
||||
success: (res) => {
|
||||
const liveList = flattenLiveInfo(res)
|
||||
.filter(item => item.status === 2)
|
||||
.map(normalizeLiveInfo)
|
||||
|
||||
resolve(liveList)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('获取视频号直播信息失败:', err)
|
||||
resolve([])
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function getNoticeVideoList(finderUserName: string, channelsApi: ChannelsQueryApi): Promise<ChannelVideoItem[]> {
|
||||
return new Promise((resolve) => {
|
||||
channelsApi.getChannelsLiveNoticeInfo({
|
||||
finderUserName,
|
||||
success: (res) => {
|
||||
const noticeList = flattenNoticeInfo(res)
|
||||
.filter(item => item.status === 0)
|
||||
.map(normalizeNoticeInfo)
|
||||
.sort((prev, next) => prev.startTimeStamp - next.startTimeStamp)
|
||||
|
||||
resolve(noticeList)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('获取视频号直播预告失败:', err)
|
||||
resolve([])
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export function useChannelLive(finderUserName: string) {
|
||||
const channelVideoList = ref<ChannelVideoItem[]>([])
|
||||
|
||||
function goToLiveHomePage(){
|
||||
uni.openChannelsUserProfile({
|
||||
finderUserName,
|
||||
success: () => {
|
||||
console.log('跳转视频号主页成功')
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('跳转视频号主页失败:', err)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async function getChannelLiveNoticeInfo() {
|
||||
if (!finderUserName) {
|
||||
uni.showToast({ title: '直播链接获取中,请稍后再试', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
const channelsApi = getChannelsQueryApi()
|
||||
|
||||
if (!channelsApi) {
|
||||
channelVideoList.value = []
|
||||
return
|
||||
}
|
||||
|
||||
const [liveList, noticeList] = await Promise.all([
|
||||
getLiveVideoList(finderUserName, channelsApi),
|
||||
getNoticeVideoList(finderUserName, channelsApi),
|
||||
])
|
||||
|
||||
channelVideoList.value = [...liveList, ...noticeList]
|
||||
}
|
||||
|
||||
function handleChannelVideoAction(item: ChannelVideoItem) {
|
||||
const channelsApi = getChannelsActionApi()
|
||||
|
||||
if (!channelsApi) {
|
||||
return
|
||||
}
|
||||
|
||||
if (item.type === 'live') {
|
||||
channelsApi.openChannelsLive({
|
||||
finderUserName,
|
||||
feedId: item.feedId,
|
||||
nonceId: item.nonceId,
|
||||
fail: (err) => {
|
||||
console.error('跳转视频号直播失败:', err)
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!item.noticeId || item.reservable === false) {
|
||||
uni.showToast({ title: '该直播暂不可预约', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
channelsApi.reserveChannelsLive({
|
||||
noticeId: item.noticeId,
|
||||
success: () => {
|
||||
uni.showModal({
|
||||
title: '预约成功',
|
||||
content: `开播时间: ${item.startTimeText} 请留意视频号消息提醒。`,
|
||||
showCancel: false,
|
||||
confirmText:'我知道了',
|
||||
})
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('预约视频号直播失败:', err)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
channelVideoList,
|
||||
getChannelLiveNoticeInfo,
|
||||
handleChannelVideoAction,
|
||||
goToLiveHomePage
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<script lang="ts" setup>
|
||||
import { getCountdown, getFirstPageInfo, getMyScore, getTopNew } from '@/service'
|
||||
import { useTokenStore } from '@/store'
|
||||
import { systemInfo } from '@/utils/systemInfo'
|
||||
import { useChannelLive } from './hooks/useChannelLive'
|
||||
import { getMyScore, getTopNew, getCountdown, getFirstPageInfo } from "@/service"
|
||||
import { useTokenStore } from '@/store'
|
||||
|
||||
|
||||
defineOptions({
|
||||
name: 'Home',
|
||||
|
|
@ -29,8 +29,7 @@ definePage({
|
|||
// #endif
|
||||
|
||||
const tokenStore = useTokenStore()
|
||||
const wechatVideoId = import.meta.env.VITE_WX_VIDEO_ID || ''
|
||||
const { channelVideoList, getChannelLiveNoticeInfo, handleChannelVideoAction,goToLiveHomePage } = useChannelLive(wechatVideoId)
|
||||
console.log(systemInfo);
|
||||
|
||||
onShareAppMessage(() => {
|
||||
return {
|
||||
|
|
@ -45,22 +44,17 @@ onShareTimeline(() => {
|
|||
}
|
||||
})
|
||||
|
||||
const subMenus = [
|
||||
{ name: '历年分数', imgPath: 'https://lwzk.ycymedu.com/img/home/sy_fenshu.png', url: '/pages-sub/information/overTheYear' },
|
||||
{ name: '高中汇总', imgPath: 'https://lwzk.ycymedu.com/img/home/sy_daoxiao.png', url: '/pages-sub/information/highSchool' },
|
||||
{ name: '批次线', imgPath: 'https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/sy_picixian.png', url: '/pages-sub/information/batchline' },
|
||||
{ name: '位次查询', imgPath: 'https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/syweici.png', url: '/pages-sub/information/rank' },
|
||||
]
|
||||
const subMenus = [{ name: '中考资讯', imgPath: 'https://lwzk.ycymedu.com/img/home/sy_zixun.png', url: "/pages-sub/information/middleSchool" }, { name: '高中汇总', imgPath: 'https://lwzk.ycymedu.com/img/home/sy_huizong.png', url: '/pages-sub/information/highSchool' }, { name: '历年分数', imgPath: 'https://lwzk.ycymedu.com/img/home/sy_fenshu.png', url: '/pages-sub/information/overTheYear' }, { name: '指标生', imgPath: 'https://lwzk.ycymedu.com/img/home/sy_daoxiao.png', url: '/pages-sub/information/quota' }]
|
||||
|
||||
const notifies = ref<any[]>([])
|
||||
const notifies = ref([])
|
||||
|
||||
const opacity = ref(0)
|
||||
const totalScore = ref('0')
|
||||
const schoolCount = ref('0')
|
||||
const wishlistCount = ref('0')
|
||||
const totalScore = ref("0")
|
||||
const schoolCount = ref("0")
|
||||
const wishlistCount = ref("0")
|
||||
|
||||
function navigateToCreateWish() {
|
||||
uni.navigateTo({ url: '/pages-sub/wishlist/create/first' })
|
||||
const navigateToCreateWish = () => {
|
||||
uni.navigateTo({ url: "/pages-sub/wishlist/create/first" })
|
||||
}
|
||||
|
||||
onPageScroll((e) => {
|
||||
|
|
@ -68,25 +62,25 @@ onPageScroll((e) => {
|
|||
opacity.value = Math.min(scrollTop / 100, 1)
|
||||
})
|
||||
|
||||
function navigateToCountdownPage() {
|
||||
const navigateToCountdownPage = () => {
|
||||
uni.navigateTo({ url: '/pages-sub/countdown/index' })
|
||||
}
|
||||
|
||||
function navigateToSubPage(url: string) {
|
||||
const navigateToSubPage = (url: string) => {
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
|
||||
function navigateToCustom() {
|
||||
uni.navigateTo({ url: '/pages-sub/about/onlineCustom' })
|
||||
const navigateToCustom = () => {
|
||||
uni.navigateTo({ url: "/pages-sub/about/onlineCustom" })
|
||||
}
|
||||
|
||||
function navigateToNewsPage() {
|
||||
const navigateToNewsPage = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages-sub/information/middleSchool',
|
||||
url: '/pages-sub/information/middleSchool'
|
||||
})
|
||||
}
|
||||
|
||||
function navigateToNewsDetail(id: number) {
|
||||
const navigateToNewsDetail = (id: number) => {
|
||||
uni.navigateTo({ url: `/pages-sub/information/middleDetail?id=${id}` })
|
||||
}
|
||||
|
||||
|
|
@ -94,7 +88,7 @@ const countdown = ref(0)
|
|||
|
||||
onLoad(() => {
|
||||
const updateManager = uni.getUpdateManager()
|
||||
updateManager.onCheckForUpdate((res) => {
|
||||
updateManager.onCheckForUpdate(function (res) {
|
||||
// 请求完新版本信息的回调
|
||||
if (res.hasUpdate) {
|
||||
uni.showToast({
|
||||
|
|
@ -104,11 +98,11 @@ onLoad(() => {
|
|||
}
|
||||
})
|
||||
|
||||
updateManager.onUpdateReady(() => {
|
||||
updateManager.onUpdateReady(function () {
|
||||
uni.showModal({
|
||||
title: '更新提示',
|
||||
content: '新版本已经准备好,是否重启应用?',
|
||||
success(res) {
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||
updateManager.applyUpdate()
|
||||
|
|
@ -117,279 +111,167 @@ onLoad(() => {
|
|||
})
|
||||
})
|
||||
|
||||
updateManager.onUpdateFailed(() => {
|
||||
updateManager.onUpdateFailed(function () {
|
||||
// 新版本下载失败
|
||||
uni.showToast({
|
||||
title: '更新失败',
|
||||
icon: 'none',
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
getTopNew({ query: { Top: 3 } }).then((resp) => {
|
||||
getTopNew({ query: { Top: 3 } }).then(resp => {
|
||||
if (resp.code === 200) {
|
||||
notifies.value = resp.result
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
if (tokenStore.hasLogin) {
|
||||
getMyScore().then((resp) => {
|
||||
getMyScore().then(resp => {
|
||||
if (resp.code === 200 && resp.result) {
|
||||
totalScore.value = resp.result.totalScore
|
||||
}
|
||||
})
|
||||
getFirstPageInfo().then((resp) => {
|
||||
getFirstPageInfo().then(resp => {
|
||||
if (resp.code === 200) {
|
||||
schoolCount.value = resp.result.schoolCount
|
||||
wishlistCount.value = resp.result.zyCount
|
||||
}
|
||||
})
|
||||
}
|
||||
getCountdown().then((resp) => {
|
||||
getCountdown().then(resp => {
|
||||
if (resp.code === 200) {
|
||||
countdown.value = resp.result
|
||||
}
|
||||
})
|
||||
|
||||
getChannelLiveNoticeInfo()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="custom-background flex flex-col">
|
||||
<sar-navbar
|
||||
:fixed="true" fixation-style="top:unset;"
|
||||
:root-style="{ '--sar-navbar-bg': `rgba(255, 255, 255, ${opacity})`, '--sar-navbar-height': `${systemInfo?.statusBarHeight + 44}px` }"
|
||||
>
|
||||
<sar-navbar :fixed="true" fixation-style="top:unset;"
|
||||
:root-style="{ '--sar-navbar-bg': `rgba(255, 255, 255, ${opacity})`, '--sar-navbar-height': `${systemInfo?.statusBarHeight + 44}px` }">
|
||||
<template #left>
|
||||
<view
|
||||
class="ml-[32rpx] flex items-center justify-center text-[32rpx] text-[#333]"
|
||||
:style="{ 'padding-top': `${systemInfo?.statusBarHeight}px` }"
|
||||
>
|
||||
济南
|
||||
</view>
|
||||
<view class="flex items-center justify-center text-[#333] text-[32rpx] ml-[32rpx]"
|
||||
:style="{ 'padding-top': `${systemInfo?.statusBarHeight}px` }">济南</view>
|
||||
</template>
|
||||
<template #title>
|
||||
<view :style="{ 'padding-top': `${systemInfo?.statusBarHeight}px` }" class="flex justify-center">
|
||||
<view class="h-[32rpx] w-[226rpx] flex justify-center">
|
||||
<image
|
||||
class="h-[32rpx] w-[226rpx]" src="https://lwzk.ycymedu.com/img/home/sy_logo.png"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<image class="h-[32rpx] w-[226rpx]" src="https://lwzk.ycymedu.com/img/home/sy_logo.png"
|
||||
mode="aspectFit" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</sar-navbar>
|
||||
<scroll-view scroll-y class="flex-1">
|
||||
<view class="mx-[40rpx] mt-[20rpx] min-h-[460rpx] overflow-hidden rounded-[32rpx] bg-[#3D72FD] font-[DinBold]">
|
||||
<view class="mx-[40rpx] bg-[#3D72FD] rounded-[32rpx] min-h-[460rpx] mt-[20rpx] font-[DinBold] overflow-hidden">
|
||||
<view
|
||||
v-if="countdown > 0"
|
||||
class="flex items-baseline justify-center rounded-[32rpx] bg-[#4c7bfc] py-[18rpx] text-[36rpx] text-white font-[JinBuFont]" @click="navigateToCountdownPage"
|
||||
>
|
||||
class="bg-[#4c7bfc] flex items-baseline justify-center rounded-[32rpx] py-[18rpx] text-white text-[36rpx] font-[JinBuFont]"
|
||||
@click="navigateToCountdownPage" v-if="countdown > 0">
|
||||
距离中考还有 <text class="text-[52rpx] text-white">{{ countdown }}</text> 天
|
||||
<view class="ml-[10rpx] h-[24rpx] w-[14rpx]">
|
||||
<image
|
||||
src="https://lwzk.ycymedu.com/img/home/sy_gengduo.png" mode="scaleToFill"
|
||||
class="h-[24rpx] w-[14rpx]"
|
||||
/>
|
||||
<view class="w-[14rpx] h-[24rpx] ml-[10rpx]">
|
||||
<image src="https://lwzk.ycymedu.com/img/home/sy_gengduo.png" mode="scaleToFill"
|
||||
class="w-[14rpx] h-[24rpx]" />
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
v-else
|
||||
class="flex items-baseline justify-center rounded-[32rpx] bg-[#4c7bfc] py-[18rpx] text-[36rpx] text-white font-[JinBuFont]"
|
||||
>
|
||||
class="bg-[#4c7bfc] flex items-baseline justify-center rounded-[32rpx] py-[18rpx] text-white text-[36rpx] font-[JinBuFont]"
|
||||
v-else>
|
||||
正在考试
|
||||
</view>
|
||||
<view class="mt-[48rpx] flex items-center justify-between pl-[46rpx] pr-[64rpx]">
|
||||
<view class="flex flex-col items-center gap-[8rpx] text-white">
|
||||
<view class="flex items-center justify-between mt-[48rpx] pl-[46rpx] pr-[64rpx]">
|
||||
<view class="flex flex-col text-white items-center gap-[8rpx]">
|
||||
<view class="flex items-center">
|
||||
<text class="text-[68rpx] font-700">{{ totalScore }}</text>
|
||||
<view class="ml-[4rpx] h-[30rpx] w-[30rpx]">
|
||||
<image
|
||||
class="h-[30rpx] w-[30rpx]"
|
||||
src="https://lwzk.ycymedu.com/img/home/sy_bianji.png" mode="scaleToFill"
|
||||
/>
|
||||
<view class="w-[30rpx] h-[30rpx] ml-[4rpx]">
|
||||
<image class="w-[30rpx] h-[30rpx]"
|
||||
src="https://lwzk.ycymedu.com/img/home/sy_bianji.png" mode="scaleToFill" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-[30rpx] text-[#b0c6ff]">
|
||||
预估成绩
|
||||
</view>
|
||||
<view class="text-[30rpx] text-[#b0c6ff]">预估成绩</view>
|
||||
</view>
|
||||
|
||||
<view class="flex flex-col items-center gap-[8rpx] text-white">
|
||||
<view class="flex flex-col text-white items-center gap-[8rpx]">
|
||||
<view class="flex items-baseline">
|
||||
<text class="text-[68rpx] font-700">{{ schoolCount }}</text>
|
||||
<view class="ml-[4rpx] text-[32rpx]">
|
||||
所
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-[30rpx] text-[#b0c6ff]">
|
||||
适合普高
|
||||
<view class="text-[32rpx] ml-[4rpx]">所</view>
|
||||
</view>
|
||||
<view class="text-[30rpx] text-[#b0c6ff]">适合普高</view>
|
||||
</view>
|
||||
|
||||
<view class="flex flex-col items-center gap-[8rpx] text-white">
|
||||
<view class="flex flex-col text-white items-center gap-[8rpx]">
|
||||
<view class="flex items-baseline">
|
||||
<text class="text-[68rpx] font-700">{{ wishlistCount }}</text>
|
||||
<view class="ml-[4rpx] text-[32rpx]">
|
||||
份
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-[30rpx] text-[#b0c6ff]">
|
||||
志愿表
|
||||
<view class="text-[32rpx] ml-[4rpx]">份</view>
|
||||
</view>
|
||||
<view class="text-[30rpx] text-[#b0c6ff]">志愿表</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="mx-[74rpx] my-[48rpx] flex items-center justify-center rounded-[52rpx] from-[#FCFDFF] to-[#B8D3FF] bg-gradient-to-b py-[28rpx] shadow-[0_8px_20px_-6px_rgba(38,129,255,0.39)]"
|
||||
@click="navigateToCreateWish"
|
||||
>
|
||||
<view class="h-[40rpx] w-[40rpx]">
|
||||
<image
|
||||
class="h-[40rpx] w-[40rpx]"
|
||||
src="https://lwzk.ycymedu.com/img/home/sy_chuangjian.png" mode="scaleToFill"
|
||||
/>
|
||||
</view>
|
||||
<view class="ml-[8rpx] text-[40rpx] text-[#3D72FD] font-600">
|
||||
创建志愿表
|
||||
class="flex items-center justify-center rounded-[52rpx] py-[28rpx] mx-[74rpx] bg-gradient-to-b from-[#FCFDFF] to-[#B8D3FF] shadow-[0_8px_20px_-6px_rgba(38,129,255,0.39)] my-[48rpx]"
|
||||
@click="navigateToCreateWish">
|
||||
<view class="w-[40rpx] h-[40rpx]">
|
||||
<image class="w-[40rpx] h-[40rpx]"
|
||||
src="https://lwzk.ycymedu.com/img/home/sy_chuangjian.png" mode="scaleToFill" />
|
||||
</view>
|
||||
<view class="text-[40rpx] text-[#3D72FD] ml-[8rpx] font-600">创建志愿表</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 咨询 -->
|
||||
<view class="grid grid-cols-2 mx-[32rpx] mt-[60rpx] gap-[24rpx]">
|
||||
<view
|
||||
v-for="(item, index) in subMenus"
|
||||
:key="index" class="flex items-center justify-between rounded-[24rpx] bg-[#F3F4F8] py-[20rpx] pl-[30rpx] pr-[24rpx]" @click="navigateToSubPage(item.url)"
|
||||
>
|
||||
<view class="grid grid-cols-2 mx-[32rpx] gap-[24rpx] mt-[60rpx]">
|
||||
<view class="rounded-[24rpx] bg-[#F3F4F8] py-[20rpx] pl-[30rpx] pr-[24rpx] flex items-center justify-between"
|
||||
v-for="(item, index) in subMenus" :key="index" @click="navigateToSubPage(item.url)">
|
||||
<text class="text-[34rpx] text-[#333] font-600">{{ item.name }}</text>
|
||||
<view class="h-[108rpx] w-[108rpx]">
|
||||
<image :src="item.imgPath" mode="scaleToFill" class="h-[108rpx] w-[108rpx]" />
|
||||
<view class="w-[108rpx] h-[108rpx]">
|
||||
<image :src="item.imgPath" mode="scaleToFill" class="w-[108rpx] h-[108rpx]" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mx-[30rpx] mt-[60rpx]">
|
||||
<view class="mb-[30rpx] flex items-center">
|
||||
<view class="mr-[12rpx] h-[48rpx] w-[48rpx]">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/sy_zhibo.png" mode="scaleToFill"
|
||||
class="h-[48rpx] w-[48rpx]"
|
||||
/>
|
||||
</view>
|
||||
<text class="text-[40rpx] text-black font-600">最新直播</text>
|
||||
<view class="h-[216rpx]">
|
||||
<image src="https://lwzk.ycymedu.com/img/home/sy_banner.png" mode="scaleToFill"
|
||||
class="h-[216rpx]" />
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-x class="w-full">
|
||||
<view class="w-full flex gap-[30rpx] whitespace-nowrap" v-if="channelVideoList.length > 0">
|
||||
<view
|
||||
v-for="item in channelVideoList"
|
||||
:key="item.id"
|
||||
class="h-[430rpx] min-h-[430rpx] min-w-[440rpx] w-[440rpx] rounded-[18rpx] bg-[#F3F4F8]"
|
||||
>
|
||||
<view class="relative h-[280rpx] rounded-[18rpx]">
|
||||
<image
|
||||
:src="item.coverUrl"
|
||||
mode="scaleToFill"
|
||||
class="h-full w-full"
|
||||
/>
|
||||
<view v-if="item.type === 'live'" class="absolute bottom-0 h-[48rpx] w-full flex items-center justify-between rounded-[0_0_18rpx_18rpx] bg-black bg-opacity-50">
|
||||
<view class="ml-[20rpx] flex items-center">
|
||||
<view class="mr-[8rpx] h-[12rpx] w-[12rpx] rounded-full bg-white" />
|
||||
<view class="text-[24rpx] text-white">
|
||||
{{ item.statusText }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="item.nickname" class="mr-[20rpx] flex items-center">
|
||||
<view class="mr-[10rpx] h-[20rpx] w-[30rpx] flex items-center">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/sy_liulan.png"
|
||||
mode="widthFix"
|
||||
/>
|
||||
</view>
|
||||
<view class="text-[24rpx] text-white">
|
||||
{{ item.nickname }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="absolute bottom-0 h-[48rpx] w-full flex items-center justify-between rounded-[0_0_18rpx_18rpx] bg-black bg-opacity-50">
|
||||
<view class="ml-[20rpx] text-[24rpx] text-white">
|
||||
{{ item.startTimeText }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="ml-[20rpx] mt-[20rpx] text-[34rpx] text-[#333] font-500">
|
||||
{{ item.title }}
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="ml-[20rpx] mt-[10rpx] h-[52rpx] w-[148rpx] flex items-center justify-center rounded-[376rpx] text-[26rpx]"
|
||||
:class="item.type === 'live' ? 'text-white bg-[#3D72FD] border-solid border-[2rpx] border-[#3D72FD]' : 'bg-[#E0E6F8] text-[#3D72FD]'"
|
||||
@click="handleChannelVideoAction(item)"
|
||||
>
|
||||
{{ item.buttonText }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="w-full flex flex-col items-center justify-center" v-if="channelVideoList.length === 0">
|
||||
<view class="w-[236rpx] h-[236rpx]">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/sy_zanweikaobo.png"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
</view>
|
||||
<view @click="goToLiveHomePage()" class="mt-[20rpx] flex items-center justify-center rounded-[376rpx] text-[26rpx] text-white bg-[#3D72FD] border-solid border-[2rpx] border-[#3D72FD] px-[40rpx] py-[12rpx]"> 关注官方视频号 </view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<view class="mx-[30rpx] mt-[60rpx]">
|
||||
<view class="mb-[30rpx] flex items-center">
|
||||
<view class="mr-[12rpx] h-[48rpx] w-[48rpx]">
|
||||
<image
|
||||
src="https://lwzk.ycymedu.com/img/home/sy_zixuntun.png" mode="scaleToFill"
|
||||
class="h-[48rpx] w-[48rpx]"
|
||||
/>
|
||||
<view class="flex items-center mb-[30rpx]">
|
||||
<view class="h-[48rpx] w-[48rpx] mr-[12rpx]">
|
||||
<image src="https://lwzk.ycymedu.com/img/home/sy_zixuntun.png" mode="scaleToFill"
|
||||
class="h-[48rpx] w-[48rpx]" />
|
||||
</view>
|
||||
<text class="text-[40rpx] text-black font-600">最新资讯</text>
|
||||
<text class="text-black text-[40rpx] font-600">最新资讯</text>
|
||||
|
||||
<view class="ml-auto text-[30rpx] text-[#A6A6A6]" @click="navigateToNewsPage">
|
||||
更多
|
||||
</view>
|
||||
<view class="h-[30rpx] w-[14rpx] flex items-center">
|
||||
<image
|
||||
class="h-[30rpx] w-[14rpx]"
|
||||
src="https://lwzk.ycymedu.com/img/home/sy_zixunjiantou.png" mode="scaleToFill"
|
||||
/>
|
||||
<view class="text-[30rpx] text-[#A6A6A6] ml-auto" @click="navigateToNewsPage">更多</view>
|
||||
<view class="w-[14rpx] h-[30rpx] flex items-center">
|
||||
<image class="w-[14rpx] h-[30rpx]"
|
||||
src="https://lwzk.ycymedu.com/img/home/sy_zixunjiantou.png" mode="scaleToFill" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-for="(value, index) in notifies"
|
||||
:key="index" class="mb-[28rpx] flex flex-col border-b-1 border-[#eee] border-b-solid pb-[22rpx]" @click="navigateToNewsDetail(value.id)"
|
||||
>
|
||||
<text class="text-[32rpx] text-[#333] font-400">{{ value.title }}</text>
|
||||
<view class="mt-[20rpx] flex items-center justify-between text-[#999]">
|
||||
<view class="flex flex-col border-b-1 border-b-solid border-[#eee] pb-[22rpx] mb-[28rpx]"
|
||||
v-for="(value, index) in notifies" :key="index" @click="navigateToNewsDetail(value.id)">
|
||||
<text class="text-[#333] text-[32rpx] font-400">{{ value.title }}</text>
|
||||
<view class="flex items-center justify-between text-[#999] mt-[20rpx]">
|
||||
<view class="flex items-center">
|
||||
<view class="mr-[10rpx] h-[28rpx] w-[28rpx] flex items-center">
|
||||
<image
|
||||
src="https://lwzk.ycymedu.com/img/home/sy_shijian.png" mode="scaleToFill"
|
||||
class="h-[28rpx] w-[28rpx]"
|
||||
/>
|
||||
<view class="w-[28rpx] h-[28rpx] mr-[10rpx] flex items-center">
|
||||
<image src="https://lwzk.ycymedu.com/img/home/sy_shijian.png" mode="scaleToFill"
|
||||
class="w-[28rpx] h-[28rpx]" />
|
||||
</view>
|
||||
<text class="text-[26rpx]">{{ value.pubtime }}</text>
|
||||
</view>
|
||||
<view class="flex items-center">
|
||||
<view class="mr-[10rpx] h-[28rpx] w-[28rpx] flex items-center">
|
||||
<image
|
||||
src="https://lwzk.ycymedu.com/img/home/sy_chakan.png" mode="scaleToFill"
|
||||
class="h-[28rpx] w-[28rpx]"
|
||||
/>
|
||||
<view class="w-[28rpx] h-[28rpx] mr-[10rpx] flex items-center">
|
||||
<image src="https://lwzk.ycymedu.com/img/home/sy_chakan.png" mode="scaleToFill"
|
||||
class="w-[28rpx] h-[28rpx]" />
|
||||
</view>
|
||||
<text class="text-[26rpx]">{{ value.viewcount }}</text>
|
||||
</view>
|
||||
|
|
@ -397,11 +279,9 @@ onShow(() => {
|
|||
</view>
|
||||
</view>
|
||||
<view class="fixed bottom-[200rpx] right-[60rpx]" @click="navigateToCustom">
|
||||
<view class="h-[160rpx] w-[160rpx]">
|
||||
<image
|
||||
class="h-[160rpx] w-[160rpx]" src="https://lwzk.ycymedu.com/img/home/sy_kefu.png"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<view class="w-[160rpx] h-[160rpx]">
|
||||
<image class="w-[160rpx] h-[160rpx]" src="https://lwzk.ycymedu.com/img/home/sy_kefu.png"
|
||||
mode="scaleToFill" />
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
|
@ -410,7 +290,7 @@ onShow(() => {
|
|||
|
||||
<style scoped>
|
||||
.custom-background {
|
||||
background: linear-gradient(180deg, #c7e0ff 0%, rgba(199, 224, 255, 0) 530rpx);
|
||||
background: linear-gradient(180deg, #C7E0FF 0%, rgba(199, 224, 255, 0) 530rpx);
|
||||
background-position: 50% 50%;
|
||||
background-origin: padding-box;
|
||||
background-clip: border-box;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script lang="ts" setup>
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { safeAreaInsets,systemInfo } from '@/utils/systemInfo'
|
||||
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useUserStore } from '@/store'
|
||||
import { useTokenStore } from '@/store/token'
|
||||
import { safeAreaInsets, systemInfo } from '@/utils/systemInfo'
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
definePage({
|
||||
|
|
@ -19,7 +19,7 @@ definePage({
|
|||
style: {
|
||||
navigationStyle: 'custom',
|
||||
transparentTitle: 'always',
|
||||
navigationBarTitleText: '',
|
||||
navigationBarTitleText: ''
|
||||
},
|
||||
excludeLoginPath: true,
|
||||
})
|
||||
|
|
@ -30,107 +30,88 @@ const tokenStore = useTokenStore()
|
|||
// 使用storeToRefs解构userInfo
|
||||
const { userInfo } = storeToRefs(userStore)
|
||||
|
||||
const topMenuList = [{ name: '我的志愿表', img: 'https://lwzk.ycymedu.com/img/qt/wd_biao.png', url: '/pages-sub/me/wishlist' }, { name: '我的测评', img: 'https://lwzk.ycymedu.com/img/qt/wd_cp.png', url: '/pages-sub/me/evaluation' }]
|
||||
const bottomMenuList = [
|
||||
{ name: '收藏院校', img: 'https://lwzk.ycymedu.com/img/qt/wd_shoucang.png', url: '/pages-sub/me/starSchool' },
|
||||
{ name: '联系客服', img: 'https://lwzk.ycymedu.com/img/qt/wd_kefu.png', url: '/pages-sub/about/onlineCustom' },
|
||||
{ name: '关于我们', img: 'https://lwzk.ycymedu.com/img/qt/wd_guanyu.png', url: '/pages-sub/about/about' },
|
||||
{ name: '直播码注册', img: 'https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/wd_liebian.png', url: '/pages-sub/invite/login' },
|
||||
]
|
||||
|
||||
function navigateToUrl(url: string) {
|
||||
uni.navigateTo({ url })
|
||||
|
||||
const topMenuList = [{ name: '我的志愿表', img: 'https://lwzk.ycymedu.com/img/qt/wd_biao.png',url:'/pages-sub/me/wishlist' }, { name: "我的测评", img: 'https://lwzk.ycymedu.com/img/qt/wd_cp.png',url:'/pages-sub/me/evaluation' }]
|
||||
const bottomMenuList = [{ name: '收藏院校', img: 'https://lwzk.ycymedu.com/img/qt/wd_shoucang.png',url:"/pages-sub/me/starSchool" }, { name: '联系客服', img: 'https://lwzk.ycymedu.com/img/qt/wd_kefu.png', url:"/pages-sub/about/onlineCustom" }, { name: '关于我们', img: 'https://lwzk.ycymedu.com/img/qt/wd_guanyu.png',url:'/pages-sub/about/about' }]
|
||||
|
||||
const navigateToUrl = (url:string) => {
|
||||
uni.navigateTo({url})
|
||||
}
|
||||
|
||||
function navigateToUserInfo() {
|
||||
uni.navigateTo({ url: '/pages-sub/about/userInfo' })
|
||||
const navigateToUserInfo = () => {
|
||||
uni.navigateTo({url:"/pages-sub/about/userInfo"})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="custom-background" :style="{ height: `calc(100vh - 50px - ${safeAreaInsets.bottom}px)` }">
|
||||
<sar-navbar
|
||||
:fixed="true" fixation-style="top:unset;"
|
||||
:root-style="{ '--sar-navbar-bg': `transparent`, '--sar-navbar-height': `${systemInfo?.statusBarHeight + 44}px` }"
|
||||
>
|
||||
<view :class="`custom-background`" :style="{height:`calc(100vh - 50px - ${safeAreaInsets.bottom}px)`}">
|
||||
<sar-navbar :fixed="true" fixation-style="top:unset;"
|
||||
:root-style="{ '--sar-navbar-bg': `transparent`, '--sar-navbar-height': `${systemInfo?.statusBarHeight + 44}px` }">
|
||||
<template #title>
|
||||
<view :style="{ 'padding-top': `${systemInfo?.statusBarHeight}px` }" class="flex justify-center">
|
||||
我的
|
||||
</view>
|
||||
</template>
|
||||
</sar-navbar>
|
||||
<view class="my-[50rpx] flex items-center justify-between px-[50rpx]">
|
||||
<view class="flex items-center justify-between px-[50rpx] my-[50rpx]">
|
||||
<view class="flex">
|
||||
<view class="h-[132rpx] w-[132rpx]">
|
||||
<image
|
||||
:src="`${userInfo.avatar}`" mode="scaleToFill"
|
||||
class="h-[132rpx] w-[132rpx] rounded-full"
|
||||
/>
|
||||
<view class="w-[132rpx] h-[132rpx]">
|
||||
<image :src="`${userInfo.avatar}`" mode="scaleToFill"
|
||||
class="w-[132rpx] h-[132rpx] rounded-full" />
|
||||
</view>
|
||||
<view class="ml-[32rpx]">
|
||||
<view class="mb-[10rpx] text-[44rpx] font-500">
|
||||
{{ userInfo.nickName }}
|
||||
</view>
|
||||
<view class="text-[32rpx] text-[#666]">
|
||||
{{ userInfo.mobile }}
|
||||
</view>
|
||||
<view class="text-[44rpx] font-500 mb-[10rpx]">{{ userInfo.nickName }}</view>
|
||||
<view class="text-[#666] text-[32rpx]">{{ userInfo.mobile }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex flex-col items-center" @click="navigateToUserInfo">
|
||||
<view class="h-[48rpx] w-[48rpx]">
|
||||
<image
|
||||
src="https://lwzk.ycymedu.com/img/qt/wd_bianji.png" mode="scaleToFill"
|
||||
class="h-[48rpx] w-[48rpx]"
|
||||
/>
|
||||
</view>
|
||||
<view class="text-[30rpx] text-[#333]">
|
||||
编辑
|
||||
<view class="w-[48rpx] h-[48rpx]">
|
||||
<image src="https://lwzk.ycymedu.com/img/qt/wd_bianji.png" mode="scaleToFill"
|
||||
class="w-[48rpx] h-[48rpx]" />
|
||||
</view>
|
||||
<view class="text-[30rpx] text-[#333]">编辑</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="grid grid-cols-2 items-center justify-between gap-[28rpx] px-[30rpx]">
|
||||
<view class="grid grid-cols-2 gap-[28rpx] items-center justify-between px-[30rpx]">
|
||||
<view
|
||||
v-for="(value, index) in topMenuList"
|
||||
:key="index" class="flex items-center border-[2rpx] border-white rounded-[20rpx] border-solid bg-[#E4EEFF] px-[50rpx] py-[44rpx]" @click="navigateToUrl(value.url)"
|
||||
>
|
||||
<view class="mr-[10rpx] h-[48rpx] w-[48rpx]">
|
||||
<image :src="value.img" mode="scaleToFill" class="h-[48rpx] w-[48rpx]" />
|
||||
class="rounded-[20rpx] flex items-center px-[50rpx] py-[44rpx] bg-[#E4EEFF] border-[2rpx] border-solid border-white"
|
||||
v-for="(value, index) in topMenuList" :key="index" @click="navigateToUrl(value.url)">
|
||||
<view class="w-[48rpx] h-[48rpx] mr-[10rpx]">
|
||||
<image :src="value.img" mode="scaleToFill" class="w-[48rpx] h-[48rpx]" />
|
||||
</view>
|
||||
<view>{{ value.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mx-[30rpx] mt-[30rpx] rounded-[20rpx] bg-white px-[30rpx] pt-[30rpx]">
|
||||
<view class="text-[34rpx] font-500">
|
||||
其他功能
|
||||
</view>
|
||||
<view v-for="(value, index) in bottomMenuList" :key="index" class="flex items-center py-[34rpx] not-last:border-b-[2rpx] not-last:border-b-[#EDEDED] not-last:border-b-solid" @click="navigateToUrl(value.url)">
|
||||
<view class="h-[44rpx] w-[44rpx] flex items-center">
|
||||
<view class="px-[30rpx] pt-[30rpx] mx-[30rpx] rounded-[20rpx] bg-white mt-[30rpx]">
|
||||
<view class="text-[34rpx] font-500">其他功能</view>
|
||||
<view class="flex items-center py-[34rpx] not-last:border-b-[2rpx] not-last:border-b-solid not-last:border-b-[#EDEDED]" v-for="(value,index) in bottomMenuList" :key="index" @click="navigateToUrl(value.url)">
|
||||
<view class="w-[44rpx] h-[44rpx] flex items-center">
|
||||
<image
|
||||
:src="value.img"
|
||||
mode="scaleToFill"
|
||||
class="h-[44rpx] w-[44rpx]"
|
||||
class="w-[44rpx] h-[44rpx]"
|
||||
/>
|
||||
</view>
|
||||
<view class="ml-[16rpx] text-[32rpx]">
|
||||
{{ value.name }}
|
||||
</view>
|
||||
<view class="ml-auto h-[36rpx] w-[18rpx] flex items-center">
|
||||
<view class="text-[32rpx] ml-[16rpx]">{{ value.name }}</view>
|
||||
<view class="w-[18rpx] h-[36rpx] ml-auto flex items-center">
|
||||
<image
|
||||
src="https://lwzk.ycymedu.com/img/qt/tb_jiantou.png"
|
||||
mode="scaleToFill"
|
||||
class="h-[36rpx] w-[18rpx]"
|
||||
class="w-[18rpx] h-[36rpx]"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.custom-background {
|
||||
background: linear-gradient(180deg, #c7e0ff 0%, #f8f8f8 530rpx);
|
||||
background: linear-gradient(180deg, #C7E0FF 0%, #f8f8f8 530rpx);
|
||||
background-position: 50% 50%;
|
||||
background-origin: padding-box;
|
||||
background-clip: border-box;
|
||||
|
|
|
|||
|
|
@ -6,4 +6,3 @@ export * from './listAll';
|
|||
export * from './info';
|
||||
|
||||
export * from "./requestApi"
|
||||
export * from './invite'
|
||||
|
|
|
|||
|
|
@ -1,116 +0,0 @@
|
|||
export interface CreatePromoterParams {
|
||||
name: string
|
||||
phone: string
|
||||
referralCode?: string
|
||||
}
|
||||
|
||||
export interface Promoter {
|
||||
_id?: string
|
||||
id: string
|
||||
name: string
|
||||
phone: string
|
||||
referralCode: string
|
||||
promotionCount: number
|
||||
promotionUrl: string
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
type InviteErrorData = {
|
||||
message?: string
|
||||
msg?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
const INVITE_API_URL = 'https://liveroom.ycymedu.com/api/h5/promoters'
|
||||
const INVITE_API_KEY = '28fd3c9a8739424ff5f38'
|
||||
|
||||
export const createPromoter = (params: CreatePromoterParams) => {
|
||||
return new Promise<Promoter>((resolve, reject) => {
|
||||
uni.request({
|
||||
url: INVITE_API_URL,
|
||||
method: 'POST',
|
||||
data: params,
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-api-key': INVITE_API_KEY,
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
resolve(res.data as Promoter)
|
||||
return
|
||||
}
|
||||
|
||||
reject(new Error(getInviteErrorMessage(res.data)))
|
||||
},
|
||||
fail: () => {
|
||||
reject(new Error('提交失败,请稍后重试'))
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const getInviteErrorMessage = (data: unknown) => {
|
||||
const errorData = data as InviteErrorData | undefined
|
||||
return errorData?.message || errorData?.msg || errorData?.error || '提交失败,请稍后重试'
|
||||
}
|
||||
|
||||
const REDIRECT_API_URL = 'https://liveroom.ycymedu.com/api/h5/promotion-visits'
|
||||
|
||||
export const trackPromoterRedirect = (referralCode: string) => {
|
||||
return new Promise<unknown>((resolve, reject) => {
|
||||
uni.request({
|
||||
url: REDIRECT_API_URL,
|
||||
method: 'POST',
|
||||
data: { from: referralCode },
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-api-key': INVITE_API_KEY,
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
resolve(res.data)
|
||||
return
|
||||
}
|
||||
|
||||
reject(new Error(getInviteErrorMessage(res.data)))
|
||||
},
|
||||
fail: () => {
|
||||
reject(new Error('请求失败,请稍后重试'))
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export interface LiveLinks {
|
||||
id: string
|
||||
wechatLiveUrl: string
|
||||
douyinLiveUrl: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
const LIVE_LINKS_API_URL = 'https://liveroom.ycymedu.com/api/h5/live-links'
|
||||
|
||||
export const getLiveLinks = () => {
|
||||
return new Promise<LiveLinks>((resolve, reject) => {
|
||||
uni.request({
|
||||
url: LIVE_LINKS_API_URL,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'x-api-key': INVITE_API_KEY,
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
resolve(res.data as LiveLinks)
|
||||
return
|
||||
}
|
||||
|
||||
reject(new Error(getInviteErrorMessage(res.data)))
|
||||
},
|
||||
fail: () => {
|
||||
reject(new Error('请求失败,请稍后重试'))
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -157,20 +157,6 @@ export const getSchoolHistoricalScores = (options: { query: any }) => {
|
|||
});
|
||||
}
|
||||
|
||||
export const getBatchLine = (options: { query: any }) => {
|
||||
return request<API.Response>('/api/busBatchLine/h5List', {
|
||||
method: 'GET',
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
export const getRankTable = (options: { query: any }) => {
|
||||
return request<API.Response>('/api/busScoreSection/h5List', {
|
||||
method: 'GET',
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
export const getSchoolNature = () => {
|
||||
return request<API.Response>('/api/zhiYuan/naturelist', {
|
||||
method: 'GET',
|
||||
|
|
@ -258,12 +244,6 @@ export const getMyScore = () => {
|
|||
});
|
||||
}
|
||||
|
||||
export const getShowAiStatus = () => {
|
||||
return request<API.Response>('/api/sysDictData/detail?Status=1&Id=812248362119237 ', {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
export const saveMyScore = (options: { data: any }) => {
|
||||
return request<API.Response>('/api/busMiddleSchoolApply/add', {
|
||||
method: "POST",
|
||||
|
|
@ -319,11 +299,4 @@ export const getHistoryYearList = () => {
|
|||
return request<API.Response>('/api/busSchoolAdmission/historicalYears', {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
export const saveUserAreaScore = (options: { data: any }) => {
|
||||
return request<API.Response>('/api/busMiddleSchoolApply/add', {
|
||||
method: "POST",
|
||||
...options
|
||||
})
|
||||
}
|
||||
|
Before Width: | Height: | Size: 7.6 KiB |
|
|
@ -1,79 +0,0 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
export type AiRole = 'user' | 'assistant' | 'system'
|
||||
|
||||
export interface AiMessage {
|
||||
id: string
|
||||
role: AiRole
|
||||
content: string
|
||||
/** 是否仍在流式生成中,用于 UI 展示打字光标 */
|
||||
pending?: boolean
|
||||
/** 标记本条消息是否出错,UI 显示重试按钮 */
|
||||
error?: boolean
|
||||
/** 仅 assistant 消息使用:本轮回答结束后由大模型给出的追问建议 */
|
||||
recommendQuestions?: string[]
|
||||
createdAt: number
|
||||
}
|
||||
|
||||
export const useAiStore = defineStore(
|
||||
'ai',
|
||||
() => {
|
||||
const messages = ref<AiMessage[]>([])
|
||||
/** 一组对话共用同一个 thread,跨多轮维持上下文 */
|
||||
const threadId = ref('')
|
||||
|
||||
const messageCount = computed(() => messages.value.length)
|
||||
|
||||
function ensureThreadId() {
|
||||
if (!threadId.value) {
|
||||
threadId.value = `thread_id_${Date.now()}${Math.floor(Math.random() * 10000)}`
|
||||
}
|
||||
return threadId.value
|
||||
}
|
||||
|
||||
function addMessage(message: AiMessage) {
|
||||
messages.value.push(message)
|
||||
}
|
||||
|
||||
function updateMessage(id: string, patch: Partial<AiMessage>) {
|
||||
const target = messages.value.find(m => m.id === id)
|
||||
if (!target) {
|
||||
return
|
||||
}
|
||||
Object.assign(target, patch)
|
||||
}
|
||||
|
||||
function appendDelta(id: string, delta: string) {
|
||||
const target = messages.value.find(m => m.id === id)
|
||||
if (!target) {
|
||||
return
|
||||
}
|
||||
target.content += delta
|
||||
}
|
||||
|
||||
function removeMessage(id: string) {
|
||||
messages.value = messages.value.filter(m => m.id !== id)
|
||||
}
|
||||
|
||||
function clear() {
|
||||
messages.value = []
|
||||
threadId.value = ''
|
||||
}
|
||||
|
||||
return {
|
||||
messages,
|
||||
threadId,
|
||||
messageCount,
|
||||
ensureThreadId,
|
||||
addMessage,
|
||||
updateMessage,
|
||||
appendDelta,
|
||||
removeMessage,
|
||||
clear,
|
||||
}
|
||||
},
|
||||
{
|
||||
persist: true,
|
||||
},
|
||||
)
|
||||
|
|
@ -16,8 +16,6 @@ setActivePinia(store)
|
|||
export default store
|
||||
|
||||
// 模块统一导出
|
||||
export * from './ai'
|
||||
export * from './invite'
|
||||
export * from './token'
|
||||
export * from './user'
|
||||
export * from './wishlist'
|
||||
export * from "./wishlist"
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
import type { Promoter } from '@/service/invite'
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
export const useInviteStore = defineStore(
|
||||
'invite',
|
||||
() => {
|
||||
const promoter = ref<Promoter | null>(null)
|
||||
const currentPromoter = computed(() => promoter.value)
|
||||
|
||||
const setPromoter = (val: Promoter) => {
|
||||
promoter.value = val
|
||||
}
|
||||
|
||||
const clearPromoter = () => {
|
||||
promoter.value = null
|
||||
uni.removeStorageSync('invite')
|
||||
}
|
||||
|
||||
return {
|
||||
promoter,
|
||||
currentPromoter,
|
||||
setPromoter,
|
||||
clearPromoter,
|
||||
}
|
||||
},
|
||||
{
|
||||
persist: true,
|
||||
},
|
||||
)
|
||||
|
|
@ -61,7 +61,6 @@ export interface CustomTabBarItem {
|
|||
iconType: 'uiLib' | 'unocss' | 'iconfont' | 'image' // 不建议用 image 模式,需要配置2张图
|
||||
icon: any // 其实是 string 类型,这里是为了避免 ts 报错 (tabbar/index.vue 里面 uni-icons 那行)
|
||||
iconActive?: string // 只有在 image 模式下才需要,传递的是高亮的图片(PS: 不建议用 image 模式)
|
||||
openType?: 'switchTab' | 'navigateTo'
|
||||
badge?: CustomTabBarItemBadge
|
||||
isBulge?: boolean // 是否是中间的鼓包tabbarItem
|
||||
}
|
||||
|
|
@ -90,18 +89,6 @@ export const customTabbarList: CustomTabBarItem[] = [
|
|||
iconActive: '/static/tabbar/talented-active.png',
|
||||
// badge: 'dot',
|
||||
},
|
||||
{
|
||||
text: '',
|
||||
pagePath: 'pages-ai/ai/index',
|
||||
// 注意 unocss 图标需要如下处理:(二选一)
|
||||
// 1)在fg-tabbar.vue页面上引入一下并注释掉(见tabbar/index.vue代码第2行)
|
||||
// 2)配置到 unocss.config.ts 的 safelist 中
|
||||
iconType: 'image',
|
||||
icon: '/static/tabbar/ai.png',
|
||||
iconActive: '/static/tabbar/ai.png',
|
||||
openType: 'navigateTo',
|
||||
// badge: 'dot',
|
||||
},
|
||||
{
|
||||
text: '测评',
|
||||
pagePath: 'pages/evaluation/index',
|
||||
|
|
@ -170,11 +157,7 @@ export const customTabbarEnable
|
|||
*/
|
||||
export const needHideNativeTabbar = selectedTabbarStrategy === TABBAR_STRATEGY_MAP.CUSTOM_TABBAR_WITH_CACHE
|
||||
|
||||
const _tabbarList = customTabbarEnable
|
||||
? customTabbarList
|
||||
.filter(item => item.openType !== 'navigateTo')
|
||||
.map(item => ({ text: item.text, pagePath: item.pagePath }))
|
||||
: nativeTabbarList
|
||||
const _tabbarList = customTabbarEnable ? customTabbarList.map(item => ({ text: item.text, pagePath: item.pagePath })) : nativeTabbarList
|
||||
export const tabbarList = customTabbarEnable ? customTabbarList : nativeTabbarList
|
||||
|
||||
const _tabbar: TabBar = {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
// i-carbon-code
|
||||
import type { CustomTabBarItem } from './config'
|
||||
import { getShowAiStatus } from '@/service'
|
||||
import { customTabbarEnable, needHideNativeTabbar, tabbarCacheEnable } from './config'
|
||||
import { tabbarList, tabbarStore } from './store'
|
||||
|
||||
|
|
@ -23,23 +22,17 @@ function handleClickBulge() {
|
|||
}
|
||||
|
||||
function handleClick(index: number) {
|
||||
const item = tabbarList[index]
|
||||
|
||||
if (item.isBulge) {
|
||||
|
||||
// 点击原来的不做操作
|
||||
if (index === tabbarStore.curIdx) {
|
||||
return
|
||||
}
|
||||
if (tabbarList[index].isBulge) {
|
||||
handleClickBulge()
|
||||
return
|
||||
}
|
||||
// 点击原来的不做操作
|
||||
if (item.openType !== 'navigateTo' && index === tabbarStore.curIdx) {
|
||||
return
|
||||
}
|
||||
const url = item.pagePath
|
||||
|
||||
if (item.openType === 'navigateTo') {
|
||||
uni.navigateTo({ url })
|
||||
return
|
||||
}
|
||||
|
||||
const url = tabbarList[index].pagePath
|
||||
|
||||
tabbarStore.setCurIdx(index)
|
||||
if (tabbarCacheEnable) {
|
||||
uni.switchTab({ url })
|
||||
|
|
@ -48,26 +41,6 @@ function handleClick(index: number) {
|
|||
uni.navigateTo({ url })
|
||||
}
|
||||
}
|
||||
|
||||
const aiShowStatus = ref("0")
|
||||
|
||||
function removeNavigateToItem() {
|
||||
const index = tabbarList.findIndex(item => item.openType === 'navigateTo')
|
||||
if (index !== -1) {
|
||||
tabbarList.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
function aiShowStatusFn() {
|
||||
getShowAiStatus().then((resp) => {
|
||||
if (resp.code === 200) {
|
||||
aiShowStatus.value = resp.result.value
|
||||
if (aiShowStatus.value === "0") {
|
||||
removeNavigateToItem()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
// #ifndef MP-WEIXIN
|
||||
// 因为有了 custom:true, 微信里面不需要多余的hide操作
|
||||
onLoad(() => {
|
||||
|
|
@ -96,10 +69,6 @@ function getImageByIndex(index: number, item: CustomTabBarItem) {
|
|||
}
|
||||
return tabbarStore.curIdx === index ? item.iconActive : item.icon
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
aiShowStatusFn()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -120,7 +89,7 @@ onBeforeMount(() => {
|
|||
<image class="mt-6rpx h-200rpx w-200rpx" src="/static/tabbar/scan.png" />
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="relative flex flex-col items-center justify-center px-3">
|
||||
<view v-else class="relative px-3 flex flex-col justify-center items-center">
|
||||
<template v-if="item.iconType === 'uiLib'">
|
||||
<!-- TODO: 以下内容请根据选择的UI库自行替换 -->
|
||||
<!-- 如:<wd-icon name="home" /> (https://wot-design-uni.cn/component/icon.html) -->
|
||||
|
|
@ -132,14 +101,11 @@ onBeforeMount(() => {
|
|||
<view :class="item.icon" class="text-20px" />
|
||||
</template>
|
||||
<template v-if="item.iconType === 'image'">
|
||||
<view v-if="item.openType !== 'navigateTo'" class="h-24px w-24px">
|
||||
<view class="h-24px w-24px">
|
||||
<image :src="getImageByIndex(index, item)" mode="scaleToFill" class="h-24px w-24px" />
|
||||
</view>
|
||||
<view v-if="item.openType === 'navigateTo' && aiShowStatus" class="h-48px w-42px">
|
||||
<image :src="getImageByIndex(index, item)" mode="scaleToFill" class="h-48px w-42px" />
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="item.text" class="mt-2px text-14px">
|
||||
<view class="mt-2px text-14px">
|
||||
{{ item.text }}
|
||||
</view>
|
||||
<!-- 角标显示 -->
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ if (customTabbarEnable && BULGE_ENABLE) {
|
|||
|
||||
export function isPageTabbar(path: string) {
|
||||
const _path = path.split('?')[0]
|
||||
return tabbarList.some(item => item.openType !== 'navigateTo' && item.pagePath === _path)
|
||||
return tabbarList.some(item => item.pagePath === _path)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -56,13 +56,13 @@ const tabbarStore = reactive({
|
|||
this.setCurIdx(0)
|
||||
return
|
||||
}
|
||||
const index = tabbarList.findIndex(item => item.openType !== 'navigateTo' && item.pagePath === path)
|
||||
const index = tabbarList.findIndex(item => item.pagePath === path)
|
||||
FG_LOG_ENABLE && console.log('index:', index, path)
|
||||
// console.log('tabbarList:', tabbarList)
|
||||
if (index === -1) {
|
||||
const pagesPathList = getCurrentPages().map(item => item.route.startsWith('/') ? item.route : `/${item.route}`)
|
||||
// console.log(pagesPathList)
|
||||
const flag = tabbarList.some(item => item.openType !== 'navigateTo' && pagesPathList.includes(item.pagePath))
|
||||
const flag = tabbarList.some(item => pagesPathList.includes(item.pagePath))
|
||||
if (!flag) {
|
||||
this.setCurIdx(0)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -108,6 +108,8 @@ export function getCurrentPageI18nKey() {
|
|||
console.warn('路由不正确')
|
||||
return ''
|
||||
}
|
||||
console.log(currPage)
|
||||
console.log(currPage.style.navigationBarTitleText)
|
||||
return currPage.style?.navigationBarTitleText || ''
|
||||
}
|
||||
|
||||
|
|
@ -118,13 +120,10 @@ export function getEnvBaseUrl() {
|
|||
// 请求基准地址
|
||||
let baseUrl = import.meta.env.VITE_SERVER_BASEURL
|
||||
|
||||
// https://senior.ycymedu.com 六纬中考通
|
||||
// https://liebian.ycymedu.com 智能中专学校的
|
||||
// https://xqwgy.ycymedu.com/ 深泉外国语学院
|
||||
// # 有些同学可能需要在微信小程序里面根据 develop、trial、release 分别设置上传地址,参考代码如下。
|
||||
const VITE_SERVER_BASEURL__WEIXIN_DEVELOP = 'https://xqwgy.ycymedu.com'
|
||||
const VITE_SERVER_BASEURL__WEIXIN_TRIAL = 'https://xqwgy.ycymedu.com'
|
||||
const VITE_SERVER_BASEURL__WEIXIN_RELEASE = 'https://xqwgy.ycymedu.com'
|
||||
const VITE_SERVER_BASEURL__WEIXIN_DEVELOP = 'https://senior.ycymedu.com'
|
||||
const VITE_SERVER_BASEURL__WEIXIN_TRIAL = 'https://senior.ycymedu.com'
|
||||
const VITE_SERVER_BASEURL__WEIXIN_RELEASE = 'https://senior.ycymedu.com'
|
||||
|
||||
// 微信小程序端环境区分
|
||||
if (isMpWeixin) {
|
||||
|
|
@ -159,9 +158,9 @@ export const isDoubleTokenMode = import.meta.env.VITE_AUTH_MODE === 'double'
|
|||
*/
|
||||
export const HOME_PAGE = `/${(pages as PageMetaDatum[]).find(page => page.type === 'home')?.path || (pages as PageMetaDatum[])[0].path}`
|
||||
|
||||
export function checkEmptyValues(obj: Record<string, any>, keys: string[]): boolean {
|
||||
return keys.some((key) => {
|
||||
const value = obj[key]
|
||||
return value === '' || value === null || value === undefined
|
||||
})
|
||||
}
|
||||
export const checkEmptyValues=(obj: Record<string, any>, keys: string[]): boolean=> {
|
||||
return keys.some(key => {
|
||||
const value = obj[key];
|
||||
return value === '' || value === null || value === undefined;
|
||||
});
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable import/no-mutable-exports */
|
||||
// 获取屏幕边界到安全区域距离
|
||||
let systemInfo: any
|
||||
let safeAreaInsets: any
|
||||
let systemInfo
|
||||
let safeAreaInsets
|
||||
let headerBarHeight = 0
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
|
|
|
|||
|
|
@ -1,231 +0,0 @@
|
|||
// components/agent-ui-new/chatFIle/chatFile.js
|
||||
import { getCloudInstance, compareVersions, commonRequest } from "../tools";
|
||||
Component({
|
||||
lifetimes: {
|
||||
attached: async function () {
|
||||
console.log("enableDel", this.data.enableDel);
|
||||
const { tempFileName, rawFileName, rawType, tempPath, fileId, botId, status } = this.data.fileData;
|
||||
const type = this.getFileType(rawFileName || tempFileName);
|
||||
console.log("type", type);
|
||||
if (!fileId) {
|
||||
this.setData({
|
||||
iconPath: "../imgs/" + type + ".svg",
|
||||
});
|
||||
|
||||
this.triggerEvent("changeChild", { tempId: this.data.fileData.tempId, status: "uploading" });
|
||||
}
|
||||
|
||||
if (fileId && status === "parsed") {
|
||||
this.setData({
|
||||
iconPath: "../imgs/" + type + ".svg",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const cloudInstance = await getCloudInstance();
|
||||
// console.log('file', cloudInstance)
|
||||
// 上传云存储获取 fileId
|
||||
// console.log('rawFileName tempFileName tempPath', rawFileName, tempFileName, tempPath)
|
||||
cloudInstance.uploadFile({
|
||||
cloudPath: this.generateCosUploadPath(
|
||||
botId,
|
||||
rawFileName ? rawFileName.split(".")[0] + "-" + tempFileName : tempFileName
|
||||
), // 云上文件路径
|
||||
filePath: tempPath,
|
||||
success: async (res) => {
|
||||
const appBaseInfo = wx.getAppBaseInfo();
|
||||
const fileId = res.fileID;
|
||||
console.log("当前版本", appBaseInfo.SDKVersion);
|
||||
if (botId.startsWith("ibot")) {
|
||||
this.triggerEvent("changeChild", { tempId: this.data.fileData.tempId, fileId, status: "parsed" });
|
||||
} else {
|
||||
this.triggerEvent("changeChild", { tempId: this.data.fileData.tempId, status: "parsing" });
|
||||
commonRequest({
|
||||
path: `bots/${botId}/files`,
|
||||
data: {
|
||||
fileList: [
|
||||
{
|
||||
fileName: rawFileName || tempFileName,
|
||||
fileId,
|
||||
type: rawType,
|
||||
},
|
||||
],
|
||||
}, // any
|
||||
method: "POST",
|
||||
timeout: 60000,
|
||||
success: (res) => {
|
||||
console.log("resolve agent file res", res);
|
||||
this.triggerEvent("changeChild", { tempId: this.data.fileData.tempId, fileId, status: "parsed" });
|
||||
},
|
||||
fail: (e) => {
|
||||
console.log("e", e);
|
||||
this.triggerEvent("changeChild", { tempId: this.data.fileData.tempId, fileId, status: "parseFailed" });
|
||||
},
|
||||
complete: () => {},
|
||||
header: {},
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error("上传失败:", err);
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
observers: {
|
||||
"fileData.status": function (status) {
|
||||
this.setData({
|
||||
statusTxt: this.getFormatStatusText(status),
|
||||
});
|
||||
},
|
||||
},
|
||||
/**
|
||||
* 组件的属性列表
|
||||
*/
|
||||
properties: {
|
||||
enableDel: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
fileData: {
|
||||
type: Object,
|
||||
value: {
|
||||
tempId: "",
|
||||
rawType: "",
|
||||
tempFileName: "",
|
||||
rawFileName: "",
|
||||
tempPath: "",
|
||||
fileSize: 0,
|
||||
fileUrl: "",
|
||||
fileId: "",
|
||||
status: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的初始数据
|
||||
*/
|
||||
data: {
|
||||
formatSize: "",
|
||||
iconPath: "../imgs/file.svg",
|
||||
statusTextMap: {
|
||||
uploading: "上传中",
|
||||
parsing: "解析中",
|
||||
parseFailed: "解析失败",
|
||||
},
|
||||
statusTxt: "",
|
||||
},
|
||||
/**
|
||||
* 组件的方法列表,
|
||||
*/
|
||||
methods: {
|
||||
getFormatStatusText: function (status) {
|
||||
if (status === "parsed") {
|
||||
return this.transformSize(this.data.fileData.fileSize);
|
||||
}
|
||||
return this.data.statusTextMap[status] || "";
|
||||
},
|
||||
generateCosUploadPath: function (botId, fileName) {
|
||||
return `agent_file/${botId}/${fileName}`;
|
||||
},
|
||||
// 提取文件后缀
|
||||
getFileType: function (fileName) {
|
||||
let index = fileName.lastIndexOf(".");
|
||||
const fileExt = fileName.substring(index + 1);
|
||||
if (fileExt === "docx" || fileExt === "doc") {
|
||||
return "word";
|
||||
}
|
||||
if (fileExt === "xlsx" || fileExt === "xls" || fileExt === "csv") {
|
||||
return "excel";
|
||||
}
|
||||
if (fileExt === "png" || fileExt === "jpg" || fileExt === "jpeg" || fileExt === "svg") {
|
||||
return "image";
|
||||
}
|
||||
|
||||
if (fileExt === "ppt" || fileExt === "pptx") {
|
||||
return "ppt";
|
||||
}
|
||||
|
||||
if (fileExt === "pdf") {
|
||||
return "pdf";
|
||||
}
|
||||
return "file";
|
||||
},
|
||||
// 转换文件大小(原始单位为B)
|
||||
transformSize: function (size) {
|
||||
if (size < 1024) {
|
||||
return size + "B";
|
||||
} else if (size < 1024 * 1024) {
|
||||
return (size / 1024).toFixed(2) + "KB";
|
||||
} else {
|
||||
return (size / 1024 / 1024).toFixed(2) + "MB";
|
||||
}
|
||||
},
|
||||
removeFileFromParents: function () {
|
||||
console.log("remove", this.data.fileData);
|
||||
this.triggerEvent("removeChild", { tempId: this.data.fileData.tempId });
|
||||
},
|
||||
openFileByWx: function (tempPath) {
|
||||
const fileExt = tempPath.split(".")[1];
|
||||
if (["doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf"].includes(fileExt)) {
|
||||
wx.openDocument({
|
||||
filePath: tempPath,
|
||||
success: function (res) {
|
||||
console.log("打开文档成功");
|
||||
},
|
||||
fail: function (err) {
|
||||
console.log("打开文档失败", err);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
wx.showModal({
|
||||
content: "当前支持预览文件类型为 pdf、doc、docx、ppt、pptx、xls、xlsx",
|
||||
showCancel: false,
|
||||
confirmText: "确定",
|
||||
});
|
||||
}
|
||||
},
|
||||
previewImageByWx: function (fileId) {
|
||||
wx.previewImage({
|
||||
urls: [fileId],
|
||||
showmenu: true,
|
||||
success: function (res) {
|
||||
console.log("previewImage res", res);
|
||||
},
|
||||
fail: function (e) {
|
||||
console.log("previewImage e", e);
|
||||
},
|
||||
});
|
||||
},
|
||||
openFile: async function () {
|
||||
if (this.data.fileData.tempPath) {
|
||||
// 本地上传的文件
|
||||
if (this.data.fileData.rawType === "file") {
|
||||
this.openFileByWx(this.data.fileData.tempPath);
|
||||
} else {
|
||||
console.log("fileId", this.data.fileData.fileId);
|
||||
if (this.data.fileData.fileId) {
|
||||
this.previewImageByWx(this.data.fileData.fileId);
|
||||
}
|
||||
}
|
||||
} else if (this.data.fileData.fileId) {
|
||||
// 针对历史记录中带cloudID的处理(历史记录中附带的文件)
|
||||
const cloudInsatnce = await getCloudInstance();
|
||||
cloudInsatnce.downloadFile({
|
||||
fileID: this.data.fileData.fileId,
|
||||
success: (res) => {
|
||||
console.log("download res", res);
|
||||
if (this.data.fileData.rawType === "file") {
|
||||
this.openFileByWx(res.tempFilePath);
|
||||
} else {
|
||||
this.previewImageByWx(this.data.fileData.fileId);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log("download err", err);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
<!--components/agent-ui-new/chatFIle/chatFile.wxml-->
|
||||
<!-- <text>components/agent-ui-new/chatFIle/chatFile.wxml</text> -->
|
||||
<view class="chat_file" bind:tap="openFile">
|
||||
<view class="chat_file__content">
|
||||
<image class="chat_file__icon" src="{{iconPath}}" />
|
||||
<view class="chat_file__info">
|
||||
<view class="chat_file__name">{{fileData.rawFileName || fileData.tempFileName}}</view>
|
||||
<view class="chat_file__size">{{statusTxt}}
|
||||
<image wx:if="{{fileData.status === 'uploading' || fileData.status === 'parsing'}}" style="width: 15px;height:15px;margin-left: 5px" src="../imgs/loading.svg" mode=""/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<image wx:if="{{enableDel}}" bind:tap="removeFileFromParents" style="width: 15px;height: 15px;position: absolute;top: -7px;right: -7px" src="../imgs/close-filled.png" mode="aspectFill"/>
|
||||
</view>
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
/* components/agent-ui-new/chatFIle/chatFile.wxss */
|
||||
.chat_file {
|
||||
padding: 16rpx 24rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
/* box-shadow: 0 1px 8px rgba(0, 0, 0, 0.253); */
|
||||
/* margin: 0rpx 5rpx; */
|
||||
/* max-width: 110px; */
|
||||
width: 110px;
|
||||
position: relative;
|
||||
background-color: #f3f4f6;
|
||||
}
|
||||
|
||||
.chat_file:active {
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
.chat_file__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.chat_file__icon {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.chat_file__info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.chat_file__name {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
margin-bottom: 8rpx;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.chat_file__size {
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
// components/agent-ui/collapsibleCard/index.js
|
||||
Component({
|
||||
|
||||
/**
|
||||
* 组件的属性列表
|
||||
*/
|
||||
properties: {
|
||||
initStatus: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
showBgColor:{
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
showExpandIcon: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的初始数据
|
||||
*/
|
||||
data: {
|
||||
collapsedStatus: false
|
||||
},
|
||||
lifetimes: {
|
||||
attached() {
|
||||
this.setData({ collapsedStatus: this.properties.initStatus })
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 组件的方法列表
|
||||
*/
|
||||
methods: {
|
||||
changeCollapsedStatus: function () {
|
||||
this.setData({ collapsedStatus: !this.data.collapsedStatus })
|
||||
}
|
||||
},
|
||||
options: {
|
||||
multipleSlots: true
|
||||
}
|
||||
})
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
<!--components/agent-ui/collapsibleCard/index.wxml-->
|
||||
<view class="collapse" style="{{collapsedStatus&&showBgColor?'background-color: #f5f5f5;':''}}">
|
||||
<view class="collapse-header" bind:tap="changeCollapsedStatus">
|
||||
<image wx:if="{{showExpandIcon}}" src="../imgs/arrow.svg" mode="aspectFill" style="width: 16px;height: 16px;transform: rotate({{collapsedStatus?360:270}}deg);" />
|
||||
<slot name="title"></slot>
|
||||
</view>
|
||||
<block wx:if="{{collapsedStatus}}">
|
||||
<slot name="content"></slot>
|
||||
</block>
|
||||
</view>
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
/* components/agent-ui/collapsibleCard/index.wxss */
|
||||
.collapse{
|
||||
border-radius: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.collapse-header {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background-color: #f5f5f5;
|
||||
justify-content: space-between;
|
||||
padding: 18rpx 26rpx;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
Component({
|
||||
properties: {
|
||||
name: {
|
||||
type: String,
|
||||
value: "",
|
||||
},
|
||||
toolParams: {
|
||||
type: Object,
|
||||
value: {},
|
||||
},
|
||||
toolData: {
|
||||
type: Object,
|
||||
value: {},
|
||||
},
|
||||
},
|
||||
data: {},
|
||||
lifetimes: {},
|
||||
});
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
<!--components/agent-ui-new/chatFIle/chatFile.wxml-->
|
||||
<!-- <text>components/agent-ui-new/chatFIle/chatFile.wxml</text> -->
|
||||
<!-- <block>
|
||||
<view wx:if="{{name === 'maps_geo' || name === 'maps_direction_driving'}}">
|
||||
<custom-map name="{{name}}" toolData="{{toolData}}"></custom-map>
|
||||
</view>
|
||||
<view wx:if="{{name === 'maps_weather'}}">
|
||||
<custom-weather name="{{name}}" toolData="{{toolData}}"></custom-weather>
|
||||
</view>
|
||||
<view wx:if="{{name === 'map_search_places'}}">
|
||||
<custom-business-list name="{{name}}" toolData="{{toolData}}"></custom-business-list>
|
||||
<custom-food-list name="{{name}}" toolData="{{toolData}}"></custom-food-list>
|
||||
</view>
|
||||
</block> -->
|
||||
|
||||
<block>
|
||||
<view class="customCard">
|
||||
<custom-map wx:if="{{name === 'geocoder' || name === 'placeSearchNearby' || 'directionDriving'}}" name="{{name}}" toolParams="{{toolParams}}" toolData="{{toolData}}"></custom-map>
|
||||
</view>
|
||||
<view class="customCard">
|
||||
<custom-weather wx:if="{{name === 'weather'}}" name="{{name}}" toolData="{{toolData}}"></custom-weather>
|
||||
</view>
|
||||
<view class="customCard" wx:if="{{name === 'placeSearchNearby'}}">
|
||||
<custom-business-list name="{{name}}" toolData="{{toolData}}"></custom-business-list>
|
||||
</view>
|
||||
<!-- 用户可类似添加自定义组件 -->
|
||||
</block>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
.customCard {
|
||||
margin: 15px 0px;
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12.0003 0.630371L14.9029 8.98093L23.7417 9.16105L16.6969 14.5021L19.2569 22.964L12.0003 17.9144L4.74363 22.964L7.30367 14.5021L0.258789 9.16105L9.09761 8.98093L12.0003 0.630371ZM12.0003 6.72181L10.5298 10.9522L6.05209 11.0434L9.62099 13.7492L8.32409 18.0359L12.0003 15.4778L15.6764 18.0359L14.3795 13.7492L17.9484 11.0434L13.4707 10.9522L12.0003 6.72181Z" fill="#f2db4a" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 473 B |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12.0003 0.630371L14.9029 8.98093L23.7417 9.16105L16.6969 14.5021L19.2569 22.964L12.0003 17.9144L4.74363 22.964L7.30367 14.5021L0.258789 9.16105L9.09761 8.98093L12.0003 0.630371ZM12.0003 6.72181L10.5298 10.9522L6.05209 11.0434L9.62099 13.7492L8.32409 18.0359L12.0003 15.4778L15.6764 18.0359L14.3795 13.7492L17.9484 11.0434L13.4707 10.9522L12.0003 6.72181Z" fill="black" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 471 B |
|
|
@ -1,277 +0,0 @@
|
|||
// pages/components/feedback/index.js
|
||||
Component({
|
||||
|
||||
/**
|
||||
* 组件的属性列表
|
||||
*/
|
||||
properties: {
|
||||
isShowFeedback: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
feedbackRecordId: {
|
||||
type: String,
|
||||
value: ''
|
||||
},
|
||||
feedbackType: {
|
||||
type: String,
|
||||
value: ''
|
||||
},
|
||||
botId: {
|
||||
type: String,
|
||||
value: ''
|
||||
},
|
||||
input: {
|
||||
type: String,
|
||||
value: ""
|
||||
},
|
||||
aiAnswer: {
|
||||
type: String,
|
||||
value: ''
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的初始数据
|
||||
*/
|
||||
data: {
|
||||
upVote: [
|
||||
{
|
||||
"selected": false,
|
||||
"value": "准确有效"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "回答全面"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "立场正确"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "格式规范"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "专业性强"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "富有创意"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "表达清晰"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "值得信赖"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "高效"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "满意"
|
||||
}
|
||||
],
|
||||
downVote: [
|
||||
{
|
||||
"selected": false,
|
||||
"value": "理解错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "未识别问题"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "事实错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "推理错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "内容不完整"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "不专业"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "违法有害"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "格式错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "乱码"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "内容重复"
|
||||
}
|
||||
],
|
||||
score: 5,
|
||||
message: ""
|
||||
},
|
||||
observers:{
|
||||
"feedbackType":function (value) {
|
||||
this.setData({score:value==='upvote'?5:1})
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 组件的方法列表
|
||||
*/
|
||||
methods: {
|
||||
reset: function () {
|
||||
this.setData({
|
||||
upVote: [
|
||||
{
|
||||
"selected": false,
|
||||
"value": "准确有效"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "回答全面"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "立场正确"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "格式规范"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "专业性强"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "富有创意"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "表达清晰"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "值得信赖"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "高效"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "满意"
|
||||
}
|
||||
],
|
||||
downVote: [
|
||||
{
|
||||
"selected": false,
|
||||
"value": "理解错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "未识别问题"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "事实错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "推理错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "内容不完整"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "不专业"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "违法有害"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "格式错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "乱码"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "内容重复"
|
||||
}
|
||||
],
|
||||
score: 5,
|
||||
message: ""
|
||||
})
|
||||
},
|
||||
onChangeScore: function (e) {
|
||||
const { score } = e.currentTarget.dataset
|
||||
this.setData({ score })
|
||||
},
|
||||
onSelect: function (e) {
|
||||
const { item } = e.currentTarget.dataset
|
||||
const newArr = [...this.data.feedbackType === 'upvote' ? this.data.upVote : this.data.downVote]
|
||||
const [selectedItem] = newArr.filter(i => i.value === item.value)
|
||||
selectedItem.selected = !selectedItem.selected
|
||||
if (this.data.feedbackType === 'upvote') {
|
||||
this.setData({ upVote: newArr })
|
||||
} else {
|
||||
this.setData({ downVote: newArr })
|
||||
}
|
||||
|
||||
},
|
||||
inputChange: function (e) {
|
||||
const value = e.detail.value
|
||||
this.setData({ message: value })
|
||||
},
|
||||
closeShowFeedback: function () {
|
||||
this.triggerEvent('close')
|
||||
},
|
||||
submitFeedback: async function () {
|
||||
const res = await wx.cloud.extend.AI.bot.sendFeedback({
|
||||
userFeedback: {
|
||||
botId: this.data.botId,
|
||||
recordId: this.data.feedbackRecordId,
|
||||
comment: this.data.message,
|
||||
rating: this.data.score,
|
||||
tags: this.data.feedbackType === 'upvote' ? this.data.upVote.filter(item => item.selected).map(item => item.value) : this.data.downVote.filter(item => item.selected).map(item => item.value),
|
||||
aiAnswer: this.data.aiAnswer,
|
||||
input: this.data.input,
|
||||
type: this.data.feedbackType === 'upvote' ? "upvote" : 'downvote',
|
||||
},
|
||||
botId: this.data.botId
|
||||
});
|
||||
if (res.status === 'success') {
|
||||
wx.showToast({
|
||||
title: "感谢反馈",
|
||||
icon: "success",
|
||||
});
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: "反馈失败",
|
||||
icon: "fail",
|
||||
});
|
||||
}
|
||||
this.reset();
|
||||
// console.log(res)
|
||||
this.triggerEvent("close")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
<view class="feedback-modal" wx:if="{{isShowFeedback}}">
|
||||
<view class="feedback">
|
||||
<view class="feedback-header">
|
||||
感谢您的宝贵反馈,我们会不断改进服务
|
||||
</view>
|
||||
<view class="feedback-body">
|
||||
<view class="item-box">
|
||||
<view class="item-title">评分</view>
|
||||
<view style="display: flex; gap: 14rpx;">
|
||||
<block wx:for="{{[1,2,3,4,5]}}" wx:key="*this">
|
||||
<image src="{{item<=score?'./imgs/star-highlight.svg':'./imgs/star.svg'}}" mode="aspectFill" class="star" bind:touchend="onChangeScore" data-score="{{item}}" />
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-box">
|
||||
<view class="item-title">回答内容</view>
|
||||
<view>
|
||||
<block wx:for="{{feedbackType==='upvote'?upVote:downVote}}" wx:key="value">
|
||||
<view class="{{item.selected?'vote-item-highlight':'vote-item-normal'}}" bind:tap="onSelect" data-item="{{item}}">{{item.value}}</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-box">
|
||||
<view class="item-title">反馈建议</view>
|
||||
<view>
|
||||
<textarea value="{{message}}" class="feedback-textarea" maxlength="140" bindinput="inputChange"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="feedback-footer">
|
||||
<view class="btn-cancel" bind:tap="closeShowFeedback">取消</view>
|
||||
<view class="btn-submit" bind:tap="submitFeedback">提交反馈</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
/* pages/components/feedback/index.wxss */
|
||||
.feedback-modal {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 750rpx;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.feedback {
|
||||
width: 520rpx;
|
||||
max-height: 70%;
|
||||
overflow-y: auto;
|
||||
background-color: #fff;
|
||||
border-radius: 24rpx;
|
||||
padding: 40rpx;
|
||||
}
|
||||
.feedback-header{
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
text-align: justify;
|
||||
}
|
||||
.feedback-body{
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.item-box{
|
||||
padding: 28rpx 0px;
|
||||
}
|
||||
.item-title{
|
||||
font-size: 28rpx;
|
||||
padding-bottom: 28rpx;
|
||||
}
|
||||
.star{
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
.vote-item-normal{
|
||||
display: inline-block;
|
||||
background-color: rgba(243, 243, 243, 1);
|
||||
height: 48rpx;
|
||||
line-height: 48rpx;
|
||||
border-radius: 24rpx;
|
||||
padding: 4rpx 24rpx;
|
||||
margin-right: 16rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
.vote-item-highlight{
|
||||
display: inline-block;
|
||||
background-color: rgba(0, 82, 217, 0.1);
|
||||
height: 48rpx;
|
||||
line-height: 48rpx;
|
||||
border-radius: 24rpx;
|
||||
padding: 4rpx 24rpx;
|
||||
margin-right: 16rpx;
|
||||
margin-bottom: 16rpx;
|
||||
color: rgb(0, 82, 217);
|
||||
}
|
||||
.feedback-textarea{
|
||||
width: 100%;
|
||||
height: 150rpx;
|
||||
border-radius: 16rpx;
|
||||
border: 1px solid #ccc;
|
||||
box-sizing: border-box;
|
||||
padding: 16rpx;
|
||||
}
|
||||
.feedback-footer{
|
||||
font-size: 28rpx;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 24rpx;
|
||||
}
|
||||
.btn-cancel{
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
border: 1px solid #eee;
|
||||
padding: 6rpx 24rpx;
|
||||
border-radius: 6rpx;
|
||||
line-height: 48rpx;
|
||||
}
|
||||
.btn-submit{
|
||||
box-sizing: border-box;
|
||||
padding: 6rpx 24rpx;
|
||||
border-radius: 6rpx;
|
||||
color: #fff;
|
||||
background-color: #0052d9;
|
||||
line-height: 48rpx;
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M17.5001 8.08575L12.0002 13.5858L6.50015 8.08576L5.08594 9.49997L12.0002 16.4142L18.9144 9.49997L17.5001 8.08575Z" fill="black" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 244 B |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.88197 1.99988H16.118L17.618 4.99988H23V20.9999H1V4.99988H6.38197L7.88197 1.99988ZM9.11803 3.99988L7.61803 6.99988H3V18.9999H21V6.99988H16.382L14.882 3.99988H9.11803ZM12 9.49988C10.3431 9.49988 9 10.843 9 12.4999C9 14.1567 10.3431 15.4999 12 15.4999C13.6569 15.4999 15 14.1567 15 12.4999C15 10.843 13.6569 9.49988 12 9.49988ZM7 12.4999C7 9.73845 9.23858 7.49988 12 7.49988C14.7614 7.49988 17 9.73845 17 12.4999C17 15.2613 14.7614 17.4999 12 17.4999C9.23858 17.4999 7 15.2613 7 12.4999Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 630 B |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><rect width="2.8" height="12" x="1" y="6" fill="#e84f50"><animate attributeName="y" begin="svgSpinnersBarsScaleMiddle0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScaleMiddle0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect><rect width="2.8" height="12" x="5.8" y="6" fill="#e84f50"><animate attributeName="y" begin="svgSpinnersBarsScaleMiddle0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScaleMiddle0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect><rect width="2.8" height="12" x="10.6" y="6" fill="#e84f50"><animate id="svgSpinnersBarsScaleMiddle0" attributeName="y" begin="0;svgSpinnersBarsScaleMiddle1.end-0.1s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="0;svgSpinnersBarsScaleMiddle1.end-0.1s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect><rect width="2.8" height="12" x="15.4" y="6" fill="#e84f50"><animate attributeName="y" begin="svgSpinnersBarsScaleMiddle0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScaleMiddle0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect><rect width="2.8" height="12" x="20.2" y="6" fill="#e84f50"><animate id="svgSpinnersBarsScaleMiddle1" attributeName="y" begin="svgSpinnersBarsScaleMiddle0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScaleMiddle0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect></svg>
|
||||
|
Before Width: | Height: | Size: 2.1 KiB |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3C7.02944 3 3 7.02944 3 12C3 14.3966 3.93542 16.5725 5.46305 18.1862L5.96701 18.7185L4.69951 21H12C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3ZM1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23H1.30049L3.51936 19.006C1.94632 17.1038 1 14.6615 1 12ZM13 8V11H16V13H13V16H11V13H8V11H11V8H13Z" fill="#4d6bfe" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 470 B |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3C7.02944 3 3 7.02944 3 12C3 14.3966 3.93542 16.5725 5.46305 18.1862L5.96701 18.7185L4.69951 21H12C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3ZM1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23H1.30049L3.51936 19.006C1.94632 17.1038 1 14.6615 1 12ZM13 8V11H16V13H13V16H11V13H8V11H11V8H13Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 480 B |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3C7.02944 3 3 7.02944 3 12C3 14.3966 3.93542 16.5725 5.46305 18.1862L5.96701 18.7185L4.69951 21H12C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3ZM1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23H1.30049L3.51936 19.006C1.94632 17.1038 1 14.6615 1 12ZM13 5.5V11.5858L16.4142 15L15 16.4142L11 12.4142V5.5H13Z" fill="rgb(160, 160, 160)" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 497 B |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M20.985 7.37845L10.3784 17.985L4.0144 11.6211L5.42862 10.2069L10.3784 15.1566L19.5708 5.96423L20.985 7.37845Z" fill="green" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 237 B |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9 1L15 1L15 9.5L21 9.5L21 23L3 23L3 9.5L9 9.5L9 1ZM11 3L11 11.5L5 11.5V14L19 14L19 11.5H13L13 3L11 3ZM19 16L5 16L5 21H14V18L16 18V21H19V16Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 283 B |
|
Before Width: | Height: | Size: 400 B |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.0502 5.63611L11.9999 10.5859L16.9497 5.63611L18.3639 7.05032L13.4142 12.0001L18.3639 16.9498L16.9497 18.364L11.9999 13.4143L7.0502 18.364L5.63599 16.9498L10.5857 12.0001L5.63599 7.05032L7.0502 5.63611Z" fill="red" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 333 B |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.0502 5.63611L11.9999 10.5859L16.9497 5.63611L18.3639 7.05032L13.4142 12.0001L18.3639 16.9498L16.9497 18.364L11.9999 13.4143L7.0502 18.364L5.63599 16.9498L10.5857 12.0001L5.63599 7.05032L7.0502 5.63611Z" fill="black" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 335 B |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 2H15V7.5H13V4H4V13H7.5V15H2V2ZM9 9H22V22H9V9ZM11 11V20H20V11H11Z" fill="#8b8b8b" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 197 B |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16.4278 1.96289L22.0381 7.57319L7.61066 22.0007L2.00037 22.0007L2.00037 16.3904L16.4278 1.96289ZM16.4278 4.79132L13.646 7.57319L16.4278 10.3551L19.2097 7.57319L16.4278 4.79132ZM15.0136 11.7693L12.2318 8.9874L4.00037 17.2188L4.00037 20.0007H6.78224L15.0136 11.7693ZM22.2252 22.0007H12.6821V20.0007L22.2252 20.0007V22.0007Z" fill="black" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 453 B |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12.0001 3C7.02956 3 3.00012 7.02944 3.00012 12C3.00012 16.9706 7.02956 21 12.0001 21C16.9707 21 21.0001 16.9706 21.0001 12C21.0001 7.02944 16.9707 3 12.0001 3ZM1.00012 12C1.00012 5.92487 5.92499 1 12.0001 1C18.0753 1 23.0001 5.92487 23.0001 12C23.0001 18.0751 18.0753 23 12.0001 23C5.92499 23 1.00012 18.0751 1.00012 12ZM13.0001 6.5V14H11.0001V6.5H13.0001ZM11.0001 15.5H13.004V17.5039H11.0001V15.5Z" fill="#8b8b8b" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 532 B |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 32 32"><path fill="#20744a" fill-rule="evenodd" d="M28.781 4.405h-10.13V2.018L2 4.588v22.527l16.651 2.868v-3.538h10.13A1.16 1.16 0 0 0 30 25.349V5.5a1.16 1.16 0 0 0-1.219-1.095m.16 21.126H18.617l-.017-1.889h2.487v-2.2h-2.506l-.012-1.3h2.518v-2.2H18.55l-.012-1.3h2.549v-2.2H18.53v-1.3h2.557v-2.2H18.53v-1.3h2.557v-2.2H18.53v-2h10.411Z"/><path fill="#20744a" d="M22.487 7.439h4.323v2.2h-4.323zm0 3.501h4.323v2.2h-4.323zm0 3.501h4.323v2.2h-4.323zm0 3.501h4.323v2.2h-4.323zm0 3.501h4.323v2.2h-4.323z"/><path fill="#fff" fill-rule="evenodd" d="m6.347 10.673l2.146-.123l1.349 3.709l1.594-3.862l2.146-.123l-2.606 5.266l2.606 5.279l-2.269-.153l-1.532-4.024l-1.533 3.871l-2.085-.184l2.422-4.663z"/></svg>
|
||||
|
Before Width: | Height: | Size: 773 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="20px" height="20px" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 4C4 2.89543 4.89543 2 6 2H10.5858C11.1162 2 11.6249 2.21071 12 2.58579L15.4142 6C15.7893 6.37507 16 6.88378 16 7.41421V16C16 17.1046 15.1046 18 14 18H6C4.89543 18 4 17.1046 4 16V4ZM6 10C6 9.44772 6.44772 9 7 9H13C13.5523 9 14 9.44772 14 10C14 10.5523 13.5523 11 13 11H7C6.44772 11 6 10.5523 6 10ZM7 13C6.44772 13 6 13.4477 6 14C6 14.5523 6.44772 15 7 15H13C13.5523 15 14 14.5523 14 14C14 13.4477 13.5523 13 13 13H7Z" fill="#3895FB"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 598 B |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 16 16"><g fill="none"><path fill="url(#fluentColorImage162)" d="M2 4.5A2.5 2.5 0 0 1 4.5 2h7A2.5 2.5 0 0 1 14 4.5v7a2.5 2.5 0 0 1-2.5 2.5h-7A2.5 2.5 0 0 1 2 11.5z"/><path fill="url(#fluentColorImage160)" d="M13.586 12.879A2.5 2.5 0 0 1 11.5 14h-7a2.5 2.5 0 0 1-2.086-1.121l4.384-4.384a1.7 1.7 0 0 1 2.404 0z"/><path fill="url(#fluentColorImage161)" d="M11.5 5.502a1.002 1.002 0 1 1-2.004 0a1.002 1.002 0 0 1 2.004 0"/><defs><linearGradient id="fluentColorImage160" x1="6.286" x2="7.572" y1="7.997" y2="14.347" gradientUnits="userSpaceOnUse"><stop stop-color="#b3e0ff"/><stop offset="1" stop-color="#8cd0ff"/></linearGradient><linearGradient id="fluentColorImage161" x1="10.097" x2="10.829" y1="4.277" y2="6.913" gradientUnits="userSpaceOnUse"><stop stop-color="#fdfdfd"/><stop offset="1" stop-color="#b3e0ff"/></linearGradient><radialGradient id="fluentColorImage162" cx="0" cy="0" r="1" gradientTransform="matrix(20.57146 26.03575 -23.68122 18.71109 -2.714 -4.75)" gradientUnits="userSpaceOnUse"><stop offset=".338" stop-color="#0fafff"/><stop offset=".529" stop-color="#367af2"/></radialGradient></defs></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2.00003 4V6H22V4H2.00003Z" fill="black" /><path d="M8.00003 11V13H22V11H8.00003Z" fill="black" /><path d="M2.00003 18H22V20H2.00003V18Z" fill="black" /><path d="M1.58582 11.9998L4.7678 15.1818L6.18201 13.7676L4.41424 11.9998L6.18201 10.232L4.7678 8.81783L1.58582 11.9998Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 415 B |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2.99997 4H1.99997V6H2.99997H21H22V4H21H2.99997ZM8.99997 11H7.99997V13H8.99997H21H22V11H21H8.99997ZM1.99997 18H2.99997H21H22V20H21H2.99997H1.99997V18ZM5.80474 12.7073L6.51184 12.0002L5.80474 11.2931L4.03697 9.52532L3.32986 8.81821L1.91565 10.2324L2.62276 10.9395L3.68342 12.0002L2.62276 13.0608L1.91565 13.768L3.32986 15.1822L4.03697 14.4751L5.80474 12.7073Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 501 B |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3.05493 11C3.45261 7.40254 5.97062 4.44413 9.33156 3.40217C8.00851 5.65483 7.1892 8.23957 7.02895 11H3.05493ZM10.9922 1.04555C5.38944 1.55442 1 6.26461 1 12C1 17.7354 5.3894 22.4455 10.9922 22.9545L11 22.9643L11.4254 22.9853C11.4932 22.9887 11.5611 22.9916 11.6292 22.9939C11.7523 22.9979 11.8759 23 12 23C12.1187 23 12.2369 22.9981 12.3546 22.9944C12.4281 22.9921 12.5015 22.989 12.5746 22.9853L13 22.9643L13.0078 22.9545C18.6106 22.4455 23 17.7354 23 12C23 6.26461 18.6106 1.55443 13.0078 1.04555L12.9999 1.03571L12.5736 1.0147C12.4767 1.00972 12.3795 1.006 12.2819 1.00354C12.1882 1.00119 12.0942 1 12 1C11.9051 1 11.8104 1.0012 11.7161 1.00359C11.6192 1.00605 11.5226 1.00976 11.4263 1.0147L11.0001 1.03571L10.9922 1.04555ZM12.0011 3C13.6972 5.25767 14.7704 8.00828 14.9672 11H9.03278C9.22955 8.00828 10.3028 5.25767 11.9989 3C11.9992 3 11.9996 3 12 3C12.0004 3 12.0008 3 12.0011 3ZM7.02894 13C7.18917 15.7604 8.00847 18.3452 9.3315 20.5978C5.97059 19.5558 3.45261 16.5974 3.05493 13H7.02894ZM11.9988 21C10.3028 18.7423 9.22953 15.9917 9.03277 13H14.9672C14.7705 15.9917 13.6972 18.7423 12.0012 21C12.0008 21 12.0004 21 12 21C11.9996 21 11.9992 21 11.9988 21ZM14.6685 20.5978C15.9915 18.3452 16.8108 15.7604 16.9711 13H20.9451C20.5474 16.5974 18.0294 19.5558 14.6685 20.5978ZM16.9711 11C16.8108 8.23957 15.9915 5.65483 14.6684 3.40217C18.0294 4.44413 20.5474 7.40254 20.9451 11H16.9711Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="rgb(77, 107, 254)" xmlns="http://www.w3.org/2000/svg"><path d="M3.05493 11C3.45261 7.40254 5.97062 4.44413 9.33156 3.40217C8.00851 5.65483 7.1892 8.23957 7.02895 11H3.05493ZM10.9922 1.04555C5.38944 1.55442 1 6.26461 1 12C1 17.7354 5.3894 22.4455 10.9922 22.9545L11 22.9643L11.4254 22.9853C11.4932 22.9887 11.5611 22.9916 11.6292 22.9939C11.7523 22.9979 11.8759 23 12 23C12.1187 23 12.2369 22.9981 12.3546 22.9944C12.4281 22.9921 12.5015 22.989 12.5746 22.9853L13 22.9643L13.0078 22.9545C18.6106 22.4455 23 17.7354 23 12C23 6.26461 18.6106 1.55443 13.0078 1.04555L12.9999 1.03571L12.5736 1.0147C12.4767 1.00972 12.3795 1.006 12.2819 1.00354C12.1882 1.00119 12.0942 1 12 1C11.9051 1 11.8104 1.0012 11.7161 1.00359C11.6192 1.00605 11.5226 1.00976 11.4263 1.0147L11.0001 1.03571L10.9922 1.04555ZM12.0011 3C13.6972 5.25767 14.7704 8.00828 14.9672 11H9.03278C9.22955 8.00828 10.3028 5.25767 11.9989 3C11.9992 3 11.9996 3 12 3C12.0004 3 12.0008 3 12.0011 3ZM7.02894 13C7.18917 15.7604 8.00847 18.3452 9.3315 20.5978C5.97059 19.5558 3.45261 16.5974 3.05493 13H7.02894ZM11.9988 21C10.3028 18.7423 9.22953 15.9917 9.03277 13H14.9672C14.7705 15.9917 13.6972 18.7423 12.0012 21C12.0008 21 12.0004 21 12 21C11.9996 21 11.9992 21 11.9988 21ZM14.6685 20.5978C15.9915 18.3452 16.8108 15.7604 16.9711 13H20.9451C20.5474 16.5974 18.0294 19.5558 14.6685 20.5978ZM16.9711 11C16.8108 8.23957 15.9915 5.65483 14.6684 3.40217C18.0294 4.44413 20.5474 7.40254 20.9451 11H16.9711Z" fill="rgb(77, 107, 254)" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1 3H23V21H1V3ZM3 5V19H21V5H3ZM4.99609 7.5H7V9.50391H4.99609V7.5ZM8.99609 7.5H11V9.50391H8.99609V7.5ZM12.9961 7.5H15V9.50391H12.9961V7.5ZM16.9961 7.5H19V9.50391H16.9961V7.5ZM4.99609 10.5H7V12.5039H4.99609V10.5ZM8.99609 10.5H11V12.5039H8.99609V10.5ZM12.9961 10.5H15V12.5039H12.9961V10.5ZM16.9961 10.5H19V12.5039H16.9961V10.5ZM5 15H19V17H5V15Z" fill="black" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 472 B |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><path fill="rgb(95, 114, 146)" d="M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z"><animateTransform attributeName="transform" dur="0.75s" repeatCount="indefinite" type="rotate" values="0 12 12;360 12 12"/></path></svg>
|
||||
|
Before Width: | Height: | Size: 417 B |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3ZM1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12ZM10.5 7V17H8.5V7H10.5ZM15.5 7V17H13.5V7H15.5Z" fill="#8b8b8b" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 402 B |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" viewBox="0 0 32 32"><path fill="#909090" d="m24.1 2.072l5.564 5.8v22.056H8.879V30h20.856V7.945z"/><path fill="#f4f4f4" d="M24.031 2H8.808v27.928h20.856V7.873z"/><path fill="#7a7b7c" d="M8.655 3.5h-6.39v6.827h20.1V3.5z"/><path fill="#dd2025" d="M22.472 10.211H2.395V3.379h20.077z"/><path fill="#464648" d="M9.052 4.534H7.745v4.8h1.028V7.715L9 7.728a2 2 0 0 0 .647-.117a1.4 1.4 0 0 0 .493-.291a1.2 1.2 0 0 0 .335-.454a2.1 2.1 0 0 0 .105-.908a2.2 2.2 0 0 0-.114-.644a1.17 1.17 0 0 0-.687-.65a2 2 0 0 0-.409-.104a2 2 0 0 0-.319-.026m-.189 2.294h-.089v-1.48h.193a.57.57 0 0 1 .459.181a.92.92 0 0 1 .183.558c0 .246 0 .469-.222.626a.94.94 0 0 1-.524.114m3.671-2.306c-.111 0-.219.008-.295.011L12 4.538h-.78v4.8h.918a2.7 2.7 0 0 0 1.028-.175a1.7 1.7 0 0 0 .68-.491a1.9 1.9 0 0 0 .373-.749a3.7 3.7 0 0 0 .114-.949a4.4 4.4 0 0 0-.087-1.127a1.8 1.8 0 0 0-.4-.733a1.6 1.6 0 0 0-.535-.4a2.4 2.4 0 0 0-.549-.178a1.3 1.3 0 0 0-.228-.017m-.182 3.937h-.1V5.392h.013a1.06 1.06 0 0 1 .6.107a1.2 1.2 0 0 1 .324.4a1.3 1.3 0 0 1 .142.526c.009.22 0 .4 0 .549a3 3 0 0 1-.033.513a1.8 1.8 0 0 1-.169.5a1.1 1.1 0 0 1-.363.36a.67.67 0 0 1-.416.106m5.08-3.915H15v4.8h1.028V7.434h1.3v-.892h-1.3V5.43h1.4v-.892"/><path fill="#dd2025" d="M21.781 20.255s3.188-.578 3.188.511s-1.975.646-3.188-.511m-2.357.083a7.5 7.5 0 0 0-1.473.489l.4-.9c.4-.9.815-2.127.815-2.127a14 14 0 0 0 1.658 2.252a13 13 0 0 0-1.4.288Zm-1.262-6.5c0-.949.307-1.208.546-1.208s.508.115.517.939a10.8 10.8 0 0 1-.517 2.434a4.4 4.4 0 0 1-.547-2.162Zm-4.649 10.516c-.978-.585 2.051-2.386 2.6-2.444c-.003.001-1.576 3.056-2.6 2.444M25.9 20.895c-.01-.1-.1-1.207-2.07-1.16a14 14 0 0 0-2.453.173a12.5 12.5 0 0 1-2.012-2.655a11.8 11.8 0 0 0 .623-3.1c-.029-1.2-.316-1.888-1.236-1.878s-1.054.815-.933 2.013a9.3 9.3 0 0 0 .665 2.338s-.425 1.323-.987 2.639s-.946 2.006-.946 2.006a9.6 9.6 0 0 0-2.725 1.4c-.824.767-1.159 1.356-.725 1.945c.374.508 1.683.623 2.853-.91a23 23 0 0 0 1.7-2.492s1.784-.489 2.339-.623s1.226-.24 1.226-.24s1.629 1.639 3.2 1.581s1.495-.939 1.485-1.035"/><path fill="#909090" d="M23.954 2.077V7.95h5.633z"/><path fill="#f4f4f4" d="M24.031 2v5.873h5.633z"/><path fill="#fff" d="M8.975 4.457H7.668v4.8H8.7V7.639l.228.013a2 2 0 0 0 .647-.117a1.4 1.4 0 0 0 .493-.291a1.2 1.2 0 0 0 .332-.454a2.1 2.1 0 0 0 .105-.908a2.2 2.2 0 0 0-.114-.644a1.17 1.17 0 0 0-.687-.65a2 2 0 0 0-.411-.105a2 2 0 0 0-.319-.026m-.189 2.294h-.089v-1.48h.194a.57.57 0 0 1 .459.181a.92.92 0 0 1 .183.558c0 .246 0 .469-.222.626a.94.94 0 0 1-.524.114m3.67-2.306c-.111 0-.219.008-.295.011l-.235.006h-.78v4.8h.918a2.7 2.7 0 0 0 1.028-.175a1.7 1.7 0 0 0 .68-.491a1.9 1.9 0 0 0 .373-.749a3.7 3.7 0 0 0 .114-.949a4.4 4.4 0 0 0-.087-1.127a1.8 1.8 0 0 0-.4-.733a1.6 1.6 0 0 0-.535-.4a2.4 2.4 0 0 0-.549-.178a1.3 1.3 0 0 0-.228-.017m-.182 3.937h-.1V5.315h.013a1.06 1.06 0 0 1 .6.107a1.2 1.2 0 0 1 .324.4a1.3 1.3 0 0 1 .142.526c.009.22 0 .4 0 .549a3 3 0 0 1-.033.513a1.8 1.8 0 0 1-.169.5a1.1 1.1 0 0 1-.363.36a.67.67 0 0 1-.416.106m5.077-3.915h-2.43v4.8h1.028V7.357h1.3v-.892h-1.3V5.353h1.4v-.892"/></svg>
|
||||
|
Before Width: | Height: | Size: 3.0 KiB |
|
|
@ -1,2 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g opacity="0.9"> <path d="M12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3ZM1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12ZM8.5 6.37083L18.25 12L8.5 17.6292L8.5 6.37083ZM10.5 9.83494L10.5 14.1651L14.25 12L10.5 9.83494Z" fill="#8b8b8b" /></g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 485 B |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><rect width="2.8" height="12" x="1" y="6" fill="#8b8b8b"><animate id="svgSpinnersBarsScale0" attributeName="y" begin="0;svgSpinnersBarsScale1.end-0.1s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="6;1;6"/><animate attributeName="height" begin="0;svgSpinnersBarsScale1.end-0.1s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="12;22;12"/></rect><rect width="2.8" height="12" x="5.8" y="6" fill="#8b8b8b"><animate attributeName="y" begin="svgSpinnersBarsScale0.begin+0.1s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScale0.begin+0.1s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="12;22;12"/></rect><rect width="2.8" height="12" x="10.6" y="6" fill="#8b8b8b"><animate attributeName="y" begin="svgSpinnersBarsScale0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScale0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="12;22;12"/></rect><rect width="2.8" height="12" x="15.4" y="6" fill="#8b8b8b"><animate attributeName="y" begin="svgSpinnersBarsScale0.begin+0.3s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScale0.begin+0.3s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="12;22;12"/></rect><rect width="2.8" height="12" x="20.2" y="6" fill="#8b8b8b"><animate id="svgSpinnersBarsScale1" attributeName="y" begin="svgSpinnersBarsScale0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScale0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="12;22;12"/></rect></svg>
|
||||
|
Before Width: | Height: | Size: 2.0 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 32 32"><path fill="#d33922" d="M18.536 2.321v2.863c3.4.019 7.357-.035 10.754.016c.642 0 .67.568.678 1.064c.054 5.942-.013 12.055.032 18c-.012.234-.006 1.1-.013 1.346c-.022.823-.434.859-1.257.884c-.132 0-.52.006-.648.012c-3.181-.016-6.362-.009-9.546-.009v3.182L2 27.134V4.873z"/><path fill="#fff" d="M18.536 6.138h10.5v19.4h-10.5V23h7.634v-1.275h-7.634v-1.59h7.634v-1.272h-7.631q.002-.936-.006-1.87a4.47 4.47 0 0 0 3.82-.375a4.35 4.35 0 0 0 1.959-3.474c-1.4-.01-2.793-.006-4.186-.006c0-1.384.016-2.767-.029-4.148c-.522.1-1.043.21-1.562.321V6.139"/><path fill="#d33922" d="M20.766 8.324a4.476 4.476 0 0 1 4.186 4.167c-1.4.016-2.793.01-4.189.01V8.324"/><path fill="#fff" d="M7.1 10.726c1.727.083 3.82-.684 5.252.611c1.371 1.664 1.008 4.724-1.024 5.719A4.7 4.7 0 0 1 9 17.348c0 1.244-.006 2.488 0 3.731q-.947-.082-1.893-.159c-.029-3.4-.035-6.8 0-10.2"/><path fill="#d33922" d="M8.993 12.446c.627-.029 1.4-.143 1.826.445a2.3 2.3 0 0 1 .041 2.087c-.363.655-1.183.592-1.816.668c-.067-1.066-.06-2.131-.051-3.2"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |