对接选课接口
This commit is contained in:
parent
f4e8120d91
commit
8e709572b3
@ -1,26 +1,21 @@
|
|||||||
// 参数接口
|
// 参数接口
|
||||||
|
|
||||||
// 响应接口
|
// 响应接口
|
||||||
import {get, post} from "@/utils/request";
|
import { get, post } from "@/utils/request";
|
||||||
|
|
||||||
|
export const loginRegisterJzApi = async (params: any) => {
|
||||||
/**
|
return await post("/open/login/registerJz", params);
|
||||||
* 获取服务器时间
|
};
|
||||||
*/
|
export const xkAddXkqdApi = async (params: any) => {
|
||||||
export const serverTimeApi = async () => {
|
return await post("/mobile/xk/addXkqd", params);
|
||||||
return await get('/api/server/serverTime')
|
|
||||||
}
|
|
||||||
export const standardWordsRandomApi = async () => {
|
|
||||||
return await get('/api/standardWords/findRandom')
|
|
||||||
}
|
|
||||||
export const cmsArticleFindPageApi = async (params: any) => {
|
|
||||||
return await get("/api/cmsArticle/findPage", params);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const agencyAgencyListApi = async () => {
|
export const xkListApi = async (params: any) => {
|
||||||
return await get("/api/agency/agencyList");
|
return await get("/mobile/xk/list", params);
|
||||||
};
|
};
|
||||||
|
export const xkXkqdApi = async (params: any) => {
|
||||||
export const serverCheckInRangeTimeApi = async () => {
|
return await get("/mobile/xk/xkqd", params);
|
||||||
return await get("/api/server/checkInRangeTime");
|
};
|
||||||
|
export const kcjhFindKcjhByKcIdApi = async (params: any) => {
|
||||||
|
return await get("/api/kcjh/findKcjhByKcId", params);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
import {get, post} from "@/utils/request";
|
import { get, post } from "@/utils/request";
|
||||||
|
|
||||||
//字典接口
|
//字典接口
|
||||||
export const dicApi = async (param: { pid: number }) => {
|
export const dicApi = async (param: { pid: number }) => {
|
||||||
return await get("/api/dic/findByPid", param);
|
return await get("/api/dic/findByPid", param);
|
||||||
};
|
};
|
||||||
|
//字典接口
|
||||||
|
export const findDicTreeByPidApi = async (param: { pid: number }) => {
|
||||||
|
return await get("/api/dic/findDicTreeByPid", param);
|
||||||
|
};
|
||||||
|
|
||||||
//根据id查询部门
|
//根据id查询部门
|
||||||
export const deptFindAllDeptsByPidApi = async (param: { pid: number }) => {
|
export const deptFindAllDeptsByPidApi = async (param: { pid: number }) => {
|
||||||
@ -12,11 +16,25 @@ export const deptFindAllDeptsByPidApi = async (param: { pid: number }) => {
|
|||||||
|
|
||||||
//刷新token
|
//刷新token
|
||||||
export const refreshTokenApi = async (param: { refresh_token: string }) => {
|
export const refreshTokenApi = async (param: { refresh_token: string }) => {
|
||||||
return await post("/userlogin/refresh-token?refresh_token=" + param.refresh_token, param);
|
return await post(
|
||||||
|
"/userlogin/refresh-token?refresh_token=" + param.refresh_token,
|
||||||
|
param
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
//修改用户部门
|
//修改用户部门
|
||||||
export const userSaveApi = async (param: { id: string, deptId: string, deptName: string }) => {
|
export const userSaveApi = async (param: {
|
||||||
return await post("/api/user/save?deptId=" + param.deptId + '&deptName=' + param.deptName + '&id=' + param.id, param);
|
id: string;
|
||||||
|
deptId: string;
|
||||||
|
deptName: string;
|
||||||
|
}) => {
|
||||||
|
return await post(
|
||||||
|
"/api/user/save?deptId=" +
|
||||||
|
param.deptId +
|
||||||
|
"&deptName=" +
|
||||||
|
param.deptName +
|
||||||
|
"&id=" +
|
||||||
|
param.id,
|
||||||
|
param
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,28 @@
|
|||||||
//登录接口
|
//登录接口
|
||||||
import {get, post} from "@/utils/request";
|
import { get, post } from "@/utils/request";
|
||||||
|
|
||||||
//密码登录接口
|
//密码登录接口
|
||||||
export const loginPass = async (param: { username: string, password: string, openId: number | string }) => {
|
export const loginPass = async (param: {
|
||||||
return await post("/userlogin/check?username=" + param.username + '&password=' + param.password + '&openId=' + param.openId, param
|
username: string;
|
||||||
)
|
password: string;
|
||||||
;
|
openId: number | string;
|
||||||
|
}) => {
|
||||||
|
return await post(
|
||||||
|
"/userlogin/check?username=" +
|
||||||
|
param.username +
|
||||||
|
"&password=" +
|
||||||
|
param.password +
|
||||||
|
"&openId=" +
|
||||||
|
param.openId,
|
||||||
|
param
|
||||||
|
);
|
||||||
};
|
};
|
||||||
//验证码登录接口
|
//验证码登录接口
|
||||||
export const loginCode = async (param: { phone: string | number, code: string | number, openId: number | string }) => {
|
export const loginCode = async (param: {
|
||||||
|
phone: string | number;
|
||||||
|
code: string | number;
|
||||||
|
openId: number | string;
|
||||||
|
}) => {
|
||||||
return await post("/open/sms/checkCode", param);
|
return await post("/open/sms/checkCode", param);
|
||||||
};
|
};
|
||||||
//验证码登录接口
|
//验证码登录接口
|
||||||
@ -16,7 +30,7 @@ export const loginCheckCode = async (param: any) => {
|
|||||||
return await post("/open/sms/checkCode", param);
|
return await post("/open/sms/checkCode", param);
|
||||||
};
|
};
|
||||||
//获取验证码接口
|
//获取验证码接口
|
||||||
export const sendCodeApi = async (param:any) => {
|
export const sendCodeApi = async (param: any) => {
|
||||||
return await get("/open/sms/sendCode", param);
|
return await get("/open/sms/sendCode", param);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -35,15 +49,20 @@ export const authenticationApi = async (param: { userId: string }) => {
|
|||||||
return await get("/api/authentication/find-by-user", param);
|
return await get("/api/authentication/find-by-user", param);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 汇兴小程序登录
|
|
||||||
export const huiXingLoginApi = async (param: { token: string }) => {
|
|
||||||
return await post("/userlogin/appCheck?token=" + param.token, param);
|
|
||||||
};
|
|
||||||
|
|
||||||
//获取公众号票据
|
//获取公众号票据
|
||||||
export const wxConfigApi = async (param: any) => {
|
export const wxConfigApi = async (param: any) => {
|
||||||
return await post("/userlogin/wxConfig", param);
|
return await post("/userlogin/wxConfig", param);
|
||||||
};
|
};
|
||||||
export const checkOpenId = async (param: { openId: string | number, appCode: string }) => {
|
|
||||||
return await post("/open/sms/checkOpenId", param);
|
export const checkOpenId = async (param: {
|
||||||
|
openId: string | number;
|
||||||
|
appCode: string;
|
||||||
|
}) => {
|
||||||
|
return await post("/open/login/jz/checkUser", param);
|
||||||
|
};
|
||||||
|
export const updateUserApi = async (param: any) => {
|
||||||
|
return await post("/open/login/js/updateUser", param);
|
||||||
|
};
|
||||||
|
export const findJsByPhoneApi = async (param: any) => {
|
||||||
|
return await get("/api/js/findJsByPhone", param);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,69 +1,124 @@
|
|||||||
<template>
|
<template>
|
||||||
<uni-data-picker :popup-title="'请选择'+attrs.label"
|
<view>
|
||||||
|
<u-loading-icon
|
||||||
|
:show="loadingShow"
|
||||||
|
style="justify-content: start"
|
||||||
|
size="20"
|
||||||
|
/>
|
||||||
|
<uni-data-picker
|
||||||
|
v-if="!loadingShow"
|
||||||
|
:popup-title="'请选择' + attrs.label"
|
||||||
:localdata="range"
|
:localdata="range"
|
||||||
v-model="newValue"
|
v-model="newValue"
|
||||||
:map="{text:attrs.componentProps.rangeKey,value:attrs.componentProps.savaKey}"
|
:map="{
|
||||||
@change="onchange" @nodeclick="onnodeclick" @popupopened="onpopupopened"
|
text: attrs.componentProps.rangeKey,
|
||||||
|
value: attrs.componentProps.savaKey,
|
||||||
|
}"
|
||||||
|
@change="onchange"
|
||||||
|
@nodeclick="onnodeclick"
|
||||||
|
@popupopened="onpopupopened"
|
||||||
@popupclosed="onpopupclosed"
|
@popupclosed="onpopupclosed"
|
||||||
:readonly="!!attrs.componentProps.disabled"
|
:readonly="!!attrs.componentProps.disabled"
|
||||||
v-bind="attrs.componentProps"
|
v-bind="attrs.componentProps"
|
||||||
>
|
>
|
||||||
<template #default="{data, error, options}">
|
<template #default="{ data, error, options }">
|
||||||
<view class="flex-row items-center justify-between py-7 font-13">
|
<view class="flex-row items-center justify-between py-7 font-13">
|
||||||
<view v-if="error">
|
<view v-if="error">
|
||||||
<text style="color: red">{{ error }}</text>
|
<text style="color: red">{{ error }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view v-else-if="data.length" class="flex-row">
|
<view v-else-if="data.length" class="flex-row">
|
||||||
<view v-for="(item,index) in data" :key="index" class="selected-item">
|
<view
|
||||||
|
v-for="(item, index) in data"
|
||||||
|
:key="index"
|
||||||
|
class="selected-item"
|
||||||
|
>
|
||||||
<text>{{ item.text }}</text>
|
<text>{{ item.text }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="color-9" v-else-if="!attrs.componentProps.disabled">
|
<view class="color-9" v-else-if="!attrs.componentProps.disabled">
|
||||||
<text v-if="attrs.componentProps&&attrs.componentProps.placeholder">{{
|
<text
|
||||||
attrs.componentProps.placeholder
|
v-if="attrs.componentProps && attrs.componentProps.placeholder"
|
||||||
}}
|
>{{ attrs.componentProps.placeholder }}
|
||||||
</text>
|
</text>
|
||||||
<text v-else>请选择{{ attrs.label }}</text>
|
<text v-else>请选择{{ attrs.label }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view v-else>无</view>
|
<view v-else>无</view>
|
||||||
<uni-icons type="right" size="18" color="#999999" v-if="!attrs.componentProps.disabled"/>
|
<uni-icons
|
||||||
|
type="right"
|
||||||
|
size="18"
|
||||||
|
color="#999999"
|
||||||
|
v-if="!attrs.componentProps.disabled"
|
||||||
|
/>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
</uni-data-picker>
|
</uni-data-picker>
|
||||||
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const props = defineProps(['modelValue'])
|
import { isFunction, map } from "lodash";
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const props = defineProps(["modelValue"]);
|
||||||
|
const emit = defineEmits(["update:modelValue"]);
|
||||||
const newValue = computed({
|
const newValue = computed({
|
||||||
get() {
|
get() {
|
||||||
return props.modelValue
|
return props.modelValue;
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
emit('update:modelValue', value)
|
emit("update:modelValue", value);
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
const attrs = useAttrs()
|
const attrs = useAttrs();
|
||||||
|
|
||||||
if (!newValue.value) {
|
if (!newValue.value) {
|
||||||
newValue.value = '0'
|
newValue.value = "0";
|
||||||
}
|
}
|
||||||
|
|
||||||
const range = ref(attrs.componentProps && attrs.componentProps.range || [])
|
const range = computed({
|
||||||
|
get() {
|
||||||
|
if (attrs.componentProps && attrs.componentProps.range) {
|
||||||
|
return attrs.componentProps.range;
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
attrs.componentProps.range = value;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const loadingShow = ref(false);
|
||||||
|
function initapi() {
|
||||||
|
if (attrs.componentProps.api && isFunction(attrs.componentProps.api)) {
|
||||||
|
loadingShow.value = true;
|
||||||
|
attrs.componentProps.api(attrs.componentProps.param || null).then((res) => {
|
||||||
|
attrs.componentProps.range =
|
||||||
|
res[attrs.componentProps.resultKey || "result"];
|
||||||
|
if (
|
||||||
|
attrs.componentProps.request &&
|
||||||
|
isFunction(attrs.componentProps.request)
|
||||||
|
) {
|
||||||
|
attrs.componentProps.request(attrs.componentProps.range);
|
||||||
|
}
|
||||||
|
loadingShow.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initapi();
|
||||||
|
|
||||||
function onchange(e) {
|
function onchange(e) {
|
||||||
|
if (
|
||||||
|
attrs.componentProps.onChange &&
|
||||||
|
isFunction(attrs.componentProps.onChange)
|
||||||
|
) {
|
||||||
|
attrs.componentProps.onChange(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onnodeclick() {
|
function onnodeclick() {}
|
||||||
|
|
||||||
}
|
function onpopupopened() {}
|
||||||
|
|
||||||
function onpopupopened() {
|
function onpopupclosed() {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function onpopupclosed() {
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -37,10 +37,10 @@ const newValue = computed({
|
|||||||
const attrs: any = useAttrs()
|
const attrs: any = useAttrs()
|
||||||
|
|
||||||
function change(e: string) {
|
function change(e: string) {
|
||||||
|
newValue.value = e
|
||||||
if (attrs.componentProps.change && isFunction(attrs.componentProps.change)) {
|
if (attrs.componentProps.change && isFunction(attrs.componentProps.change)) {
|
||||||
attrs.componentProps.change(e)
|
attrs.componentProps.change(e)
|
||||||
}
|
}
|
||||||
newValue.value = e
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|||||||
141
src/components/BasicForm/components/BasicTree.vue
Normal file
141
src/components/BasicForm/components/BasicTree.vue
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
<template>
|
||||||
|
<view class="py-7">
|
||||||
|
<u-loading-icon :show="loadingShow" style="justify-content: start" size="20"/>
|
||||||
|
<view @click="open" class="wh-full flex-row items-center justify-between" v-if="!loadingShow">
|
||||||
|
<view class="font-13 text-ellipsis-1" v-if="pickerValue">{{ pickerValue.join(',') }}</view>
|
||||||
|
<view class="font-13 color-9" v-else-if="!attrs.componentProps.disabled">
|
||||||
|
<text v-if="attrs.componentProps&&attrs.componentProps.placeholder">{{
|
||||||
|
attrs.componentProps.placeholder
|
||||||
|
}}
|
||||||
|
</text>
|
||||||
|
<text v-else>请选择{{ attrs.label }}</text>
|
||||||
|
</view>
|
||||||
|
<view v-else>无</view>
|
||||||
|
<uni-icons type="right" size="18" color="#999999" v-if="!attrs.componentProps.disabled"/>
|
||||||
|
</view>
|
||||||
|
<BasicTree ref="basicTreeRef"
|
||||||
|
:range="range"
|
||||||
|
:idKey="savaKey"
|
||||||
|
:rangeKey="rangeKey"
|
||||||
|
:title="'选择'+ attrs.label"
|
||||||
|
@confirm="confirm"
|
||||||
|
v-bind="attrs.componentProps"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import BasicTree from '@/components/BasicTree/Tree.vue';
|
||||||
|
/**
|
||||||
|
* BasicPicker 选择器
|
||||||
|
* @property title 顶部title
|
||||||
|
* @property range 渲染数据列表
|
||||||
|
* @property api 渲染数据接口
|
||||||
|
* @property param 接口参数
|
||||||
|
* @property resultKey 数据接口返回字段默认为result
|
||||||
|
* @property rangeKey 显示值的key
|
||||||
|
* @property savaKey 保存值的key
|
||||||
|
*
|
||||||
|
* @property @ok 点击确定事件
|
||||||
|
* @property @change 选择器change事件
|
||||||
|
*/
|
||||||
|
import {isFunction, map} from "lodash";
|
||||||
|
|
||||||
|
const loadingShow = ref(false)
|
||||||
|
const basicTreeRef = ref<any>(null)
|
||||||
|
const props = defineProps(['modelValue'])
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const pickerValue = ref<any>([])
|
||||||
|
|
||||||
|
const newValue = computed({
|
||||||
|
get() {
|
||||||
|
return props.modelValue
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
emit('update:modelValue', value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const attrs: any = useAttrs()
|
||||||
|
|
||||||
|
const rangeKey = ref(attrs.componentProps && attrs.componentProps.rangeKey || '')
|
||||||
|
const savaKey = ref(attrs.componentProps && attrs.componentProps.savaKey || '')
|
||||||
|
|
||||||
|
const range = computed({
|
||||||
|
get() {
|
||||||
|
if (attrs.componentProps && attrs.componentProps.range) {
|
||||||
|
return attrs.componentProps.range
|
||||||
|
} else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
attrs.componentProps.range = value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
function initapi() {
|
||||||
|
if (attrs.componentProps.api && isFunction(attrs.componentProps.api)) {
|
||||||
|
loadingShow.value = true
|
||||||
|
attrs.componentProps.api(attrs.componentProps.param || null).then((res: any) => {
|
||||||
|
attrs.componentProps.range = res[attrs.componentProps.resultKey || 'result']
|
||||||
|
if (attrs.componentProps.request && isFunction(attrs.componentProps.request)) {
|
||||||
|
attrs.componentProps.request(attrs.componentProps.range)
|
||||||
|
}
|
||||||
|
loadingShow.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initapi()
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
if (!attrs.componentProps.disabled) {
|
||||||
|
basicTreeRef.value._show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirm(value: any) {
|
||||||
|
const valueDataID = map(value, (item) => {
|
||||||
|
return item[attrs.componentProps.savaKey]
|
||||||
|
})
|
||||||
|
newValue.value = valueDataID.join(',')
|
||||||
|
|
||||||
|
if (attrs.componentProps.ok && typeof attrs.componentProps.ok === 'function') {
|
||||||
|
attrs.componentProps.ok(value, attrs.componentProps.range)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hx(rangeData: any, data: any) {
|
||||||
|
let valueList = data.split(',')
|
||||||
|
for (const key in rangeData) {
|
||||||
|
for (const vkey in valueList) {
|
||||||
|
if (rangeData[key][attrs.componentProps.savaKey] == valueList[vkey]) {
|
||||||
|
rangeData[key].checked = true;
|
||||||
|
if (!attrs.componentProps.multiple) {
|
||||||
|
pickerValue.value = []
|
||||||
|
}
|
||||||
|
pickerValue.value.push(rangeData[key][attrs.componentProps.rangeKey])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rangeData[key].children && rangeData[key].children.length > 0) {
|
||||||
|
hx(rangeData[key].children, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
range.value = rangeData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
if (newValue.value || newValue.value == 0) {
|
||||||
|
if (attrs.componentProps.range && attrs.componentProps.range.length > 0) {
|
||||||
|
hx(attrs.componentProps.range, newValue.value.toString())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pickerValue.value = newValue.value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
@ -14,6 +14,7 @@
|
|||||||
<FormBasicDataPicker v-bind="attrs" v-if="isShow('BasicDataPicker')" v-model="newValue"/>
|
<FormBasicDataPicker v-bind="attrs" v-if="isShow('BasicDataPicker')" v-model="newValue"/>
|
||||||
<FormBasicSearchList v-bind="attrs" v-if="isShow('BasicSearchList')" v-model="newValue"/>
|
<FormBasicSearchList v-bind="attrs" v-if="isShow('BasicSearchList')" v-model="newValue"/>
|
||||||
<FormBasicDateTimes v-bind="attrs" v-if="isShow('BasicDateTimes')" v-model="newValue"/>
|
<FormBasicDateTimes v-bind="attrs" v-if="isShow('BasicDateTimes')" v-model="newValue"/>
|
||||||
|
<FormBasicTree v-bind="attrs" v-if="isShow('BasicTree')" v-model="newValue"/>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
1
src/components/BasicForm/type/useForm.d.ts
vendored
1
src/components/BasicForm/type/useForm.d.ts
vendored
@ -26,6 +26,7 @@ type Component =
|
|||||||
| 'BasicDataPicker'
|
| 'BasicDataPicker'
|
||||||
| 'BasicSearchList'
|
| 'BasicSearchList'
|
||||||
| 'BasicDateTimes'
|
| 'BasicDateTimes'
|
||||||
|
| 'BasicTree'
|
||||||
|
|
||||||
interface FormsSchema {
|
interface FormsSchema {
|
||||||
field?: string,
|
field?: string,
|
||||||
|
|||||||
@ -407,7 +407,7 @@ export default {
|
|||||||
background: #FFF;
|
background: #FFF;
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
width: 90vw;
|
width: 90vw;
|
||||||
height: 90vh;
|
height: 88vh;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
// pointer-events:none;
|
// pointer-events:none;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
const ip: string = "dj.zhongjingzh.com";
|
const ip: string = "119.29.194.155:8893";
|
||||||
|
const fwqip: string = "yufangzc.com";
|
||||||
//打包服务器接口代理标识
|
//打包服务器接口代理标识
|
||||||
const SERVERAGENT: string = "/";
|
const SERVERAGENT: string = "/jzd-api";
|
||||||
//本地代理url地址,配置了就启动代理,没配置就不启动代理
|
//本地代理url地址,配置了就启动代理,没配置就不启动代理
|
||||||
export const HOMEAGENT: string = "";
|
export const HOMEAGENT: string = "";
|
||||||
// 接口地址
|
// 接口地址
|
||||||
export const BASE_URL: string =
|
export const BASE_URL: string =
|
||||||
process.env.NODE_ENV == "development" ? `http://${ip}/yqdj` : SERVERAGENT;
|
process.env.NODE_ENV == "development" ? `http://${ip}/zhxy` : SERVERAGENT;
|
||||||
// WebSocket地址
|
// WebSocket地址
|
||||||
export const BASE_WS_URL: string = `wss://${ip}`;
|
export const BASE_WS_URL: string = `wss://${ip}`;
|
||||||
//图片地址
|
//图片地址
|
||||||
export const BASE_IMAGE_URL: string = `http://${ip}`;
|
export const BASE_IMAGE_URL: string = process.env.NODE_ENV == "development" ? `http://${ip}` : `https://${fwqip}`;
|
||||||
//存token的key
|
//存token的key
|
||||||
export const AUTH_KEY: string = "satoken";
|
export const AUTH_KEY: string = "satoken";
|
||||||
//token过期返回状态码
|
//token过期返回状态码
|
||||||
@ -17,7 +18,7 @@ export const RESULT_CODE_NOT_LOGIN: number = 10;
|
|||||||
//是否打印接口日志
|
//是否打印接口日志
|
||||||
export const ISREQUESTLOG: boolean = false;
|
export const ISREQUESTLOG: boolean = false;
|
||||||
//是否打开登录页面拦截
|
//是否打开登录页面拦截
|
||||||
export const ISROUTERINTERCEPT: boolean = false;
|
export const ISROUTERINTERCEPT: boolean = true;
|
||||||
//配置路由白名单
|
//配置路由白名单
|
||||||
export const WHITELIST: WhiteList = [];
|
export const WHITELIST: WhiteList = [];
|
||||||
//主题颜色
|
//主题颜色
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "模版",
|
"name": "智慧校园",
|
||||||
"appid": "__UNI__27C6F45",
|
"appid": "__UNI__27C6F45",
|
||||||
"description": "",
|
"description": "",
|
||||||
"versionName": "1.0.0",
|
"versionName": "1.0.0",
|
||||||
@ -207,9 +207,9 @@
|
|||||||
"uniStatistics": {
|
"uniStatistics": {
|
||||||
"enable": false
|
"enable": false
|
||||||
},
|
},
|
||||||
"publicPath": "/",
|
"publicPath": "/zhxy-jzd",
|
||||||
"router": {
|
"router": {
|
||||||
"base": "/",
|
"base": "/zhxy-jzd/",
|
||||||
"mode": "hash"
|
"mode": "hash"
|
||||||
},
|
},
|
||||||
"sdkConfigs": {
|
"sdkConfigs": {
|
||||||
|
|||||||
@ -91,13 +91,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"path": "pages/base/parentRegister/index",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "家长注册",
|
|
||||||
"enablePullDownRefresh": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"path": "pages/base/class-schedule/index",
|
"path": "pages/base/class-schedule/index",
|
||||||
"style": {
|
"style": {
|
||||||
@ -195,6 +188,26 @@
|
|||||||
"navigationBarTitleText": "俱乐部选课",
|
"navigationBarTitleText": "俱乐部选课",
|
||||||
"enablePullDownRefresh": false
|
"enablePullDownRefresh": false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/base/course-selection/notice",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "告知书",
|
||||||
|
"enablePullDownRefresh": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/base/course-selection/enrolled",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "已报名",
|
||||||
|
"enablePullDownRefresh": false
|
||||||
|
}
|
||||||
|
} , {
|
||||||
|
"path": "pages/base/course-selection/notopen",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "未开放",
|
||||||
|
"enablePullDownRefresh": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"globalStyle": {
|
"globalStyle": {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,7 @@
|
|||||||
<view class="course-info">
|
<view class="course-info">
|
||||||
<image
|
<image
|
||||||
class="course-image"
|
class="course-image"
|
||||||
:src="courseDetail.image || '/static/images/course-default.jpg'"
|
:src="courseDetail.xkkcImg"
|
||||||
mode="aspectFill"
|
mode="aspectFill"
|
||||||
></image>
|
></image>
|
||||||
|
|
||||||
@ -21,11 +21,12 @@
|
|||||||
<view class="course-location"
|
<view class="course-location"
|
||||||
>上课地点:{{ courseDetail.location }}</view
|
>上课地点:{{ courseDetail.location }}</view
|
||||||
>
|
>
|
||||||
<view class="course-price"
|
<view class="course-time"
|
||||||
>金额:<text class="price-value"
|
>上课时间:{{ courseDetail.studyTime }}</view
|
||||||
>¥{{ courseDetail.price }}</text
|
|
||||||
></view
|
|
||||||
>
|
>
|
||||||
|
<view class="course-price">
|
||||||
|
金额:<text class="price-value">¥{{ courseDetail.price }}</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -36,17 +37,28 @@
|
|||||||
<view class="divider"></view>
|
<view class="divider"></view>
|
||||||
|
|
||||||
<view class="teacher-info">
|
<view class="teacher-info">
|
||||||
|
<!-- 教师头部信息区域 -->
|
||||||
|
<view class="teacher-header">
|
||||||
<image
|
<image
|
||||||
class="teacher-avatar"
|
class="teacher-avatar"
|
||||||
:src="teacherInfo.avatar || '/static/images/teacher-avatar.jpg'"
|
:src="teacherInfo.avatar"
|
||||||
mode="aspectFill"
|
mode="aspectFill"
|
||||||
></image>
|
></image>
|
||||||
|
<view class="teacher-basic-info">
|
||||||
|
<view class="teacher-name">{{ teacherInfo.name }}</view>
|
||||||
|
<view class="teacher-title">课程教师</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 教师简介区域 -->
|
||||||
|
<view class="teacher-intro-section">
|
||||||
|
<view class="intro-title">教师简介</view>
|
||||||
<view class="teacher-intro">
|
<view class="teacher-intro">
|
||||||
<text>{{ teacherInfo.introduction }}</text>
|
<text>{{ teacherInfo.introduction }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 教学理念 -->
|
<!-- 教学理念 -->
|
||||||
<view class="info-card">
|
<view class="info-card">
|
||||||
@ -64,6 +76,7 @@
|
|||||||
<view class="divider"></view>
|
<view class="divider"></view>
|
||||||
|
|
||||||
<view class="content-section">
|
<view class="content-section">
|
||||||
|
<template v-if="teachingPlan && teachingPlan.length > 0">
|
||||||
<view
|
<view
|
||||||
v-for="(phase, index) in teachingPlan"
|
v-for="(phase, index) in teachingPlan"
|
||||||
:key="index"
|
:key="index"
|
||||||
@ -71,6 +84,13 @@
|
|||||||
>
|
>
|
||||||
<text>{{ phase }}</text>
|
<text>{{ phase }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<view class="empty-data">
|
||||||
|
<u-icon name="info-circle" color="#C8C9CC" size="18"></u-icon>
|
||||||
|
<text>暂无教学计划</text>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -90,57 +110,81 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted, computed } from "vue";
|
||||||
import { navigateBack } from "@/utils/uniapp";
|
import { navigateBack } from "@/utils/uniapp";
|
||||||
|
import { useDataStore } from "@/store/modules/data";
|
||||||
|
import { storeToRefs } from "pinia";
|
||||||
|
import { imagUrl } from "@/utils";
|
||||||
|
import { kcjhFindKcjhByKcIdApi } from "@/api/base/server";
|
||||||
|
|
||||||
|
// 定义课程数据类型
|
||||||
|
interface CourseData {
|
||||||
|
id?: string;
|
||||||
|
kcmc?: string;
|
||||||
|
jsName?: string;
|
||||||
|
kcdd?: string;
|
||||||
|
kcje?: number;
|
||||||
|
studyTime?: string;
|
||||||
|
kcjsms?: string;
|
||||||
|
jxll?: string;
|
||||||
|
remark?: string;
|
||||||
|
xkkcImg?: string;
|
||||||
|
[key: string]: any; // 允许其他字段
|
||||||
|
}
|
||||||
|
|
||||||
|
const useData = useDataStore();
|
||||||
|
const { kcData } = storeToRefs(useData);
|
||||||
|
|
||||||
|
// 教学计划 - 此处假设没有具体教学计划字段,将备注内容拆分为教学计划
|
||||||
|
const teachingPlan = ref<string[]>([]);
|
||||||
|
|
||||||
|
const courseData = kcData.value as CourseData;
|
||||||
|
if (courseData && courseData.id) {
|
||||||
|
kcjhFindKcjhByKcIdApi({
|
||||||
|
xkkcId: courseData.id,
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.resultCode == 1) {
|
||||||
|
teachingPlan.value = res.result.map(
|
||||||
|
(item: any) => item.jhjd + ":" + item.jhms
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 课程详情数据
|
// 课程详情数据
|
||||||
const courseDetail = ref({
|
const courseDetail = computed(() => {
|
||||||
id: 2,
|
const data = (kcData.value as CourseData) || {};
|
||||||
title: "机器人创客",
|
return {
|
||||||
teacher: "叶老师",
|
id: data.id || "",
|
||||||
location: "第一教学楼302",
|
title: data.kcmc || "暂无课程名称",
|
||||||
price: 142,
|
teacher: data.jsName || "暂无教师信息",
|
||||||
image: "/static/images/robot-course.jpg",
|
location: data.kcdd || "暂无地点信息",
|
||||||
|
price: data.kcje || 0,
|
||||||
|
studyTime: data.studyTime || "暂无上课时间",
|
||||||
|
xkkcImg: data.xkkcImg || "/static/images/robot-course.jpg", // 默认图片
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// 教师信息
|
// 教师信息
|
||||||
const teacherInfo = ref({
|
const teacherInfo = computed(() => {
|
||||||
name: "叶老师",
|
const data = (kcData.value as CourseData) || {};
|
||||||
avatar: "/static/images/teacher-avatar.jpg",
|
return {
|
||||||
introduction:
|
name: data.jsName || "暂无教师信息",
|
||||||
"叶老师,男,出生于1997年7月10日,青少年机器人创客指导教师,指导祥富小学-晟航水木年华获得2022年青少年机器人竞赛小学组三等奖。",
|
avatar: imagUrl(data.jstx), // 默认头像
|
||||||
|
introduction: data.kcjsms || "暂无教师介绍",
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// 教学理念
|
// 教学理念
|
||||||
const teachingPhilosophy = ref(
|
const teachingPhilosophy = computed(() => {
|
||||||
'"做中学、玩中学"的教育理念,机器人课程最大的优势就是能够让孩子在"玩"中去探索,去体验属于他们自己的世界,很多孩子刚开始接触的时候都是出于兴趣。培养孩子更进一步的能力,提高孩子的学习效果也的确需要从兴趣开始。但真正激发孩子能力,形成学习动力的是对目标的追求。我就通过机器人赛事帮助孩子把"兴趣"变成学习的目标,继而助力孩子未来成长的道路。'
|
const data = (kcData.value as CourseData) || {};
|
||||||
);
|
return data.jxll || "暂无教学理念信息";
|
||||||
|
|
||||||
// 教学计划
|
|
||||||
const teachingPlan = ref([
|
|
||||||
"第一阶段:了解机器人的组成,知道每个零件的名称及用途,认识机器人的结构。",
|
|
||||||
"第二阶段:在老师的引导下,分组搭建机器人,注意引导幼儿理解机器人的数据线连接和遥控器方向的关系。",
|
|
||||||
"第三阶段:学会操控机器人的移动方向,并练习把魔方根据要求推到指定位置。",
|
|
||||||
"第四阶段:组织幼儿参加创客机器人比赛。",
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 返回上一页
|
|
||||||
const goBack = () => {
|
|
||||||
uni.navigateBack();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 页面加载时获取课程详情
|
|
||||||
onMounted(() => {
|
|
||||||
// 实际应用中从URL参数获取课程ID,然后请求详情
|
|
||||||
const courseId = uni.getStorageSync("currentCourseId") || 2;
|
|
||||||
// fetchCourseDetail(courseId);
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.course-detail {
|
.course-detail {
|
||||||
min-height: 100vh;
|
|
||||||
background-color: #f5f7fa;
|
background-color: #f5f7fa;
|
||||||
padding-bottom: 80px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-bar {
|
.nav-bar {
|
||||||
@ -195,7 +239,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
.course-image {
|
.course-image {
|
||||||
width: 120px;
|
width: 120px;
|
||||||
height: 120px;
|
height: 138px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
}
|
}
|
||||||
@ -217,6 +261,12 @@ onMounted(() => {
|
|||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.course-time {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.course-price {
|
.course-price {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #666;
|
color: #666;
|
||||||
@ -231,19 +281,62 @@ onMounted(() => {
|
|||||||
|
|
||||||
.teacher-info {
|
.teacher-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.teacher-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
.teacher-avatar {
|
.teacher-avatar {
|
||||||
width: 80px;
|
width: 60px;
|
||||||
height: 100px;
|
height: 60px;
|
||||||
border-radius: 4px;
|
border-radius: 50%;
|
||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
border: 2px solid #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.teacher-basic-info {
|
||||||
|
.teacher-name {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.teacher-title {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
background-color: #f4f7fc;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.teacher-intro-section {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.intro-title {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #555;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
padding-left: 8px;
|
||||||
|
border-left: 3px solid #2879ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.teacher-intro {
|
.teacher-intro {
|
||||||
flex: 1;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #666;
|
color: #666;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
|
background-color: #f8f9fc;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,6 +352,19 @@ onMounted(() => {
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.empty-data {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px 0;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
text {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottom-action {
|
.bottom-action {
|
||||||
|
|||||||
428
src/pages/base/course-selection/enrolled.vue
Normal file
428
src/pages/base/course-selection/enrolled.vue
Normal file
@ -0,0 +1,428 @@
|
|||||||
|
<template>
|
||||||
|
<BasicLayout>
|
||||||
|
<view class="enrolled-page">
|
||||||
|
<!-- 已报名状态提示 -->
|
||||||
|
<view class="status-card">
|
||||||
|
<view class="status-icon">
|
||||||
|
<u-icon name="checkmark" size="32" color="#3FBF72"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view class="status-text">已报名</view>
|
||||||
|
<view class="status-desc">该学生已成功报名以下兴趣课程</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 学生信息卡片 -->
|
||||||
|
<view class="info-card student-card">
|
||||||
|
<view class="card-title">学生信息</view>
|
||||||
|
<view class="divider"></view>
|
||||||
|
|
||||||
|
<view class="student-info">
|
||||||
|
<view class="student-avatar">
|
||||||
|
<image
|
||||||
|
:src="studentInfo.avatar || '/static/base/home/11222.png'"
|
||||||
|
mode="aspectFill"
|
||||||
|
></image>
|
||||||
|
</view>
|
||||||
|
<view class="student-details">
|
||||||
|
<view class="student-name">{{ studentInfo.xm }}</view>
|
||||||
|
<view class="student-class"
|
||||||
|
>{{ studentInfo.njmc }} {{ studentInfo.bjmc }}</view
|
||||||
|
>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 已报名课程信息 -->
|
||||||
|
<view class="info-card">
|
||||||
|
<view class="card-title">已报名课程</view>
|
||||||
|
<view class="divider"></view>
|
||||||
|
|
||||||
|
<view class="course-info">
|
||||||
|
<image
|
||||||
|
class="course-image"
|
||||||
|
:src="enrolledCourse.image || '/static/base/home/2211.png'"
|
||||||
|
mode="aspectFill"
|
||||||
|
></image>
|
||||||
|
<view class="course-details">
|
||||||
|
<view class="course-name">{{ enrolledCourse.title }}</view>
|
||||||
|
<view class="course-teacher"
|
||||||
|
>开课老师:{{ enrolledCourse.teacher }}</view
|
||||||
|
>
|
||||||
|
<view class="course-time">上课时间:{{ enrolledCourse.time }}</view>
|
||||||
|
<view class="course-location"
|
||||||
|
>上课地点:{{ enrolledCourse.location }}</view
|
||||||
|
>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 报名信息 -->
|
||||||
|
<view class="enrollment-info">
|
||||||
|
<view class="info-item">
|
||||||
|
<text class="info-label">报名时间:</text>
|
||||||
|
<text class="info-value">{{ enrolledCourse.enrollDate }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-item">
|
||||||
|
<text class="info-label">课程费用:</text>
|
||||||
|
<text class="info-value highlight">¥{{ enrolledCourse.fee }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-item">
|
||||||
|
<text class="info-label">支付状态:</text>
|
||||||
|
<text
|
||||||
|
class="info-value"
|
||||||
|
:class="enrolledCourse.isPaid ? 'paid' : 'unpaid'"
|
||||||
|
>
|
||||||
|
{{ enrolledCourse.isPaid ? "已支付" : "未支付" }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 温馨提示 -->
|
||||||
|
<!-- <view class="notice-card">
|
||||||
|
<view class="notice-title">
|
||||||
|
<u-icon name="info-circle" size="18" color="#2879FF"></u-icon>
|
||||||
|
<text>温馨提示</text>
|
||||||
|
</view>
|
||||||
|
<view class="notice-content">
|
||||||
|
<text>1. 课程一经报名成功,不可取消或更换;</text>
|
||||||
|
<text>2. 如有特殊情况需要请假,请提前与老师联系;</text>
|
||||||
|
<text>3. 请按时上课,迟到将影响学习效果。</text>
|
||||||
|
</view>
|
||||||
|
</view> -->
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<template #bottom>
|
||||||
|
<view class="bottom-actions" v-if="!enrolledCourse.isPaid">
|
||||||
|
<u-button text="继续支付" type="primary" @click="goPay"></u-button>
|
||||||
|
<!-- <u-button
|
||||||
|
text="返回选课"
|
||||||
|
:plain="true"
|
||||||
|
@click="goBack"
|
||||||
|
></u-button> -->
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</BasicLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, computed } from "vue";
|
||||||
|
import { useUserStore } from "@/store/modules/user";
|
||||||
|
|
||||||
|
const { getUser } = useUserStore();
|
||||||
|
|
||||||
|
// 获取路由参数
|
||||||
|
const studentId = ref("");
|
||||||
|
onMounted(() => {
|
||||||
|
const pages = getCurrentPages();
|
||||||
|
const currentPage = pages[pages.length - 1];
|
||||||
|
// @ts-ignore
|
||||||
|
const options = currentPage.$page?.options;
|
||||||
|
if (options && options.studentId) {
|
||||||
|
studentId.value = options.studentId;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 当前学生信息
|
||||||
|
const studentInfo = ref({
|
||||||
|
id: "",
|
||||||
|
xm: "加载中...",
|
||||||
|
njmc: "",
|
||||||
|
bjmc: "",
|
||||||
|
avatar: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
// 已报名课程信息
|
||||||
|
const enrolledCourse = ref({
|
||||||
|
id: "",
|
||||||
|
title: "少儿声乐",
|
||||||
|
image: "",
|
||||||
|
teacher: "张老师",
|
||||||
|
time: "每周一 16:00-17:30",
|
||||||
|
location: "艺术楼 203教室",
|
||||||
|
enrollDate: "2023-09-15 14:30:45",
|
||||||
|
fee: 420,
|
||||||
|
isPaid: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取学生信息
|
||||||
|
const fetchStudentInfo = () => {
|
||||||
|
// 在实际应用中,这里应该从学生列表中找到对应ID的学生
|
||||||
|
// 或者调用接口获取详细信息
|
||||||
|
const student = getUser.xsList.find((s: any) => s.id === studentId.value);
|
||||||
|
if (student) {
|
||||||
|
studentInfo.value = student;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 添加实际的接口调用
|
||||||
|
// const url = '/api/student/detail';
|
||||||
|
// const params = { studentId: studentId.value };
|
||||||
|
// return new Promise((resolve) => {
|
||||||
|
// // 模拟API调用
|
||||||
|
// setTimeout(() => {
|
||||||
|
// resolve();
|
||||||
|
// }, 500);
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取已报名课程信息
|
||||||
|
const fetchEnrolledCourse = () => {
|
||||||
|
// TODO: 添加实际的接口调用
|
||||||
|
// const url = '/api/course/enrolled';
|
||||||
|
// const params = { studentId: studentId.value };
|
||||||
|
// return new Promise((resolve) => {
|
||||||
|
// // 模拟API调用
|
||||||
|
// setTimeout(() => {
|
||||||
|
// resolve();
|
||||||
|
// }, 500);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// 模拟数据
|
||||||
|
setTimeout(() => {
|
||||||
|
enrolledCourse.value = {
|
||||||
|
id: "course123",
|
||||||
|
title: "少儿声乐",
|
||||||
|
image: "/static/base/home/2211.png",
|
||||||
|
teacher: "张老师",
|
||||||
|
time: "每周一 16:00-17:30",
|
||||||
|
location: "艺术楼 203教室",
|
||||||
|
enrollDate: "2023-09-15 14:30:45",
|
||||||
|
fee: 420,
|
||||||
|
isPaid: Math.random() > 0.5, // 随机生成支付状态
|
||||||
|
};
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 去支付
|
||||||
|
const goPay = () => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/base/course-selection/payment?courseId=${enrolledCourse.value.id}&studentId=${studentId.value}`,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 返回选课页面
|
||||||
|
const goBack = () => {
|
||||||
|
uni.navigateBack();
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
uni.showLoading({ title: "加载中..." });
|
||||||
|
|
||||||
|
// 获取学生信息和已报名课程信息
|
||||||
|
Promise.all([fetchStudentInfo(), fetchEnrolledCourse()]).finally(() => {
|
||||||
|
uni.hideLoading();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.enrolled-page {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-card {
|
||||||
|
background: linear-gradient(135deg, #3fbf72, #2ab559);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
color: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.status-icon {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-desc {
|
||||||
|
font-size: 14px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-card {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||||||
|
|
||||||
|
&.student-card {
|
||||||
|
background-color: #eef4ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
height: 1px;
|
||||||
|
background-color: #eee;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.student-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.student-avatar {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-right: 15px;
|
||||||
|
|
||||||
|
image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.student-details {
|
||||||
|
.student-name {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.student-class {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-info {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
.course-image {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-right: 15px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-details {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.course-name {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-teacher,
|
||||||
|
.course-time,
|
||||||
|
.course-location {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.enrollment-info {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-label {
|
||||||
|
color: #666;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
|
||||||
|
&.highlight {
|
||||||
|
color: #ff6b01;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.paid {
|
||||||
|
color: #3fbf72;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.unpaid {
|
||||||
|
color: #ff5252;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-card {
|
||||||
|
background-color: #fff9e6;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 15px;
|
||||||
|
|
||||||
|
.notice-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
text {
|
||||||
|
margin-left: 5px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-content {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
|
||||||
|
text {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-actions {
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
:deep(.u-button) {
|
||||||
|
flex: 1;
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
File diff suppressed because it is too large
Load Diff
60
src/pages/base/course-selection/notice.vue
Normal file
60
src/pages/base/course-selection/notice.vue
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<BasicLayout>
|
||||||
|
<view class="p-15">
|
||||||
|
<view class="white-bg-color p-15 r-md">
|
||||||
|
<view> 各位家长:</view>
|
||||||
|
<view class="notice-text">
|
||||||
|
随着素质教育的不断深入,学生各项素质、能力的培养越来越受到学校、家庭的重视。我校根据教育局的有关精神,继续举办兴趣班。请各位家长根据实际情况,遵照"孩子自主,家长自愿"的原则,选择兴趣班,请点击下一步确认知晓告知内容。
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<BasicSign ref="signCompRef" title="签名"></BasicSign>
|
||||||
|
</view>
|
||||||
|
<template #bottom>
|
||||||
|
<view class="white-bg-color py-5">
|
||||||
|
<view class="flex-row items-center pb-10 pt-5">
|
||||||
|
<u-button
|
||||||
|
text="下一步"
|
||||||
|
class="mx-15"
|
||||||
|
type="primary"
|
||||||
|
@click="submit"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</BasicLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { xkListApi } from "@/api/base/server";
|
||||||
|
import { useDataStore } from "@/store/modules/data";
|
||||||
|
import { useUserStore } from "@/store/modules/user";
|
||||||
|
|
||||||
|
const signCompRef = ref<any>(null);
|
||||||
|
const sign_file = ref<any>(null);
|
||||||
|
const { setData, getGlobal } = useDataStore();
|
||||||
|
async function submit() {
|
||||||
|
// 显示加载中
|
||||||
|
const data = await signCompRef.value.getSyncSignature();
|
||||||
|
sign_file.value = data.base64;
|
||||||
|
setData({
|
||||||
|
sign_file: sign_file.value,
|
||||||
|
});
|
||||||
|
if (getGlobal.type == 1) {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: "/pages/base/course-selection/index",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (getGlobal.type == 2) {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: "/pages/base/course-selection/club-selection",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.notice-text {
|
||||||
|
margin-top: 10px;
|
||||||
|
text-indent: 2em; /* 添加两个中文字符的缩进 */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
171
src/pages/base/course-selection/notopen.vue
Normal file
171
src/pages/base/course-selection/notopen.vue
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
<template>
|
||||||
|
<BasicLayout>
|
||||||
|
<view class="notopen-page">
|
||||||
|
<!-- 未开放状态图标 -->
|
||||||
|
<view class="status-icon">
|
||||||
|
<u-icon name="clock" size="80" color="#A0CFFF"></u-icon>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 状态说明 -->
|
||||||
|
<view class="status-text">
|
||||||
|
<view class="title">课程报名尚未开放</view>
|
||||||
|
<view class="subtitle">请耐心等待学校通知</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 提示信息 -->
|
||||||
|
<view class="info-card">
|
||||||
|
<view class="info-title">
|
||||||
|
<u-icon name="info-circle" size="18" color="#2879FF"></u-icon>
|
||||||
|
<text>温馨提示</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-content">
|
||||||
|
<text>1. 学校将按计划开放兴趣课程报名,敬请关注学校通知;</text>
|
||||||
|
<text>2. 为保证公平,课程报名将统一时间开放;</text>
|
||||||
|
<text>3. 开放报名后,您可以为孩子选择合适的兴趣课程;</text>
|
||||||
|
<text>4. 如有疑问,请联系班主任老师咨询详情。</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 时间提示 -->
|
||||||
|
<!-- <view class="time-info">
|
||||||
|
<view class="time-title">预计开放时间</view>
|
||||||
|
<view class="time-value">9月15日 14:00</view>
|
||||||
|
</view> -->
|
||||||
|
|
||||||
|
<!-- 课程预览图 -->
|
||||||
|
<!-- <view class="preview-container">
|
||||||
|
<image
|
||||||
|
src="/static/base/home/2211.png"
|
||||||
|
mode="aspectFill"
|
||||||
|
class="preview-image"
|
||||||
|
></image>
|
||||||
|
</view> -->
|
||||||
|
</view>
|
||||||
|
|
||||||
|
|
||||||
|
</BasicLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
|
||||||
|
// 返回首页
|
||||||
|
const goHome = () => {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: "/pages/base/home/index"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 页面加载时可以执行一些操作,例如记录用户访问日志
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.notopen-page {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
padding: 30px 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-icon {
|
||||||
|
margin-top: 50px;
|
||||||
|
width: 140px;
|
||||||
|
height: 140px;
|
||||||
|
background-color: rgba(160, 207, 255, 0.1);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-card {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #eef4ff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
|
||||||
|
.info-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
text {
|
||||||
|
margin-left: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-content {
|
||||||
|
text {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-info {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
|
||||||
|
.time-title {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-value {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #2879FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-container {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
|
||||||
|
.preview-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 150px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-actions {
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,403 +0,0 @@
|
|||||||
<template>
|
|
||||||
<BasicLayout>
|
|
||||||
<view class="page-container">
|
|
||||||
<view class="notice-box">
|
|
||||||
<text class="notice-text"
|
|
||||||
>特别提示:家中家庭成员可多人注册,可接收孩子在校情况、学业情况等。</text
|
|
||||||
>
|
|
||||||
</view>
|
|
||||||
<view
|
|
||||||
v-for="(student, index) in students"
|
|
||||||
:key="index"
|
|
||||||
class="form-section mb-15"
|
|
||||||
>
|
|
||||||
<view v-if="index > 0" class="remove-btn" @click="removeStudent(index)">
|
|
||||||
<u-icon name="minus-circle" color="#ff4d4f" size="18"></u-icon>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="avatar-section">
|
|
||||||
<view class="avatar-uploader-container-rect">
|
|
||||||
<CustomUpload
|
|
||||||
@select="(event) => afterRead(event, index)"
|
|
||||||
@close="handleAvatarClose(index)"
|
|
||||||
:sourceType="['camera', 'album']"
|
|
||||||
>
|
|
||||||
<view class="avatar-placeholder">
|
|
||||||
<view class="wh-full flex-col-center">
|
|
||||||
<svg
|
|
||||||
t="1729656215869"
|
|
||||||
class="icon"
|
|
||||||
viewBox="0 0 1024 1024"
|
|
||||||
version="1.1"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
p-id="5302"
|
|
||||||
width="32"
|
|
||||||
height="32"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M851.552 890.88 172.448 890.88c-74.592 0-135.296-60.672-135.296-135.296L37.152 370.752c0-74.624 60.672-135.328 135.296-135.328l132.16 0L302.912 195.904c0-34.624 28.192-62.816 62.816-62.816l302.016 0c29.408 0 53.312 23.904 53.312 53.312l0 49.024 130.464 0c74.592 0 135.296 60.672 135.296 135.328l0 384.832C986.816 830.208 926.144 890.88 851.552 890.88zM172.448 283.456c-48.128 0-87.296 39.168-87.296 87.328l0 384.832c0 48.128 39.168 87.296 87.296 87.296l679.104 0c48.128 0 87.296-39.168 87.296-87.296L938.848 370.752c0-48.16-39.168-87.328-87.296-87.328L716.8 283.424c-24.096 0-43.712-19.616-43.712-43.712L673.088 186.4c0-2.944-2.368-5.312-5.312-5.312l-302.016 0c-8.16 0-14.816 6.656-14.816 14.816L350.944 237.12c0 25.536-20.768 46.304-46.304 46.304L172.448 283.424zM512 755.84c-107.04 0-194.08-87.072-194.08-194.08S404.992 367.68 512 367.68s194.08 87.072 194.08 194.08S619.04 755.84 512 755.84zM512 415.68c-80.576 0-146.08 65.536-146.08 146.08S431.456 707.84 512 707.84s146.08-65.536 146.08-146.08S592.576 415.68 512 415.68zM816.8 438.016c-25.568 0-46.336-20.768-46.336-46.336s20.768-46.336 46.336-46.336 46.336 20.768 46.336 46.336S842.368 438.016 816.8 438.016zM816.8 390.016l-1.664 1.664c0 0.896 0.736 1.664 1.664 1.664L816.8 390.016z"
|
|
||||||
fill="#cdcdcd"
|
|
||||||
p-id="5303"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</CustomUpload>
|
|
||||||
</view>
|
|
||||||
<text class="avatar-upload-note">上传学生人像用于校园进出</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="student-info-form">
|
|
||||||
<u--form label-width="auto">
|
|
||||||
<u-form-item
|
|
||||||
label="姓名"
|
|
||||||
:prop="`students[${index}].name`"
|
|
||||||
required
|
|
||||||
borderBottom
|
|
||||||
>
|
|
||||||
<u--input
|
|
||||||
v-model="student.name"
|
|
||||||
placeholder="请输入子女姓名"
|
|
||||||
border="none"
|
|
||||||
inputAlign="right"
|
|
||||||
></u--input>
|
|
||||||
</u-form-item>
|
|
||||||
<u-form-item
|
|
||||||
label="身份证号"
|
|
||||||
:prop="`students[${index}].idCard`"
|
|
||||||
required
|
|
||||||
borderBottom
|
|
||||||
>
|
|
||||||
<u--input
|
|
||||||
v-model="student.idCard"
|
|
||||||
placeholder="请输入子女身份证号"
|
|
||||||
border="none"
|
|
||||||
inputAlign="right"
|
|
||||||
></u--input>
|
|
||||||
</u-form-item>
|
|
||||||
</u--form>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="add-child-btn mb-15" @click="addMoreChildren">
|
|
||||||
<u-icon name="plus" color="#416AF2" size="20"></u-icon>
|
|
||||||
<text class="add-child-btn-text">新增多孩</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<BasicForm @register="register"></BasicForm>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<template #bottom>
|
|
||||||
<view class="white-bg-color py-5">
|
|
||||||
<view class="flex-row items-center pb-10 pt-5">
|
|
||||||
<u-button text="提交" class="mx-15" type="primary" @click="submit" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
</BasicLayout>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { hideLoading, showLoading, showToast } from "@/utils/uniapp";
|
|
||||||
import { ref } from "vue";
|
|
||||||
import { attachmentUpload } from "@/api/system/upload";
|
|
||||||
import CustomUpload from "/src/components/BasicUpload/CustomUpload.vue";
|
|
||||||
|
|
||||||
import { useForm } from "@/components/BasicForm/hooks/useForm";
|
|
||||||
|
|
||||||
const [register, { getValue }] = useForm({
|
|
||||||
formsProps: { labelWidth: 100 },
|
|
||||||
schema: [
|
|
||||||
{ title: "监督人信息" },
|
|
||||||
{
|
|
||||||
field: "gsmc",
|
|
||||||
label: "与学生关系",
|
|
||||||
component: "BasicInput",
|
|
||||||
required: true,
|
|
||||||
componentProps: {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: "gsmc",
|
|
||||||
label: "姓名",
|
|
||||||
component: "BasicInput",
|
|
||||||
required: true,
|
|
||||||
componentProps: {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: "gsmc",
|
|
||||||
label: "手机号",
|
|
||||||
component: "BasicInput",
|
|
||||||
required: true,
|
|
||||||
componentProps: {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: "gsmc",
|
|
||||||
label: "工作单位",
|
|
||||||
component: "BasicInput",
|
|
||||||
required: true,
|
|
||||||
componentProps: {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: "gsmc",
|
|
||||||
label: "职务",
|
|
||||||
component: "BasicInput",
|
|
||||||
required: true,
|
|
||||||
componentProps: {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: "gsmc",
|
|
||||||
label: "家庭地址",
|
|
||||||
component: "BasicInput",
|
|
||||||
required: true,
|
|
||||||
componentProps: {},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const students = ref([
|
|
||||||
{
|
|
||||||
name: "",
|
|
||||||
idCard: "",
|
|
||||||
avatar: "",
|
|
||||||
avatarFile: null as UniNamespace.ChooseImageSuccessCallbackResult | null,
|
|
||||||
avatarServerPath: "",
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
async function afterRead(event: any, index: number) {
|
|
||||||
if (!event.tempFilePaths || event.tempFilePaths.length === 0) {
|
|
||||||
showToast({ title: "图片选择失败", icon: "none" });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const tempFilePath = event.tempFilePaths[0];
|
|
||||||
students.value[index].avatar = tempFilePath;
|
|
||||||
students.value[index].avatarFile = event;
|
|
||||||
|
|
||||||
showLoading({ title: "上传中" });
|
|
||||||
try {
|
|
||||||
const { result } = await attachmentUpload(tempFilePath);
|
|
||||||
if (result && result.length > 0 && result[0].filePath) {
|
|
||||||
students.value[index].avatarServerPath = result[0].filePath;
|
|
||||||
console.log(`Student ${index} avatar uploaded:`, result[0].filePath);
|
|
||||||
showToast({ title: "上传成功" });
|
|
||||||
} else {
|
|
||||||
showToast({ title: "上传失败,请重试", icon: "none" });
|
|
||||||
console.error("Upload result format error:", result);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
showToast({ title: "上传出错", icon: "none" });
|
|
||||||
console.error("Upload error:", error);
|
|
||||||
} finally {
|
|
||||||
hideLoading();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleAvatarClose(index: number) {
|
|
||||||
students.value[index].avatar = "";
|
|
||||||
students.value[index].avatarFile = null;
|
|
||||||
students.value[index].avatarServerPath = "";
|
|
||||||
console.log(`Student ${index} avatar removed`);
|
|
||||||
}
|
|
||||||
|
|
||||||
function addMoreChildren() {
|
|
||||||
students.value.push({
|
|
||||||
name: "",
|
|
||||||
idCard: "",
|
|
||||||
avatar: "",
|
|
||||||
avatarFile: null,
|
|
||||||
avatarServerPath: "",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeStudent(index: number) {
|
|
||||||
if (students.value.length > 1) {
|
|
||||||
students.value.splice(index, 1);
|
|
||||||
} else {
|
|
||||||
showToast({ title: "至少需要一个学生信息", icon: "none" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function submit() {
|
|
||||||
for (const student of students.value) {
|
|
||||||
if (!student.name || !student.idCard) {
|
|
||||||
showToast({ title: "请完整填写所有学生信息", icon: "none" });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const formData = await getValue();
|
|
||||||
console.log(formData);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.page-container {
|
|
||||||
padding: 15px; /* Consistent padding */
|
|
||||||
}
|
|
||||||
|
|
||||||
.notice-box {
|
|
||||||
background-color: #fff1f0; /* Slightly lighter red */
|
|
||||||
padding: 12px 18px;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notice-text {
|
|
||||||
color: #fa541c; /* Adjusted red color */
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-section {
|
|
||||||
background-color: #ffffff;
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 20px 20px 0 20px;
|
|
||||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.06);
|
|
||||||
/* Added margin-bottom directly here for spacing between sections */
|
|
||||||
margin-bottom: 5px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar-section {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 25px; /* Increased margin */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Keep avatar uploader styles relevant to CustomUpload */
|
|
||||||
/* Replace with rectangular styles */
|
|
||||||
.avatar-uploader-container-rect {
|
|
||||||
/* Assuming uni.rpx units based on class names like wi-180, he-240 */
|
|
||||||
width: 180rpx;
|
|
||||||
height: 240rpx;
|
|
||||||
margin: 0 auto 10px auto; /* mx-auto mb-10 */
|
|
||||||
border-radius: 6px; /* r-md approximation */
|
|
||||||
border: 1px solid #cccccc;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
background-color: #fafafa;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove old circular styles */
|
|
||||||
/* .avatar-uploader-container { ... } */
|
|
||||||
|
|
||||||
.avatar-placeholder {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Keep inner placeholder for centering SVG */
|
|
||||||
.avatar-placeholder-inner {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar-image {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove old hint style */
|
|
||||||
/* .avatar-upload-hint { ... } */
|
|
||||||
|
|
||||||
.avatar-upload-note {
|
|
||||||
color: #999;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.student-info-form {
|
|
||||||
margin-bottom: 20px; /* Restore original margin */
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-title {
|
|
||||||
display: block;
|
|
||||||
font-size: 16px; /* Slightly larger title */
|
|
||||||
font-weight: 600; /* Bolder */
|
|
||||||
margin-bottom: 15px; /* Space below title */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Restore remove button style if needed, or adapt */
|
|
||||||
/* Updated remove button style */
|
|
||||||
.remove-btn {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px; /* Closer to top edge */
|
|
||||||
right: 10px; /* Closer to right edge */
|
|
||||||
cursor: pointer;
|
|
||||||
z-index: 10;
|
|
||||||
/* Optional: add padding for easier clicking */
|
|
||||||
// padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-child-btn {
|
|
||||||
background-color: #ffffff;
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 15px; /* Increased padding */
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
margin-top: 10px; /* Increased margin */
|
|
||||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.06);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-child-btn-text {
|
|
||||||
color: #416af2;
|
|
||||||
margin-left: 8px;
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Adjust uview form item styles */
|
|
||||||
::v-deep .u-form-item {
|
|
||||||
margin-bottom: 0; /* Remove default margin if any */
|
|
||||||
}
|
|
||||||
|
|
||||||
::v-deep .u-form-item__body {
|
|
||||||
padding: 15px 0 !important; /* Adjusted padding */
|
|
||||||
/* Align items vertically if label wraps */
|
|
||||||
// align-items: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
::v-deep .u-form-item__body__left {
|
|
||||||
/* Allow label to take necessary width, adjust as needed */
|
|
||||||
// flex: 0 0 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::v-deep .u-form-item__body__left__text {
|
|
||||||
font-size: 15px;
|
|
||||||
color: #333;
|
|
||||||
line-height: 1.5; /* Improve line spacing if label wraps */
|
|
||||||
/* Ensure required asterisk is red and BEFORE the text */
|
|
||||||
display: flex; /* Use flex to control order */
|
|
||||||
align-items: center; /* Vertically center asterisk and text */
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: #f56c6c;
|
|
||||||
/* Order asterisk first */
|
|
||||||
order: -1;
|
|
||||||
margin-right: 4px;
|
|
||||||
/* Adjust vertical alignment if needed */
|
|
||||||
// line-height: 1;
|
|
||||||
// display: inline-block;
|
|
||||||
// vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::v-deep .u-input {
|
|
||||||
text-align: right; /* Align input text to the right */
|
|
||||||
}
|
|
||||||
|
|
||||||
::v-deep .u-border-bottom {
|
|
||||||
/* Ensure border spans full width if needed, or adjust */
|
|
||||||
// left: 0 !important;
|
|
||||||
// right: 0 !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,24 +1,62 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="wh-full">
|
<view class="wh-full">
|
||||||
<BasicLoading :isShow="isShow" bgColor="#fff" isShowTitle textColor="#000" title="启动中..." :type="1"/>
|
<BasicLoading
|
||||||
|
:isShow="isShow"
|
||||||
|
bgColor="#fff"
|
||||||
|
isShowTitle
|
||||||
|
textColor="#000"
|
||||||
|
title="启动中..."
|
||||||
|
:type="1"
|
||||||
|
/>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {onShow} from "@dcloudio/uni-app";
|
import { onLoad } from "@dcloudio/uni-app";
|
||||||
import {isTabBar} from "@/utils/uniapp";
|
import pages from "@/pages.json";
|
||||||
import pages from '@/pages.json'
|
import { useDataStore } from "@/store/modules/data";
|
||||||
|
import { useUserStore } from "@/store/modules/user";
|
||||||
|
import { checkOpenId } from "@/api/system/login";
|
||||||
|
import { isTabBar } from "@/utils/uniapp";
|
||||||
|
|
||||||
const isShow = ref(true)
|
const { setGlobal, getGlobal } = useDataStore();
|
||||||
onShow(async () => {
|
const { afterLoginAction, getToken } = useUserStore();
|
||||||
if (isTabBar()) {
|
const { setFile, getFile } = useDataStore();
|
||||||
uni.switchTab({
|
const isShow = ref(true);
|
||||||
url: '/' + (pages as any).tabBar.list[0].pagePath
|
|
||||||
})
|
function toHome(data: any) {
|
||||||
|
if (data.type == 1 || data.type == 2) {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: "/pages/base/course-selection/notice",
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
uni.reLaunch({
|
uni.reLaunch({
|
||||||
url: '/' + pages.pages[1].path
|
url: "/pages/base/home/index",
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
onLoad(async (data: any) => {
|
||||||
|
setGlobal(data);
|
||||||
|
if (!getToken) {
|
||||||
|
if (data && data.openId) {
|
||||||
|
checkOpenId({ openId: data.openId, appCode: "JZ" })
|
||||||
|
.then(async (res) => {
|
||||||
|
if (res.resultCode == 1) {
|
||||||
|
if (res.result) {
|
||||||
|
afterLoginAction(res.result);
|
||||||
|
toHome(data);
|
||||||
|
} else {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: "/pages/base/parentRegister/index",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toHome(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,20 +1,29 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="register-container p-30">
|
<BasicLayout>
|
||||||
<!-- 顶部 Logo -->
|
<view class="page-container">
|
||||||
<image
|
<view class="notice-box">
|
||||||
class="logo"
|
<text class="notice-text"
|
||||||
src="@/static/system/login/logo.png"
|
>特别提示:家中家庭成员可多人注册,可接收孩子在校情况、学业情况等。</text
|
||||||
mode="aspectFit"
|
|
||||||
></image>
|
|
||||||
|
|
||||||
<!-- 表单区域 -->
|
|
||||||
<view class="form-card">
|
|
||||||
<!-- 头像和标题 -->
|
|
||||||
<view
|
|
||||||
class="wi-180 he-240 mx-auto r-md mb-20"
|
|
||||||
style="border: 1px solid #cccccc"
|
|
||||||
>
|
>
|
||||||
<CustomUpload @select="afterRead" :sourceType="['camera']">
|
</view>
|
||||||
|
<view
|
||||||
|
v-for="(student, index) in students"
|
||||||
|
:key="index"
|
||||||
|
class="form-section mb-15"
|
||||||
|
>
|
||||||
|
<view v-if="index > 0" class="remove-btn" @click="removeStudent(index)">
|
||||||
|
<u-icon name="minus-circle" color="#ff4d4f" size="18"></u-icon>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="avatar-section">
|
||||||
|
<view class="avatar-uploader-container-rect">
|
||||||
|
<CustomUpload
|
||||||
|
@select="(event:any) => afterRead(event, index)"
|
||||||
|
@close="handleAvatarClose(index)"
|
||||||
|
:sourceType="['camera', 'album']"
|
||||||
|
:value="student.xstx"
|
||||||
|
>
|
||||||
|
<view class="avatar-placeholder">
|
||||||
<view class="wh-full flex-col-center">
|
<view class="wh-full flex-col-center">
|
||||||
<svg
|
<svg
|
||||||
t="1729656215869"
|
t="1729656215869"
|
||||||
@ -33,274 +42,401 @@
|
|||||||
></path>
|
></path>
|
||||||
</svg>
|
</svg>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
</CustomUpload>
|
</CustomUpload>
|
||||||
<!-- <text class="verify-title">身份验证</text> -->
|
</view>
|
||||||
|
<text class="avatar-upload-note">上传学生人像用于校园进出</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 输入框 -->
|
<view class="student-info-form">
|
||||||
<view class="input-group">
|
<u--form label-width="auto">
|
||||||
<view class="input-item">
|
<u-form-item
|
||||||
<text class="label"><text class="required">*</text>姓名:</text>
|
label="姓名"
|
||||||
<input
|
:prop="`students[${index}].xcxm`"
|
||||||
class="input-field"
|
required
|
||||||
type="text"
|
borderBottom
|
||||||
v-model="formData.name"
|
|
||||||
placeholder="请输入姓名"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
<view class="input-item">
|
|
||||||
<text class="label"><text class="required">*</text>手机号码:</text>
|
|
||||||
<input
|
|
||||||
class="input-field"
|
|
||||||
type="number"
|
|
||||||
v-model="formData.phone"
|
|
||||||
placeholder="请输入手机号码"
|
|
||||||
maxlength="11"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
<view class="input-item verification-code-item">
|
|
||||||
<text class="label"><text class="required">*</text>验证码:</text>
|
|
||||||
<input
|
|
||||||
class="input-field verification-code-input"
|
|
||||||
type="number"
|
|
||||||
v-model="formData.code"
|
|
||||||
placeholder="请输入验证码"
|
|
||||||
maxlength="6"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
class="get-code-btn"
|
|
||||||
:disabled="isCountingDown"
|
|
||||||
@click="handleGetCode"
|
|
||||||
>
|
>
|
||||||
{{ countdownText }}
|
<u--input
|
||||||
</button>
|
v-model="student.xcxm"
|
||||||
|
placeholder="请输入子女姓名"
|
||||||
|
border="none"
|
||||||
|
inputAlign="right"
|
||||||
|
></u--input>
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item
|
||||||
|
label="身份证号"
|
||||||
|
:prop="`students[${index}].xssfzh`"
|
||||||
|
required
|
||||||
|
borderBottom
|
||||||
|
>
|
||||||
|
<u--input
|
||||||
|
v-model="student.xssfzh"
|
||||||
|
placeholder="请输入子女身份证号"
|
||||||
|
border="none"
|
||||||
|
inputAlign="right"
|
||||||
|
></u--input>
|
||||||
|
</u-form-item>
|
||||||
|
</u--form>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="add-child-btn mb-15" @click="addMoreChildren">
|
||||||
|
<u-icon name="plus" color="#416AF2" size="20"></u-icon>
|
||||||
|
<text class="add-child-btn-text">新增多孩</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 验证按钮 -->
|
<BasicForm @register="register"></BasicForm>
|
||||||
<button class="verify-btn" @click="handleVerify">验证</button>
|
</view>
|
||||||
|
|
||||||
|
<template #bottom>
|
||||||
|
<view class="white-bg-color py-5">
|
||||||
|
<view class="flex-row items-center pb-10 pt-5">
|
||||||
|
<u-button text="提交" class="mx-15" type="primary" @click="submit" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
</template>
|
||||||
|
</BasicLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive, computed } from "vue";
|
import { hideLoading, showLoading, showToast } from "@/utils/uniapp";
|
||||||
import CustomUpload from "/src/components/BasicUpload/CustomUpload.vue";
|
import { ref } from "vue";
|
||||||
import { onUnmounted } from "vue";
|
|
||||||
import { hideLoading, showLoading } from "@/utils/uniapp";
|
|
||||||
import { attachmentUpload } from "@/api/system/upload";
|
import { attachmentUpload } from "@/api/system/upload";
|
||||||
|
import CustomUpload from "/src/components/BasicUpload/CustomUpload.vue";
|
||||||
|
|
||||||
const formData = reactive({
|
import { useForm } from "@/components/BasicForm/hooks/useForm";
|
||||||
name: "",
|
import { dicApi } from "@/api/system/dic";
|
||||||
phone: "",
|
import { loginRegisterJzApi } from "@/api/base/server";
|
||||||
code: "",
|
import { useUserStore } from "@/store/modules/user";
|
||||||
avatar_url: "",
|
import { useDataStore } from "@/store/modules/data";
|
||||||
|
|
||||||
|
const [register, { getValue }] = useForm({
|
||||||
|
formsProps: { labelWidth: 100 },
|
||||||
|
schema: [
|
||||||
|
{ title: "监督人信息" },
|
||||||
|
{
|
||||||
|
field: "jzxsgxId",
|
||||||
|
label: "与学生关系",
|
||||||
|
component: "BasicPicker",
|
||||||
|
componentProps: {
|
||||||
|
api: dicApi,
|
||||||
|
param: { pid: 1622287061 },
|
||||||
|
rangeKey: "dictionaryValue",
|
||||||
|
savaKey: "dictionaryCode",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "jzxm",
|
||||||
|
label: "家长姓名",
|
||||||
|
component: "BasicInput",
|
||||||
|
required: true,
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "jzsj",
|
||||||
|
label: "家长手机号",
|
||||||
|
component: "BasicInput",
|
||||||
|
required: true,
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "gzdw",
|
||||||
|
label: "家长工作单位",
|
||||||
|
component: "BasicInput",
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "zw",
|
||||||
|
label: "职务",
|
||||||
|
component: "BasicInput",
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "jtzz",
|
||||||
|
label: "家庭地址",
|
||||||
|
component: "BasicInput",
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const countdown = ref(60);
|
const students = ref([
|
||||||
const isCountingDown = ref(false);
|
{
|
||||||
let timer: NodeJS.Timeout | null = null;
|
xcxm: "",
|
||||||
const countdownText = computed(() => {
|
xssfzh: "",
|
||||||
return isCountingDown.value ? `${countdown.value}s后重试` : "获取验证码";
|
xstx: "",
|
||||||
});
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
const handleGetCode = () => {
|
async function afterRead(event: any, index: number) {
|
||||||
if (isCountingDown.value) {
|
if (!event.tempFilePaths || event.tempFilePaths.length === 0) {
|
||||||
|
showToast({ title: "图片选择失败", icon: "none" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!formData.phone) {
|
const tempFilePath = event.tempFilePaths[0];
|
||||||
uni.showToast({ title: "请输入手机号码", icon: "none" });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("获取验证码,手机号:", formData.phone);
|
|
||||||
|
|
||||||
isCountingDown.value = true;
|
|
||||||
countdown.value = 60; // 重置倒计时
|
|
||||||
timer = setInterval(() => {
|
|
||||||
if (countdown.value > 1) {
|
|
||||||
countdown.value--;
|
|
||||||
} else {
|
|
||||||
if (timer) clearInterval(timer);
|
|
||||||
timer = null;
|
|
||||||
isCountingDown.value = false;
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleVerify = () => {
|
|
||||||
if (
|
|
||||||
!formData.name ||
|
|
||||||
!formData.phone ||
|
|
||||||
!formData.code ||
|
|
||||||
!formData.avatar_url
|
|
||||||
) {
|
|
||||||
uni.showToast({ title: "请填写完整的验证信息", icon: "none" });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("提交验证信息:", formData);
|
|
||||||
uni.showToast({ title: "验证成功 (模拟)", icon: "success" });
|
|
||||||
};
|
|
||||||
|
|
||||||
async function afterRead(event: any) {
|
|
||||||
showLoading({ title: "上传中" });
|
showLoading({ title: "上传中" });
|
||||||
const { result } = await attachmentUpload(event.tempFilePaths[0]);
|
try {
|
||||||
|
const { result } = await attachmentUpload(tempFilePath);
|
||||||
|
if (result && result.length > 0 && result[0].filePath) {
|
||||||
|
students.value[index].xstx = result[0].filePath;
|
||||||
|
console.log(`Student ${index} avatar uploaded:`, result[0].filePath);
|
||||||
|
showToast({ title: "上传成功" });
|
||||||
|
} else {
|
||||||
|
showToast({ title: "上传失败,请重试", icon: "none" });
|
||||||
|
console.error("Upload result format error:", result);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showToast({ title: "上传出错", icon: "none" });
|
||||||
|
console.error("Upload error:", error);
|
||||||
|
} finally {
|
||||||
hideLoading();
|
hideLoading();
|
||||||
formData.avatar_url = result[0].filePath;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onUnmounted(() => {
|
function handleAvatarClose(index: number) {
|
||||||
if (timer) {
|
students.value[index].xstx = "";
|
||||||
clearInterval(timer);
|
}
|
||||||
|
|
||||||
|
function addMoreChildren() {
|
||||||
|
students.value.push({
|
||||||
|
xcxm: "",
|
||||||
|
xssfzh: "",
|
||||||
|
xstx: "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeStudent(index: number) {
|
||||||
|
if (students.value.length > 1) {
|
||||||
|
students.value.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
showToast({ title: "至少需要一个子女信息", icon: "none" });
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
function toHome() {
|
||||||
|
if (getGlobal.type == 1) {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: "/pages/base/course-selection/notice",
|
||||||
|
});
|
||||||
|
} else if (getGlobal.type == 2) {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: "/pages/base/course-selection/club-selection",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: "/pages/base/home/index",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { getGlobal } = useDataStore();
|
||||||
|
const { afterLoginAction } = useUserStore();
|
||||||
|
async function submit() {
|
||||||
|
for (const student of students.value) {
|
||||||
|
if (!student.xstx) {
|
||||||
|
showToast({ title: "请上传子女照片", icon: "none" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!student.xcxm) {
|
||||||
|
showToast({ title: "请输入子女姓名", icon: "none" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!student.xssfzh) {
|
||||||
|
showToast({ title: "请输入子女身份证号", icon: "none" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const formData = await getValue();
|
||||||
|
showLoading({ title: "提交中" });
|
||||||
|
try {
|
||||||
|
const res = await loginRegisterJzApi({
|
||||||
|
xsList: students.value,
|
||||||
|
...formData,
|
||||||
|
openId: getGlobal.openId,
|
||||||
|
appCode: "JZ",
|
||||||
|
});
|
||||||
|
hideLoading();
|
||||||
|
if (res.resultCode == 1) {
|
||||||
|
afterLoginAction(res.result);
|
||||||
|
toHome();
|
||||||
|
} else {
|
||||||
|
showToast({ title: res.message || "提交失败", icon: "none" });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style lang="scss" scoped>
|
||||||
.register-container {
|
.page-container {
|
||||||
display: flex;
|
padding: 15px; /* Consistent padding */
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
// height: 100vh; // 使用 min-height 避免内容过长时截断
|
|
||||||
min-height: 100vh;
|
|
||||||
background: url("@/static/base/bg.jpg") no-repeat;
|
|
||||||
background-size: 100% 100%;
|
|
||||||
padding: 20px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.notice-box {
|
||||||
width: 250px; // 根据实际 logo 尺寸调整
|
background-color: #fff1f0; /* Slightly lighter red */
|
||||||
height: 60px; // 根据实际 logo 尺寸调整
|
padding: 12px 18px;
|
||||||
margin-top: 40px; // 与顶部的距离
|
border-radius: 8px;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-card {
|
.notice-text {
|
||||||
|
color: #fa541c; /* Adjusted red color */
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-radius: 15px;
|
border-radius: 10px;
|
||||||
padding: 30px 25px;
|
padding: 20px 20px 0 20px;
|
||||||
box-sizing: border-box;
|
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.06);
|
||||||
width: 100%;
|
/* Added margin-bottom directly here for spacing between sections */
|
||||||
max-width: 400px; // 限制最大宽度
|
margin-bottom: 5px;
|
||||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
position: relative;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-section {
|
.avatar-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 25px;
|
margin-bottom: 25px; /* Increased margin */
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar {
|
/* Keep avatar uploader styles relevant to CustomUpload */
|
||||||
width: 70px;
|
/* Replace with rectangular styles */
|
||||||
height: 70px;
|
.avatar-uploader-container-rect {
|
||||||
border-radius: 50%;
|
/* Assuming uni.rpx units based on class names like wi-180, he-240 */
|
||||||
margin-bottom: 10px;
|
width: 180rpx;
|
||||||
background-color: #f0f0f0; // 头像占位背景色
|
height: 240rpx;
|
||||||
|
margin: 0 auto 10px auto; /* mx-auto mb-10 */
|
||||||
|
border-radius: 6px; /* r-md approximation */
|
||||||
|
border: 1px solid #cccccc;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #fafafa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.verify-title {
|
/* Remove old circular styles */
|
||||||
font-size: 16px;
|
/* .avatar-uploader-container { ... } */
|
||||||
color: #333;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group {
|
.avatar-placeholder {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 20px;
|
height: 100%;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-item {
|
/* Keep inner placeholder for centering SVG */
|
||||||
|
.avatar-placeholder-inner {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 20px;
|
justify-content: center;
|
||||||
border-bottom: 1px solid #eee; // 输入框底部线条
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.avatar-image {
|
||||||
width: 80px; // 固定标签宽度
|
width: 100%;
|
||||||
font-size: 14px;
|
height: 100%;
|
||||||
color: #666;
|
object-fit: cover;
|
||||||
flex-shrink: 0; // 防止标签被压缩
|
|
||||||
display: flex; // 使星号和文字对齐
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.required {
|
/* Remove old hint style */
|
||||||
color: red;
|
/* .avatar-upload-hint { ... } */
|
||||||
margin-right: 4px;
|
|
||||||
|
.avatar-upload-note {
|
||||||
|
color: #999;
|
||||||
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-field {
|
.student-info-form {
|
||||||
flex-grow: 1;
|
margin-bottom: 20px; /* Restore original margin */
|
||||||
font-size: 14px;
|
|
||||||
border: none; // 移除默认边框
|
|
||||||
outline: none; // 移除选中时的轮廓
|
|
||||||
padding: 5px 0; // 微调输入框内边距
|
|
||||||
color: #333;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.verification-code-item {
|
.form-title {
|
||||||
display: flex;
|
display: block;
|
||||||
align-items: center;
|
font-size: 16px; /* Slightly larger title */
|
||||||
justify-content: space-between; // 让输入框和按钮分开
|
font-weight: 600; /* Bolder */
|
||||||
|
margin-bottom: 15px; /* Space below title */
|
||||||
}
|
}
|
||||||
|
|
||||||
.verification-code-input {
|
/* Restore remove button style if needed, or adapt */
|
||||||
flex-grow: 1; // 输入框占据剩余空间
|
/* Updated remove button style */
|
||||||
margin-right: 10px; // 与按钮的间距
|
.remove-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px; /* Closer to top edge */
|
||||||
|
right: 10px; /* Closer to right edge */
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 10;
|
||||||
|
/* Optional: add padding for easier clicking */
|
||||||
|
// padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.get-code-btn {
|
.add-child-btn {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
color: #007aff; // 按钮文字颜色
|
border-radius: 10px;
|
||||||
border: 1px solid #007aff; // 按钮边框
|
padding: 15px; /* Increased padding */
|
||||||
font-size: 12px;
|
display: flex;
|
||||||
padding: 8px 10px;
|
justify-content: center;
|
||||||
border-radius: 20px;
|
align-items: center;
|
||||||
white-space: nowrap; // 防止文字换行
|
margin-top: 10px; /* Increased margin */
|
||||||
line-height: 1; // 确保文字垂直居中
|
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.06);
|
||||||
height: auto; // 自适应高度
|
cursor: pointer;
|
||||||
margin: 0; // 移除默认外边距
|
|
||||||
flex-shrink: 0; // 防止按钮被压缩
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.get-code-btn[disabled] {
|
.add-child-btn-text {
|
||||||
background-color: #f8f8f8;
|
color: #416af2;
|
||||||
color: #cccccc;
|
margin-left: 8px;
|
||||||
border-color: #cccccc;
|
font-size: 15px;
|
||||||
}
|
font-weight: 500;
|
||||||
// 移除按钮默认的边框伪元素
|
|
||||||
.get-code-btn::after {
|
|
||||||
border: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.verify-btn {
|
/* Adjust uview form item styles */
|
||||||
width: 100%;
|
::v-deep .u-form-item {
|
||||||
height: 45px;
|
margin-bottom: 0; /* Remove default margin if any */
|
||||||
line-height: 45px;
|
|
||||||
background: linear-gradient(to right, #ff8c4a, #ff5e62); // 按钮渐变色
|
|
||||||
color: #ffffff;
|
|
||||||
font-size: 16px;
|
|
||||||
border-radius: 25px;
|
|
||||||
margin-top: 10px;
|
|
||||||
border: none; // 移除默认边框
|
|
||||||
box-shadow: 0 2px 5px rgba(255, 100, 100, 0.3); // 添加阴影
|
|
||||||
}
|
|
||||||
// 移除按钮默认的边框伪元素
|
|
||||||
.verify-btn::after {
|
|
||||||
border: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 可以在这里添加 placeholder 的样式
|
::v-deep .u-form-item__body {
|
||||||
input::placeholder {
|
padding: 15px 0 !important; /* Adjusted padding */
|
||||||
color: #cccccc;
|
/* Align items vertically if label wraps */
|
||||||
font-size: 14px;
|
// align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .u-form-item__body__left {
|
||||||
|
/* Allow label to take necessary width, adjust as needed */
|
||||||
|
// flex: 0 0 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .u-form-item__body__left__text {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #333;
|
||||||
|
line-height: 1.5; /* Improve line spacing if label wraps */
|
||||||
|
/* Ensure required asterisk is red and BEFORE the text */
|
||||||
|
display: flex; /* Use flex to control order */
|
||||||
|
align-items: center; /* Vertically center asterisk and text */
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #f56c6c;
|
||||||
|
/* Order asterisk first */
|
||||||
|
order: -1;
|
||||||
|
margin-right: 4px;
|
||||||
|
/* Adjust vertical alignment if needed */
|
||||||
|
// line-height: 1;
|
||||||
|
// display: inline-block;
|
||||||
|
// vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .u-input {
|
||||||
|
text-align: right; /* Align input text to the right */
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .u-border-bottom {
|
||||||
|
/* Ensure border spans full width if needed, or adjust */
|
||||||
|
// left: 0 !important;
|
||||||
|
// right: 0 !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,23 +1,44 @@
|
|||||||
import {defineStore} from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
export const useDataStore = defineStore({
|
export const useDataStore = defineStore({
|
||||||
id: 'data',
|
id: "data",
|
||||||
state: () => ({
|
state: () => ({
|
||||||
data: {}
|
data: {},
|
||||||
|
kcData: {},
|
||||||
|
global: {},
|
||||||
|
file: {},
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
getData(): any {
|
getData(): any {
|
||||||
return this.data
|
return this.data;
|
||||||
}
|
},
|
||||||
|
getGlobal(): any {
|
||||||
|
return this.global;
|
||||||
|
},
|
||||||
|
getFile(): any {
|
||||||
|
return this.file;
|
||||||
|
},
|
||||||
|
getKcData(): any {
|
||||||
|
return this.kcData;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
setData(data: any) {
|
setData(data: any) {
|
||||||
this.data = data
|
this.data = data;
|
||||||
}
|
},
|
||||||
|
setGlobal(data: any) {
|
||||||
|
this.global = data;
|
||||||
|
},
|
||||||
|
setFile(data: any) {
|
||||||
|
this.file = data;
|
||||||
|
},
|
||||||
|
setKcData(data: any) {
|
||||||
|
this.kcData = data;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
persist: {
|
persist: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
detached: true,
|
detached: true,
|
||||||
H5Storage: localStorage
|
H5Storage: localStorage,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|||||||
@ -80,7 +80,7 @@ export const useUserStore = defineStore({
|
|||||||
if (value[AUTH_KEY]) {
|
if (value[AUTH_KEY]) {
|
||||||
this.setToken(value[AUTH_KEY])
|
this.setToken(value[AUTH_KEY])
|
||||||
}
|
}
|
||||||
authenticationApi({userId: value.userid}).then(({result}) => {
|
authenticationApi({userId: value.userId}).then(({result}) => {
|
||||||
if (result) {
|
if (result) {
|
||||||
this.setAuth(result)
|
this.setAuth(result)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user