Compare commits
52 Commits
dev
...
14263a8d76
| Author | SHA1 | Date | |
|---|---|---|---|
| 14263a8d76 | |||
| 4da9c43056 | |||
| 5d52ca004f | |||
| b31fcd34c7 | |||
| d3fef15fa3 | |||
| 0f11935749 | |||
| 312a8fcfeb | |||
| 19c48d7c71 | |||
| 5809791a56 | |||
| 9c18c3f19b | |||
| daf5ac5808 | |||
| 886b27218c | |||
| 3ac717c851 | |||
| b8773c30d7 | |||
| ed3fb5ed94 | |||
| 3565339fd7 | |||
| c951b5d1bd | |||
| 17f393df45 | |||
| 9a706c1275 | |||
|
|
73664abe4b | ||
|
|
975f3b0cd0 | ||
|
|
da78b02bbc | ||
|
|
349d17b5c4 | ||
| 99262f2ac8 | |||
| f4dfeebd31 | |||
| 328721e6e9 | |||
| 8f5d92c80d | |||
| 972284174f | |||
| e5526cc930 | |||
| d76c7eabff | |||
| cb7d68a57f | |||
| 6e02708ed3 | |||
|
|
81aae7a9ad | ||
|
|
66d1122dea | ||
| 9cf00a1449 | |||
| 0b3c32348b | |||
| 78d3bd8eb3 | |||
| 0787fc6b44 | |||
| 262f398772 | |||
| 3a1bd54878 | |||
| 2fbd8ade5b | |||
| 4ba6539850 | |||
| 33a33bb7b0 | |||
| a1b37ba39a | |||
| 8c25a3ab4f | |||
| 22cb414232 | |||
| ec01a81c64 | |||
| 1c6d5c7a15 | |||
| 233e5fecdc | |||
| e24901222d | |||
| 4c40e609c1 | |||
| ef0a65c09c |
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
11
.idea/ks-app-employment-service.iml
generated
11
.idea/ks-app-employment-service.iml
generated
@@ -1,11 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
|
||||
92
.idea/workspace.xml
generated
92
.idea/workspace.xml
generated
@@ -1,92 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="d1c3f1c8-c1f7-4e7b-8f95-b53233831e5a" name="更改" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/main.js" beforeDir="false" afterPath="$PROJECT_DIR$/main.js" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/manifest.json" beforeDir="false" afterPath="$PROJECT_DIR$/manifest.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/packageRc/pages/daiban/daiban.vue" beforeDir="false" afterPath="$PROJECT_DIR$/packageRc/pages/daiban/daiban.vue" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/packageRc/pages/index/index.vue" beforeDir="false" afterPath="$PROJECT_DIR$/packageRc/pages/index/index.vue" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/pages.json" beforeDir="false" afterPath="$PROJECT_DIR$/pages.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/pages/login/login.vue" beforeDir="false" afterPath="$PROJECT_DIR$/pages/login/login.vue" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/unpackage/dist/cache/.vite/deps/_metadata.json" beforeDir="false" afterPath="$PROJECT_DIR$/unpackage/dist/cache/.vite/deps/_metadata.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/unpackage/dist/cache/.vite/deps/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/unpackage/dist/cache/.vite/deps/package.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/unpackage/dist/dev/mp-weixin/project.config.json" beforeDir="false" afterPath="$PROJECT_DIR$/unpackage/dist/dev/mp-weixin/project.config.json" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
||||
<map>
|
||||
<entry key="$PROJECT_DIR$" value="kashi" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectColorInfo">{
|
||||
"customColor": "",
|
||||
"associatedIndex": 5
|
||||
}</component>
|
||||
<component name="ProjectId" id="34d7ujHT03QwPL2xzGtFFa7cAse" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"git-widget-placeholder": "dev",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"ts.external.directory.path": "C:\\Program Files\\JetBrains\\WebStorm 2025.1\\plugins\\javascript-plugin\\jsLanguageServicesImpl\\external",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}</component>
|
||||
<component name="SharedIndexes">
|
||||
<attachedChunks>
|
||||
<set>
|
||||
<option value="bundled-js-predefined-d6986cc7102b-f27c65a3e318-JavaScript-WS-251.23774.424" />
|
||||
</set>
|
||||
</attachedChunks>
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="默认任务">
|
||||
<changelist id="d1c3f1c8-c1f7-4e7b-8f95-b53233831e5a" name="更改" comment="" />
|
||||
<created>1761531820211</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1761531820211</updated>
|
||||
<workItem from="1761531821927" duration="3212000" />
|
||||
<workItem from="1761552146567" duration="49000" />
|
||||
<workItem from="1761553662904" duration="1204000" />
|
||||
<workItem from="1761795269754" duration="1248000" />
|
||||
<workItem from="1761819899814" duration="2588000" />
|
||||
<workItem from="1761873794088" duration="313000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
<option name="TAB_STATES">
|
||||
<map>
|
||||
<entry key="MAIN">
|
||||
<value>
|
||||
<State />
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
7
App.vue
7
App.vue
@@ -13,10 +13,10 @@ onLaunch((options) => {
|
||||
|
||||
// 先尝试从缓存恢复用户信息
|
||||
const restored = useUserStore().restoreUserInfo();
|
||||
|
||||
|
||||
// 用户信息恢复后再初始化自定义tabbar
|
||||
tabbarManager.initTabBar();
|
||||
|
||||
|
||||
if (restored) {
|
||||
// 如果成功恢复用户信息,验证token是否有效
|
||||
let token = uni.getStorageSync('token') || '';
|
||||
@@ -54,9 +54,8 @@ onHide(() => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<style>
|
||||
/*每个页面公共css */
|
||||
// @import 'uview-ui/index.scss';
|
||||
@import '@/common/animation.css';
|
||||
@import '@/common/common.css';
|
||||
/* 引入阿里图标库 */
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import request from '@/utilB/request.js'
|
||||
|
||||
const api = {}
|
||||
// 获取openid
|
||||
api.getOpenId = (params) => request.globalRequest(`/WishOrder/GetOpenId?code=${params}`,'GET', {}, "")
|
||||
|
||||
// 微信支付
|
||||
api.createWeiXinOrder = (data) => request.globalRequest(`/TenpayOrder/CreateWeiXinOrder`, 'POST', data)
|
||||
|
||||
export default api
|
||||
@@ -1,26 +0,0 @@
|
||||
import request from '@/utilB/request.js'
|
||||
|
||||
const api = {}
|
||||
|
||||
// 获取个人信息
|
||||
api.getMyWeChartUser = (params) => request.globalRequest(`/WeChartUser/GetMyWeChartUser?openId=${params}`,'GET', {})
|
||||
// 保存个人信息
|
||||
api.saveChartUser = (data) => request.globalRequest(`/WeChartUser/SaveChartUser`, 'POST', data)
|
||||
// 保存反馈信息
|
||||
api.saveWeChartUserFeedback = (data) => request.globalRequest(`/WeChartUser/SaveWeChartUserFeedback`, 'POST', data)
|
||||
// 获取出行人列表
|
||||
api.getResearchUserList = (params) => request.globalRequest(`/WeChartUser/GetResearchUserList?openId=${params}`,'GET', {})
|
||||
// 删除出行人
|
||||
api.deleteResearchUser = (params) => request.globalRequest(`/WeChartUser/DeleteResearchUser?id=${params}`,'GET', {})
|
||||
// 保存出行人
|
||||
api.saveResearchUser = (data) => request.globalRequest(`/WeChartUser/SaveResearchUser`, 'POST', data)
|
||||
|
||||
//根据openId,获取token,并判断用户是否已绑定账号
|
||||
api.getAccessTokenAndUser = (params) => request.globalRequest(`/WeChartToken/GetAccessTokenAndUser?openId=${params}`,'GET', {})
|
||||
|
||||
//获取用户token 生涯平台token
|
||||
api.queryWechartToken = (userId,schoolId,userType) => request.globalRequest(`/Auth/QueryWechartToken?userId=${userId}&schoolId=${schoolId}&userType=${userType}`,'GET', {},1,4)
|
||||
|
||||
api.sLLogin = (accessToken,openId,studentId) => request.globalRequest(`/WeChartUser/SLLogin?accessToken=${accessToken}&openId=${openId}&studentId=${studentId}`, 'POST', {})
|
||||
|
||||
export default api
|
||||
@@ -1,4 +1,4 @@
|
||||
import request from '@/utilB/request.js'
|
||||
import request from '@/utilCa/request.js'
|
||||
|
||||
const api = {}
|
||||
// 获取职业大类 中类
|
||||
@@ -1,4 +1,4 @@
|
||||
import request from '@/utilB/request.js'
|
||||
import request from '@/utilCa/request.js'
|
||||
|
||||
const api = {}
|
||||
// 获取生涯罗盘
|
||||
@@ -22,4 +22,11 @@ api.queryPlanList = (encodeId) => request.globalRequest(`/StudentProfile/QueryPl
|
||||
api.savePlanList = (data) => request.globalRequest(`/StudentProfile/SavePlanList`,'POST', data, 1)
|
||||
// 获取生涯档案(高校
|
||||
api.getGXWechatStudentProfile = () => request.globalRequest(`/StudentProfile/GetGXWechatStudentProfile`,'GET', {}, 1)
|
||||
|
||||
//获取职业路径职业列表
|
||||
api.queryCareerPath = () => request.globalRequest(`/StudentManage/QueryCareerPath`,'POST', {}, 1)
|
||||
// 获取职业详情,参数encodeId 加密id
|
||||
api.queryPathInfo = (encodeId) => request.globalRequest(`/StudentManage/QueryPathInfo?encodeId=${encodeId}`,'POST', {}, 1)
|
||||
|
||||
|
||||
export default api
|
||||
@@ -1,4 +1,4 @@
|
||||
import request from '@/utilB/request.js'
|
||||
import request from '@/utilCa/request.js'
|
||||
|
||||
const api = {}
|
||||
|
||||
@@ -1,6 +1,21 @@
|
||||
import request from '@/utilB/request.js'
|
||||
import request from '@/utilCa/request.js'
|
||||
|
||||
const api = {}
|
||||
|
||||
//根据openId,获取token,并判断用户是否已绑定账号
|
||||
api.queryKaShiToken = (userId,name) => request.globalRequest(`/KaShi/QueryKaShiToken?userId=${userId}&name=${name}&schoolId=2268`,'GET', {})
|
||||
|
||||
//根据openId,获取token,并判断用户是否已绑定账号
|
||||
api.getAccessTokenAndUser = (params) => request.globalRequest(`/WeChartToken/GetAccessTokenAndUser?openId=${params}`,'GET', {})
|
||||
|
||||
//获取用户token 生涯平台token
|
||||
api.queryWechartToken = (userId,schoolId,userType) => request.globalRequest(`/Auth/QueryWechartToken?userId=${userId}&schoolId=${schoolId}&userType=${userType}`,'GET', {},1,4)
|
||||
// 获取openid
|
||||
api.getOpenId = (params) => request.globalRequest(`/WishOrder/GetOpenId?code=${params}`,'GET', {}, "")
|
||||
|
||||
// 微信支付
|
||||
api.createWeiXinOrder = (data) => request.globalRequest(`/TenpayOrder/CreateWeiXinOrder`, 'POST', data)
|
||||
|
||||
// 用户绑定登录
|
||||
api.userBindLogin = (data) => request.globalRequest(`/user/UserBindLogin`, 'POST', data)
|
||||
//用户解绑账号或切换账号(有返回User, Token话,前端重新绑定到header上)
|
||||
514
apiRc/company/index.js
Normal file
514
apiRc/company/index.js
Normal file
@@ -0,0 +1,514 @@
|
||||
// 获取人员基本信息详情
|
||||
|
||||
|
||||
|
||||
// import { post, get } from '../../utils/request.js'
|
||||
|
||||
// export function getPersonInfo(id) {
|
||||
// return get({
|
||||
// url: `personnel/personBaseInfo/${id}`,
|
||||
// method: 'get'
|
||||
// })
|
||||
// }
|
||||
|
||||
import request from '@/utilsRc/request'
|
||||
|
||||
// 根据 userId 获取企业详情
|
||||
export function companyDetails(userId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/company/unitBaseInfo/user/${userId}`,
|
||||
})
|
||||
}
|
||||
|
||||
// 企业-推荐人员信息
|
||||
export function recommendedPerson(params) {
|
||||
return request({
|
||||
url: '/company/unitBaseInfo/recommend/person',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 人员邀请
|
||||
export function invitePerson(params) {
|
||||
return request({
|
||||
url: '/company/unitBaseInfo/invite',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取企业招聘岗位列表
|
||||
export function jobList(params) {
|
||||
return request({
|
||||
url: '/company/unitPostInfo/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 查找已投递、已推荐、已邀请的人员信息
|
||||
export function listMatch(query) {
|
||||
return request({
|
||||
url: '/company/unitBaseInfo/relevance',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 添加企业基本信息
|
||||
export function addJobBase(data) {
|
||||
return request({
|
||||
url: '/company/unitBaseInfo',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 查询部门下拉树结构
|
||||
export function deptTreeSelect() {
|
||||
return request({
|
||||
url: '/system/center/user/deptTree',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 企业发布招聘岗位
|
||||
export function addJob(data) {
|
||||
return request({
|
||||
url: '/company/unitPostInfo',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取招聘工种列表
|
||||
export function jobTypeList(params) {
|
||||
return request({
|
||||
url: '/basicdata/workType/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 企业基本信息列表
|
||||
export function jobBaseList(query) {
|
||||
return request({
|
||||
url: '/company/unitBaseInfo/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获取企业招聘岗位信息详细信息
|
||||
export function getJob(id) {
|
||||
return request({
|
||||
url: `/company/unitPostInfo/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 修改企业招聘岗位信息
|
||||
export function updateJob(data) {
|
||||
return request({
|
||||
url: '/company/unitPostInfo',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改企业基本信息
|
||||
export function updateJobBase(data) {
|
||||
return request({
|
||||
url: '/company/unitBaseInfo',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
// 查询角色详细
|
||||
export function getJobService(id) {
|
||||
return request({
|
||||
url: '/personnel/personBaseInfo/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 查询推荐人员、已推荐、已邀请 详情
|
||||
export function getUnitBaseInfo(id) {
|
||||
return request({
|
||||
url: '/manage/personDemand/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 查询工种列表
|
||||
export function listJobType(query) {
|
||||
return request({
|
||||
url: '/basicdata/workType/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 人员基本信息 - 列表
|
||||
export function personInfoList(query) {
|
||||
return request({
|
||||
url: '/personnel/personBaseInfo/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获取人员基本信息详情
|
||||
export function getPersonInfo(id) {
|
||||
return request({
|
||||
url: `/personnel/personBaseInfo/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 删除人员基本信息
|
||||
export function delPersonInfo(ids) {
|
||||
return request({
|
||||
url: '/personnel/personBaseInfo/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 删除录入人员 公用 type = 1 失业中 2 就业困难 3 离校生 4 其他人员
|
||||
export function delPersonUser(ids) {
|
||||
return request({
|
||||
url: `/personnel/personInputInfo/${ids}`,
|
||||
method: 'delete',
|
||||
})
|
||||
}
|
||||
|
||||
// 新增人员基本信息
|
||||
export function addPersonInfo(data) {
|
||||
return request({
|
||||
url: '/personnel/personBaseInfo',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改人员基本信息
|
||||
export function updatePersonInfo(data) {
|
||||
return request({
|
||||
url: '/personnel/personBaseInfo',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
//社区人员审核
|
||||
export function personInfoAudit(data) {
|
||||
return request({
|
||||
url: '/personnel/personBaseInfo/audit',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//记录查看身份证
|
||||
export function recordLookIdCard(params) {
|
||||
return request({
|
||||
url: '/personnel/personBaseInfo/recordLookIdCard',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* 失业人员 --------------------------------------------- start */
|
||||
|
||||
// 新增失业人员
|
||||
export function addPersonUnemployed(data) {
|
||||
return request({
|
||||
url: '/person/unemployment',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 失业人员修改
|
||||
export function updatePersonUnemployed(data) {
|
||||
return request({
|
||||
url: '/person/unemployment',
|
||||
method: 'put',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 失业人员列表
|
||||
export function unemployment(params) {
|
||||
return request({
|
||||
url: '/person/unemployment/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 失业人员详情
|
||||
export function unemploymentDetails(id) {
|
||||
return request({
|
||||
url: `/person/unemployment/${id}`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
// 失业人员删除
|
||||
export function unemploymentDelete(id) {
|
||||
return request({
|
||||
url: `/person/unemployment/${id}`,
|
||||
method: 'delete',
|
||||
})
|
||||
}
|
||||
|
||||
/* 失业人员 --------------------------------------------- end */
|
||||
|
||||
|
||||
/* 就业困难人员 --------------------------------------------- start */
|
||||
|
||||
// 新增就业困难
|
||||
export function addPersonDifficult(data) {
|
||||
return request({
|
||||
url: '/person/findingEmployment',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改就业困难
|
||||
export function updatePersonDifficult(data) {
|
||||
return request({
|
||||
url: '/person/findingEmployment',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 就业困难列表
|
||||
export function findingEmployment(params) {
|
||||
return request({
|
||||
url: '/person/findingEmployment/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 就业困难详情
|
||||
export function findingEmploymentDetails(id) {
|
||||
return request({
|
||||
url: `/person/findingEmployment/${id}`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
// 就业困难删除
|
||||
export function findingEmploymentDelete(id) {
|
||||
return request({
|
||||
url: `/person/findingEmployment/${id}`,
|
||||
method: 'delete',
|
||||
})
|
||||
}
|
||||
/* 就业困难人员 --------------------------------------------- end */
|
||||
|
||||
|
||||
/* 离校未就业高校生 --------------------------------------------- start */
|
||||
|
||||
// 新增离校未就业高校生
|
||||
export function addLeaveSchool(data) {
|
||||
return request({
|
||||
url: '/person/leavingSchoolInfo',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改离校未就业高校生
|
||||
export function updateLeaveSchool(data) {
|
||||
return request({
|
||||
url: '/person/leavingSchoolInfo',
|
||||
method: 'put',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 高校未就业列表
|
||||
export function leavingSchoolInfo(params) {
|
||||
return request({
|
||||
url: '/person/leavingSchoolInfo/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 高校未就业详情
|
||||
export function leavingSchoolInfoDetails(id) {
|
||||
return request({
|
||||
url: `/person/leavingSchoolInfo/${id}`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 高校未就业删除
|
||||
export function leavingSchoolInfoDelete(id) {
|
||||
return request({
|
||||
url: `/person/leavingSchoolInfo/${id}`,
|
||||
method: 'delete',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/* 离校未就业高校生 --------------------------------------------- end */
|
||||
|
||||
/* 其他人员 --------------------------------------------- start */
|
||||
|
||||
// 新增其他人员
|
||||
export function addOther(data) {
|
||||
return request({
|
||||
url: '/person/other',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 其他人员修改
|
||||
export function updateOther(data) {
|
||||
return request({
|
||||
url: '/person/other',
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 其他人员列表
|
||||
export function other(params) {
|
||||
return request({
|
||||
url: '/person/other/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 其他人员详情
|
||||
export function otherDetails(id) {
|
||||
return request({
|
||||
url: `/person/other/${id}`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
// 其他人员删除
|
||||
export function otherDelete(id) {
|
||||
return request({
|
||||
url: `/person/other/${id}`,
|
||||
method: 'delete',
|
||||
})
|
||||
}
|
||||
/* 其他人员 --------------------------------------------- end */
|
||||
|
||||
// 需求预警列表
|
||||
export function personAlertList(params) {
|
||||
return request({
|
||||
url: '/manage/personDemand/warningList',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
export function personDealList(params) {
|
||||
return request({
|
||||
url: '/manage/personDemand/dealingList',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 服务追踪 服务类型/服务id
|
||||
export function serviceTraceability({
|
||||
demandType,
|
||||
id
|
||||
}) {
|
||||
return request({
|
||||
// url: `/system/personRequirementsRecords/serviceTraceability/${demandType}/${id}`,
|
||||
url: `/timelime/timelime/fwzs/${id}`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
// 需求办结
|
||||
export function requirementCompletion(url, data) {
|
||||
return request({
|
||||
url,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
//岗位审核
|
||||
export function jobAudit(data) {
|
||||
return request({
|
||||
url: '/company/unitPostInfo/audit',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
//社群 首页未完成数
|
||||
// export function getPeopleCount() {
|
||||
// return request({
|
||||
// url: '/pc/index/getPeopleCount',
|
||||
// method: 'get',
|
||||
// })
|
||||
// }
|
||||
|
||||
//社群 首页未完成数
|
||||
export function getDemandUnfinished() {
|
||||
return request({
|
||||
url: '/pc/index/todo',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 删除企业招聘岗位信息
|
||||
export function delJob(ids) {
|
||||
return request({
|
||||
url: '/company/unitPostInfo/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 所在社区列表
|
||||
export function deptList(params) {
|
||||
return request({
|
||||
'url': `/system/center/user/deptList`,
|
||||
'method': 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 所在社区列表
|
||||
export function returnPerson(params) {
|
||||
return request({
|
||||
'url': `/personnel/personBaseInfo/returnPerson`,
|
||||
'method': 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 根据人的身份证查询人的详细信息
|
||||
export function getIdNumberInfo(params) {
|
||||
return request({
|
||||
'url': `/personnel/personBaseInfo/getIdNumberInfo`,
|
||||
'method': 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
15
apiRc/jobType/index.js
Normal file
15
apiRc/jobType/index.js
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* @Date: 2025-10-31 11:06:15
|
||||
* @LastEditors: lip
|
||||
* @LastEditTime: 2025-11-03 12:48:22
|
||||
*/
|
||||
// import { post, get } from '@/utilsRc/request'
|
||||
|
||||
import request from '@/utilsRc/request'
|
||||
export function listJobType(query) {
|
||||
return request({
|
||||
url: '/basicdata/workType/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
182
apiRc/login.js
182
apiRc/login.js
@@ -1,177 +1,53 @@
|
||||
/*
|
||||
* @Descripttion:
|
||||
* @Author: lip
|
||||
* @Date: 2023-07-27 16:01:59
|
||||
* @Date: 2025-10-31 11:06:15
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-11-03 15:51:28
|
||||
*/
|
||||
import request from '@/utilsRc/request'
|
||||
|
||||
// 登录方法
|
||||
// export function login(data) {
|
||||
// return request({
|
||||
// 'url': '/login',
|
||||
// headers: {
|
||||
// isToken: false
|
||||
// },
|
||||
// 'method': 'post',
|
||||
// data
|
||||
// })
|
||||
// }
|
||||
const userApi = {
|
||||
Login: '/login',
|
||||
Logout: '/logout',
|
||||
Register: '/register',
|
||||
// get my info
|
||||
UserInfo: '/getInfo'
|
||||
}
|
||||
// 登录接口
|
||||
export function login(data) {
|
||||
return request({
|
||||
'url': '/personnel/personBaseInfo/loginGrAndQy',
|
||||
headers: {
|
||||
isToken: false
|
||||
},
|
||||
'method': 'post',
|
||||
data
|
||||
method: 'get',
|
||||
url: '/not/login/person/zkrLogin',
|
||||
params: data,
|
||||
})
|
||||
}
|
||||
export function loginphone(data) {
|
||||
return request({
|
||||
'url': '/not/login/person/xcxLogin',
|
||||
'method': 'get',
|
||||
headers: {
|
||||
isToken: false
|
||||
},
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 注册方法
|
||||
export function register (data) {
|
||||
return request({
|
||||
'url': '/register',
|
||||
headers: {
|
||||
isToken: false
|
||||
},
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 短信登录
|
||||
export function smsLogin(data) {
|
||||
return request({
|
||||
'url': '/smsLogin',
|
||||
'method': 'post',
|
||||
'data': data
|
||||
method: 'post',
|
||||
url: '/personnel/personBaseInfo/loginGrAndQy',
|
||||
data,
|
||||
headers: {
|
||||
isToken: false
|
||||
}
|
||||
})
|
||||
}
|
||||
export function wechatLogin(data) {
|
||||
return request({
|
||||
url: '/xcxLogin',
|
||||
method: 'post',
|
||||
params: data
|
||||
url: '/personnel/personBaseInfo/loginGrAndQy',
|
||||
data,
|
||||
headers: {
|
||||
isToken: false
|
||||
}
|
||||
})
|
||||
}
|
||||
export function register(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/personnel/personBaseInfo/loginGrAndQy',
|
||||
data,
|
||||
headers: {
|
||||
isToken: false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 获取用户详细信息
|
||||
export function getInfo() {
|
||||
return request({
|
||||
'url': '/getInfo',
|
||||
'method': 'get'
|
||||
url: '/getInfo',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 退出方法
|
||||
export function logout() {
|
||||
return request({
|
||||
'url': '/logout',
|
||||
'method': 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取验证码
|
||||
export function getCodeImg() {
|
||||
return request({
|
||||
'url': '/captchaImage',
|
||||
headers: {
|
||||
isToken: false
|
||||
},
|
||||
method: 'get',
|
||||
timeout: 20000
|
||||
})
|
||||
}
|
||||
|
||||
export function registerReq(data) {
|
||||
// const data = {
|
||||
// username,
|
||||
// password,
|
||||
// code,
|
||||
// uuid,
|
||||
// userType
|
||||
// }
|
||||
return request({
|
||||
'url': '/registerBody',
|
||||
headers: {
|
||||
isToken: false
|
||||
},
|
||||
'method': 'post',
|
||||
'data': data
|
||||
})
|
||||
}
|
||||
|
||||
// 发送邮箱验证码
|
||||
export function sendMailCode(query) {
|
||||
return request({
|
||||
url: '/manage/mail/sendMailCode',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 发送短信(人才集团)
|
||||
export function sendSmsForRcjt(data) {
|
||||
return request({
|
||||
'url': '/sendSmsForRcjt',
|
||||
'method': 'post',
|
||||
'data': data
|
||||
})
|
||||
}
|
||||
// 发送登录短信
|
||||
export function sendSmsCode(data) {
|
||||
return request({
|
||||
'url': '/onlySendSms',
|
||||
'method': 'post',
|
||||
'data': data
|
||||
})
|
||||
}
|
||||
// 修改密码
|
||||
export function updateUserPwd({oldPassword, newPassword}) {
|
||||
return request({
|
||||
url: '/system/center/user/profile/updatePwd',
|
||||
method: 'put',
|
||||
params: {
|
||||
oldPassword,
|
||||
newPassword
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 找回密码 发送验证码
|
||||
export function sendSms(data) {
|
||||
return request({
|
||||
'url': '/sendSms',
|
||||
'method': 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 找回密码
|
||||
export function retrieve(data) {
|
||||
return request({
|
||||
'url': '/retrieve',
|
||||
'method': 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
}
|
||||
58
apiRc/needs/assistService.js
Normal file
58
apiRc/needs/assistService.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* @Date: 2024-09-25 11:14:29
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-11-04 08:56:51
|
||||
*/
|
||||
import request from '@/utilsRc/request'
|
||||
|
||||
// 查询援助需求列表
|
||||
export function listAssistService(query) {
|
||||
return request({
|
||||
url: '/demand/personAssistDemandInfo/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询援助需求详细
|
||||
export function getAssistService(ids) {
|
||||
return request({
|
||||
url: '/demand/personAssistDemandInfo/' + ids,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增援助需求
|
||||
export function addAssistService(data) {
|
||||
return request({
|
||||
url: '/demand/personAssistDemandInfo',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改援助需求
|
||||
export function updateAssistService(data) {
|
||||
return request({
|
||||
url: '/demand/personAssistDemandInfo',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除援助需求
|
||||
export function delAssistService(ids) {
|
||||
return request({
|
||||
url: '/manage/personDemand/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 个人援助需求办结
|
||||
export function finishAssistService(data) {
|
||||
return request({
|
||||
url: '/demand/personAssistDemandInfo/assistDone',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
58
apiRc/needs/entrepreneurshipService.js
Normal file
58
apiRc/needs/entrepreneurshipService.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* @Date: 2024-09-25 11:14:29
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-11-04 08:56:35
|
||||
*/
|
||||
import request from '@/utilsRc/request'
|
||||
|
||||
// 查询创业需求列表
|
||||
export function listEntrepreneurshipService(query) {
|
||||
return request({
|
||||
url: '/demand/personEntrepreneurshipDemandInfo/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询创业需求详细
|
||||
export function getEntrepreneurshipService(ids) {
|
||||
return request({
|
||||
url: '/demand/personEntrepreneurshipDemandInfo/' + ids,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增创业需求
|
||||
export function addEntrepreneurshipService(data) {
|
||||
return request({
|
||||
url: '/demand/personEntrepreneurshipDemandInfo',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改创业需求
|
||||
export function updateEntrepreneurshipService(data) {
|
||||
return request({
|
||||
url: '/demand/personEntrepreneurshipDemandInfo',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除创业需求
|
||||
export function delEntrepreneurshipService(ids) {
|
||||
return request({
|
||||
url: '/manage/personDemand/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 个人援助需求办结
|
||||
export function finishEntrepreneurshipService(data) {
|
||||
return request({
|
||||
url: '/demand/personEntrepreneurshipDemandInfo/entrepreneurshipDone',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
57
apiRc/needs/jobService.js
Normal file
57
apiRc/needs/jobService.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* @Date: 2025-04-07 14:23:47
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-11-04 08:56:39
|
||||
*/
|
||||
import request from '@/utilsRc/request'
|
||||
|
||||
// 查询求职需求列表
|
||||
export function listJobService(query) {
|
||||
return request({
|
||||
url: '/manage/personDemand/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询求职需求详细
|
||||
export function getJobService(ids) {
|
||||
return request({
|
||||
url: '/manage/personDemand/' + ids,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增求职需求
|
||||
export function addJobService(data) {
|
||||
return request({
|
||||
url: '/manage/personDemand',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改求职需求
|
||||
export function updateJobService(data) {
|
||||
return request({
|
||||
url: '/manage/personDemand',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除求职需求
|
||||
export function delJobService(ids) {
|
||||
return request({
|
||||
url: '/manage/personDemand/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
//查询服务次数
|
||||
export function serviceTraceability(userId) {
|
||||
return request({
|
||||
url: '/timelime/timelime/getFwcs/' + userId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
58
apiRc/needs/otherService.js
Normal file
58
apiRc/needs/otherService.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* @Date: 2024-09-25 11:14:29
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-11-04 08:56:42
|
||||
*/
|
||||
import request from '@/utilsRc/request'
|
||||
|
||||
// 查询其他需求列表
|
||||
export function listOtherService(query) {
|
||||
return request({
|
||||
url: '/demand/personOtherDemandInfo/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询其他需求详细
|
||||
export function getOtherService(ids) {
|
||||
return request({
|
||||
url: '/demand/personOtherDemandInfo/' + ids,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增其他需求
|
||||
export function addOtherService(data) {
|
||||
return request({
|
||||
url: '/demand/personOtherDemandInfo',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改其他需求
|
||||
export function updateOtherService(data) {
|
||||
return request({
|
||||
url: '/demand/personOtherDemandInfo',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除其他需求
|
||||
export function delOtherService(ids) {
|
||||
return request({
|
||||
url: '/manage/personDemand/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 个人援助需求办结
|
||||
export function finishOtherService(data) {
|
||||
return request({
|
||||
url: '/demand/personOtherDemandInfo/otherDemandDone',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
34
apiRc/needs/person.js
Normal file
34
apiRc/needs/person.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* @Date: 2025-10-31 11:06:15
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-11-05 15:33:21
|
||||
*/
|
||||
// 人员接口
|
||||
// import { post, get } from '@/utilsRc/request'
|
||||
import request from '@/utilsRc/request'
|
||||
export function getPersonBase(params) {
|
||||
return request({
|
||||
url: '/personnel/personBaseInfo/list',
|
||||
method: 'get',
|
||||
|
||||
params
|
||||
})
|
||||
}
|
||||
export function getPersonList(params) {
|
||||
return request({
|
||||
url: '/personnel/personBaseInfo/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 新增角色
|
||||
export function addInvestigate(data) {
|
||||
return request({
|
||||
// url: '//process/processInterview',
|
||||
url: '/timelime/timelime',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
52
apiRc/needs/personDemand.js
Normal file
52
apiRc/needs/personDemand.js
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* @Date: 2025-11-03 08:48:44
|
||||
* @LastEditors: lip
|
||||
* @LastEditTime: 2025-11-03 12:48:41
|
||||
*/
|
||||
// 查询个人需求信息列表
|
||||
// import { post, get } from '@/utilsRc/request'
|
||||
import request from '@/utilsRc/request'
|
||||
export function listPersonDemand(query) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/manage/personDemand/list',
|
||||
|
||||
params: query
|
||||
})
|
||||
}
|
||||
export function delPersonDemand(id) {
|
||||
return request({
|
||||
url: '/manage/personDemand/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 查询个人需求信息详细
|
||||
export function getPersonDemand(id) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/manage/personDemand/' + id,
|
||||
})
|
||||
}
|
||||
|
||||
// 新增个人需求信息
|
||||
export function addPersonDemand(data) {
|
||||
// 确保传递数据前进行日志输出
|
||||
console.log('addPersonDemand函数接收到的数据:', data);
|
||||
return request({
|
||||
url: '/manage/personDemand',
|
||||
method: 'post', // 修改为大写POST,确保请求参数正确传递
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改个人需求信息
|
||||
export function updatePersonDemand(data) {
|
||||
return request({
|
||||
url: '/manage/personDemand',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
49
apiRc/needs/trainService.js
Normal file
49
apiRc/needs/trainService.js
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* @Date: 2024-09-25 11:14:29
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-11-04 08:56:47
|
||||
*/
|
||||
import request from '@/utilsRc/request'
|
||||
|
||||
// 查询培训需求列表
|
||||
export function listTrainService(query) {
|
||||
return request({
|
||||
url: '/demand/personTrainDemandInfo/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询培训需求详细
|
||||
export function getTrainService(ids) {
|
||||
return request({
|
||||
url: '/demand/personTrainDemandInfo/' + ids,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增培训需求
|
||||
export function addTrainService(data) {
|
||||
return request({
|
||||
url: '/demand/personTrainDemandInfo',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改培训需求
|
||||
export function updateTrainService(data) {
|
||||
return request({
|
||||
url: '/demand/personTrainDemandInfo',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除培训需求
|
||||
export function delTrainService(ids) {
|
||||
return request({
|
||||
url: '/manage/personDemand/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
56
apiRc/personinfo/index.js
Normal file
56
apiRc/personinfo/index.js
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* @Descripttion:
|
||||
* @Author: lip
|
||||
* @Date: 2025-11-03 12:35:56
|
||||
* @LastEditors: shirlwang
|
||||
*/
|
||||
// import { post, get } from '../../utils/request.js'
|
||||
import request from '@/utilsRc/request'
|
||||
|
||||
// 登录方法
|
||||
export function personInfoList(data) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/personnel/personBaseInfo/list',
|
||||
params: data,
|
||||
})
|
||||
}
|
||||
// 需求预警列表
|
||||
export function personAlertList(params) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/manage/personDemand/warningList',
|
||||
|
||||
params
|
||||
})
|
||||
}
|
||||
//经办人数据获取
|
||||
export function getJbrInfo() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/system/center/user/selectHxjbr`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
export function getPersonBase() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/system/center/user/selectHxjbr`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
export function returnPerson(params) {
|
||||
return request({
|
||||
method: 'get',
|
||||
'url': `/personnel/personBaseInfo/returnPerson`,
|
||||
|
||||
params
|
||||
})
|
||||
}
|
||||
export function getStatistic(params) {
|
||||
return request({
|
||||
method: 'get',
|
||||
'url': `/pc/index/fwqkfx`,
|
||||
params
|
||||
})
|
||||
}
|
||||
50
apiRc/service/investigate.js
Normal file
50
apiRc/service/investigate.js
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* @Date: 2024-09-25 11:14:29
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-11-04 08:56:56
|
||||
*/
|
||||
import request from '@/utilsRc/request'
|
||||
|
||||
// 查询角色列表
|
||||
export function listInvestigate(query) {
|
||||
return request({
|
||||
url: '/process/processInterview/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询角色详细
|
||||
export function getInvestigate(ids) {
|
||||
return request({
|
||||
url: '/process/processInterview/' + ids,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增角色
|
||||
export function addInvestigate(data) {
|
||||
return request({
|
||||
// url: '/process/processInterview',
|
||||
url: '/timelime/timelime',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改角色
|
||||
export function updateInvestigate(data) {
|
||||
return request({
|
||||
url: '/process/processInterview',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除角色
|
||||
export function delInvestigate(ids) {
|
||||
return request({
|
||||
url: '/process/processInterview/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
86
apiRc/service/jobRecommend.js
Normal file
86
apiRc/service/jobRecommend.js
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* @Date: 2024-09-25 11:14:29
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-11-04 08:56:59
|
||||
*/
|
||||
import request from '@/utilsRc/request'
|
||||
|
||||
// 查询角色列表
|
||||
export function listJobRecommend(query) {
|
||||
return request({
|
||||
url: '/process/processJobRecommend/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
// 查询角色列表
|
||||
export function getWorkListReq(query) {
|
||||
return request({
|
||||
// url: '/personnel/personBaseInfo/postRecommend',
|
||||
url: '/company/unitPostInfo/postElectedList',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询角色详细
|
||||
export function getJobRecommend(ids) {
|
||||
return request({
|
||||
url: '/process/processJobRecommend/' + ids,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增角色
|
||||
export function addJobRecommend(data) {
|
||||
return request({
|
||||
url: '/process/processJobRecommend',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
//岗位推荐保存和办结
|
||||
export function saveJobRecommend(data) {
|
||||
return request({
|
||||
url: '/process/processJobRecommend/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改角色
|
||||
export function updateJobRecommend(data) {
|
||||
return request({
|
||||
url: '/process/processJobRecommend',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除角色
|
||||
export function delJobRecommend(ids) {
|
||||
return request({
|
||||
url: '/process/processJobRecommend/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取绑定的职位
|
||||
export function getAddedJobs(params) {
|
||||
return request({
|
||||
// url: '/company/postDeliverInfo/list',
|
||||
url: '/company/unitPostInfo/no/permission/list',
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
// // 获取推荐岗位
|
||||
// export function getAddedJobs(params) {
|
||||
// return request({
|
||||
// url: '/personnel/personBaseInfo/postRecommend',
|
||||
// method: 'get',
|
||||
// params,
|
||||
// })
|
||||
// }
|
||||
49
apiRc/service/jobTrack.js
Normal file
49
apiRc/service/jobTrack.js
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* @Date: 2024-09-25 11:14:29
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-11-04 08:57:02
|
||||
*/
|
||||
import request from '@/utilsRc/request'
|
||||
|
||||
// 查询角色列表
|
||||
export function listJobTrack(query) {
|
||||
return request({
|
||||
url: '/process/processEmploymentTracking/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询角色详细
|
||||
export function getJobTrack(ids) {
|
||||
return request({
|
||||
url: '/process/processEmploymentTracking/' + ids,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增角色
|
||||
export function addJobTrack(data) {
|
||||
return request({
|
||||
url: '/process/processEmploymentTracking',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改角色
|
||||
export function updateJobTrack(data) {
|
||||
return request({
|
||||
url: '/process/processEmploymentTracking',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除角色
|
||||
export function delJobTrack(ids) {
|
||||
return request({
|
||||
url: '/process/processEmploymentTracking/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
49
apiRc/service/policyConsultation.js
Normal file
49
apiRc/service/policyConsultation.js
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* @Date: 2024-09-25 11:14:29
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-11-04 08:57:05
|
||||
*/
|
||||
import request from '@/utilsRc/request'
|
||||
|
||||
// 查询角色列表
|
||||
export function listPolicyConsultation(query) {
|
||||
return request({
|
||||
url: '/process/processPolicyConsult/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询角色详细
|
||||
export function getPolicyConsultation(ids) {
|
||||
return request({
|
||||
url: '/process/processPolicyConsult/' + ids,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增角色
|
||||
export function addPolicyConsultation(data) {
|
||||
return request({
|
||||
url: '/process/processPolicyConsult',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改角色
|
||||
export function updatePolicyConsultation(data) {
|
||||
return request({
|
||||
url: '/process/processPolicyConsult',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除角色
|
||||
export function delPolicyConsultation(ids) {
|
||||
return request({
|
||||
url: '/process/processPolicyConsult/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
49
apiRc/service/skillTrain.js
Normal file
49
apiRc/service/skillTrain.js
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* @Date: 2024-09-25 11:14:29
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-11-04 08:57:09
|
||||
*/
|
||||
import request from '@/utilsRc/request'
|
||||
|
||||
// 查询角色列表
|
||||
export function listSkillTrain(query) {
|
||||
return request({
|
||||
url: '/process/processSkillTraining/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询角色详细
|
||||
export function getSkillTrain(ids) {
|
||||
return request({
|
||||
url: '/process/processSkillTraining/' + ids,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增角色
|
||||
export function addSkillTrain(data) {
|
||||
return request({
|
||||
url: '/process/processSkillTraining',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改角色
|
||||
export function updateSkillTrain(data) {
|
||||
return request({
|
||||
url: '/process/processSkillTraining',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除角色
|
||||
export function delSkillTrain(ids) {
|
||||
return request({
|
||||
url: '/process/processSkillTraining/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* @Date: 2025-10-31 15:06:34
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-11-03 12:20:28
|
||||
*/
|
||||
import request from '@/utilsRc/request'
|
||||
// 查询字典数据列表
|
||||
export function listData (query) {
|
||||
@@ -23,6 +28,13 @@ export function getDicts (dictType) {
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 根据字典类型查询字典数据信息
|
||||
export function getDict (dictType) {
|
||||
return request({
|
||||
url: '/system/dict/data/type/' + dictType,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增字典数据
|
||||
export function addData (data) {
|
||||
|
||||
26
apiRc/timeLine/index.js
Normal file
26
apiRc/timeLine/index.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import request from '@/utilsRc/request'
|
||||
|
||||
// 查询时间轴列表
|
||||
export function timelineList(params) {
|
||||
return request({
|
||||
url: '/timelime/timelime/timeline',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 查询时间轴详情列表
|
||||
export function timeList(params) {
|
||||
return request({
|
||||
url: '/timelime/timelime/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
//获取时间轴详细信息
|
||||
export function timeDetails(id) {
|
||||
return request({
|
||||
url: '/timelime/timelime/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -50,7 +50,7 @@ const prePage = () => {
|
||||
return prePage.$vm;
|
||||
}
|
||||
|
||||
|
||||
export const urls ='http://10.110.145.145/images/train/'
|
||||
|
||||
/**
|
||||
* 页面跳转封装,支持 query 参数传递和返回回调
|
||||
@@ -894,6 +894,7 @@ export const $api = {
|
||||
|
||||
export default {
|
||||
$api,
|
||||
urls,
|
||||
navTo,
|
||||
navBack,
|
||||
cloneDeep,
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
<template>
|
||||
<view class="upload-container">
|
||||
<u-upload :disabled="disabled" :width="width" :height="height" :fileList="internalFileList" :name="name" :multiple="multiple"
|
||||
:maxCount="maxCount" @afterRead="handleAfterRead" @delete="handleRemove">
|
||||
</u-upload>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import {
|
||||
// uploadImg
|
||||
// } from '@/api/company'
|
||||
import config from '@/config'
|
||||
//import {
|
||||
// getToken
|
||||
//} from '@/utils/auth'
|
||||
export default {
|
||||
props: {
|
||||
maxSize: {
|
||||
type: Number,
|
||||
default: 5, // 最大文件大小(MB)
|
||||
},
|
||||
allowedFormats: {
|
||||
type: Array,
|
||||
default: () => [], // 允许的文件格式
|
||||
},
|
||||
maxImageSize: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
width: 2048,
|
||||
height: 2048
|
||||
}), // 图片最大宽度和高度
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '100rpx', // 默认宽度
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '100rpx', // 默认高度
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: 'file', // 默认name字段
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false, // 是否允许多选,默认不允许
|
||||
},
|
||||
maxCount: {
|
||||
type: Number,
|
||||
default: 1, // 默认最大上传数量为1
|
||||
},
|
||||
fileList: {
|
||||
type: Array,
|
||||
default: () => [], // 默认的文件列表为空
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
internalFileList: [...this.fileList], // 内部的文件列表,确保与父组件的同步
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
// 监听 fileList 的变化,确保内外部数据同步
|
||||
fileList(newVal) {
|
||||
this.internalFileList = [...newVal];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 新增图片
|
||||
async handleAfterRead(event) {
|
||||
let lists = [].concat(event.file);
|
||||
let fileListLen = this.internalFileList.length;
|
||||
lists.map((item) => {
|
||||
this.internalFileList.push({
|
||||
...item,
|
||||
status: "uploading",
|
||||
message: "上传中",
|
||||
});
|
||||
});
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
if (this.allowedFormats.length > 0) {
|
||||
let fileType = lists[i].name.split('.').pop().toLowerCase();
|
||||
if (!this.allowedFormats.includes(fileType)) {
|
||||
// this.$emit('error', '不支持的文件格式');
|
||||
uni.showToast({
|
||||
title: '不支持的文件格式',
|
||||
icon: 'none',
|
||||
});
|
||||
this.internalFileList.splice(fileListLen, 1);
|
||||
this.$emit('update', this.internalFileList); // 通知父组件文件列表更新
|
||||
return;
|
||||
}
|
||||
}
|
||||
const result = await this.uploadFilePromise(lists[i].url);
|
||||
let item = this.internalFileList[fileListLen];
|
||||
this.internalFileList.splice(
|
||||
fileListLen,
|
||||
1,
|
||||
Object.assign(item, {
|
||||
status: "success",
|
||||
message: "",
|
||||
data: result,
|
||||
})
|
||||
);
|
||||
fileListLen++;
|
||||
this.$emit('update', this.internalFileList); // 通知父组件文件列表更新
|
||||
}
|
||||
},
|
||||
uploadFilePromise(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: config.baseUrl + '/system/oss/upload',
|
||||
filePath: url,
|
||||
name: "file",
|
||||
header: {
|
||||
Authorization: "Bearer " + getToken(),
|
||||
},
|
||||
success: (uploadFileRes) => {
|
||||
let res = JSON.parse(uploadFileRes.data);
|
||||
resolve(res.data);
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log(err);
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
handleRemove({file, index}) {
|
||||
this.internalFileList.splice(index, 1); // 从文件列表中移除指定文件
|
||||
this.$emit('update', this.internalFileList); // 通知父组件文件列表更新
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.upload-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.upload-slot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px dashed #ccc;
|
||||
border-radius: 4px;
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
639
components/jobfair/signDialog.vue
Normal file
639
components/jobfair/signDialog.vue
Normal file
@@ -0,0 +1,639 @@
|
||||
<template>
|
||||
<view class="job-dialog">
|
||||
<view class="header-title">
|
||||
<image :src="`${imgBaseUrl}/jobfair/xb.png`" mode=""></image>
|
||||
<text>招聘会报名</text>
|
||||
</view>
|
||||
<view class="dialog-content">
|
||||
<view class="detail-item" v-if="type == 2">
|
||||
<view class="gw-label">选择展区展位:</view>
|
||||
<!-- 展位状态说明 -->
|
||||
<view class="status-description">
|
||||
<view class="status-title">
|
||||
<text>展位状态说明:</text>
|
||||
</view>
|
||||
<view class="status-item">
|
||||
<view class="status-color available"></view>
|
||||
<text class="status-text">未被占用</text>
|
||||
</view>
|
||||
<view class="status-item">
|
||||
<view class="status-color occupied"></view>
|
||||
<text class="status-text">已被占用</text>
|
||||
</view>
|
||||
<view class="status-item">
|
||||
<view class="status-color pending"></view>
|
||||
<text class="status-text">待审核占用</text>
|
||||
</view>
|
||||
<view class="status-item">
|
||||
<view class="status-color selected"></view>
|
||||
<text class="status-text">当前选中</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="gw-value">
|
||||
<view class="cd-detail" v-for="(item, index) in areaAndBoothList" :key="index">
|
||||
<view class="cd-name">{{ item.jobFairAreaName }}</view>
|
||||
<view class="cd-con">
|
||||
<view class="cd-con-item" :class="getBoothStatusClass(booth)"
|
||||
v-for="(booth, boothIndex) in item.boothList" :key="boothIndex"
|
||||
@click="selectBooth(booth, item.jobFairAreaId)">
|
||||
<text>{{ booth.jobFairBoothName }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<view class="gw-label">请选择招聘岗位:</view>
|
||||
<view class="gw-value">
|
||||
<view class="checkbox-group">
|
||||
<view class="checkbox-item job-item" v-for="(item, index) in jobList" :key="index"
|
||||
:class="{ 'checked': checkList.includes(item) }" @click="toggleJobSelection(item)">
|
||||
<view class="item-checkbox">
|
||||
<view class="checkbox-icon" :class="{ 'checked': checkList.includes(item) }">
|
||||
<text v-if="checkList.includes(item)">✓</text>
|
||||
</view>
|
||||
<view class="job-info">
|
||||
<view class="job-name">{{ item.jobTitle }}</view>
|
||||
<view class="salary">{{ item.salaryRange }}元/月</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<view class="gw-label">请上传招聘海报:</view>
|
||||
<view class="gw-value">
|
||||
<view v-if="imageUrl">
|
||||
<image v-if="imageUrl" :src="publicUrl + '/file/file/minio' + imageUrl" class="avatar"
|
||||
mode="aspectFit" />
|
||||
<button type="warn" class="del-icon" @click="imageUrl = ''" size="mini">删除</button>
|
||||
</view>
|
||||
<view v-else>
|
||||
<button @click="chooseImage" class="avatar-uploader transparent-btn" type="default">
|
||||
<view class="avatar-uploader-icon">+</view>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="btn-box">
|
||||
<button style="background: #409EFF;color: #fff;" @click="submitForm">提交</button>
|
||||
<button type="default" @click="closeDialog">取消</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import config from "@/config.js"
|
||||
import {
|
||||
ref,
|
||||
reactive,
|
||||
onMounted,
|
||||
nextTick,
|
||||
watch,
|
||||
inject
|
||||
} from 'vue';
|
||||
|
||||
const emit = defineEmits(['closePopup']);
|
||||
import {
|
||||
createRequest
|
||||
} from '@/utils/request.js';
|
||||
const {
|
||||
$api
|
||||
} = inject('globalFunction');
|
||||
|
||||
// 定义props
|
||||
const props = defineProps({
|
||||
// 招聘会类型1线上 2线下
|
||||
signType: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
// 报名角色 ent企业 person个人
|
||||
signRole: {
|
||||
type: String,
|
||||
default: 'ent'
|
||||
},
|
||||
// 招聘会id
|
||||
jobFairId: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
|
||||
// 监听props变化
|
||||
watch(() => props.signType, (newVal) => {
|
||||
type.value = newVal;
|
||||
});
|
||||
|
||||
// 响应式数据
|
||||
const checkList = ref([]);
|
||||
const imageUrl = ref('');
|
||||
const type = ref('');
|
||||
const id = ref('');
|
||||
const jobList = ref([]);
|
||||
const userId = ref('');
|
||||
const areaAndBoothList = ref([]);
|
||||
const jobFairAreaId = ref(null);
|
||||
const jobFairBoothId = ref(null);
|
||||
const avatarUploader = ref(null);
|
||||
|
||||
// 配置
|
||||
const publicUrl = config.LCBaseUrl;
|
||||
const imgBaseUrl = config.imgBaseUrl
|
||||
const uploadUrl = config.LCBaseUrl + "/file/file/upload";
|
||||
|
||||
// 方法
|
||||
const selectBooth = (booth, jobFairAreaIdVal) => {
|
||||
if (booth.status == 0) {
|
||||
jobFairBoothId.value = booth.jobFairBoothId;
|
||||
jobFairAreaId.value = jobFairAreaIdVal;
|
||||
}
|
||||
};
|
||||
|
||||
const submitForm = async () => {
|
||||
if (type.value == "2") {
|
||||
if (!jobFairBoothId.value || !jobFairAreaId.value) {
|
||||
uni.showToast({
|
||||
title: '请选择展区展位',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (checkList.value.length === 0) {
|
||||
uni.showToast({
|
||||
title: '请选择招聘岗位',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!imageUrl.value) {
|
||||
uni.showToast({
|
||||
title: '请上传招聘海报',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
$api.myRequest("/system/user/login/user/info", {}, "GET", 10100, {
|
||||
Authorization: `Bearer ${uni.getStorageSync("Padmin-Token")}`
|
||||
}).then((userInfo) => {
|
||||
let data = {}
|
||||
if (type.value == "2") {
|
||||
data = {
|
||||
jobFairId: id.value,
|
||||
enterpriseId: userInfo.info.userId,
|
||||
jobInfoList: checkList.value,
|
||||
poster: imageUrl.value,
|
||||
jobFairAreaId: jobFairAreaId.value,
|
||||
jobFairBoothId: jobFairBoothId.value,
|
||||
code: userInfo.info.entCreditCode
|
||||
};
|
||||
} else {
|
||||
data = {
|
||||
jobFairId: id.value,
|
||||
enterpriseId: userInfo.info.userId,
|
||||
jobInfoList: checkList.value,
|
||||
poster: imageUrl.value,
|
||||
code: userInfo.info.entCreditCode
|
||||
};
|
||||
}
|
||||
$api.myRequest("/jobfair/public/job-fair-sign-up-enterprise/sign-up", data, "post", 9100, {
|
||||
Authorization: `Bearer ${uni.getStorageSync("Padmin-Token")}`
|
||||
}).then((res) => {
|
||||
if (res.code === 200) {
|
||||
uni.showToast({
|
||||
title: '报名成功',
|
||||
icon: 'success'
|
||||
});
|
||||
closeDialog();
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.msg || '报名失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
const closeDialog = () => {
|
||||
checkList.value = [];
|
||||
imageUrl.value = '';
|
||||
jobFairBoothId.value = null;
|
||||
jobFairAreaId.value = null;
|
||||
emit('closePopup')
|
||||
};
|
||||
|
||||
const handleAvatarSuccess = (response) => {
|
||||
imageUrl.value = response.data.url;
|
||||
uni.showToast({
|
||||
title: '海报上传成功',
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
|
||||
const showDialog = (dialogType, dialogId) => {
|
||||
type.value = dialogType;
|
||||
id.value = dialogId;
|
||||
nextTick(() => {
|
||||
getJobList();
|
||||
if (type.value === "2") {
|
||||
getAreaAndBoothInfo();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 展区展位列表
|
||||
const getAreaAndBoothInfo = () => {
|
||||
const data = {
|
||||
jobFairId: props.jobFairId,
|
||||
}
|
||||
$api.myRequest("/jobfair/public/jobfair/area-and-booth-info-by-job-fair-id", data, "GET", 9100, {
|
||||
Authorization: `Bearer ${uni.getStorageSync("Padmin-Token")}`
|
||||
}).then((resData) => {
|
||||
areaAndBoothList.value = resData.data || [];
|
||||
});
|
||||
};
|
||||
|
||||
// 岗位列表
|
||||
const getJobList = () => {
|
||||
$api.myRequest("/system/user/login/user/info", {}, "GET", 10100, {
|
||||
Authorization: `Bearer ${uni.getStorageSync("Padmin-Token")}`
|
||||
}).then((userInfo) => {
|
||||
const data = {
|
||||
jobFairId: id.value,
|
||||
enterpriseId: userInfo.info.userId,
|
||||
pageNum: 1,
|
||||
pageSize: 1000,
|
||||
code: userInfo.info.entCreditCode
|
||||
}
|
||||
$api.myRequest("/jobfair/public/job-info/list", data, "GET", 9100, {
|
||||
Authorization: `Bearer ${uni.getStorageSync("Padmin-Token")}`
|
||||
}).then((resData) => {
|
||||
jobList.value = resData.data.list || [];
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const getBoothStatusClass = (booth) => {
|
||||
const s = booth.status || 0;
|
||||
if (s == 1) return "cd-con-item-checked";
|
||||
if (s == 2) return "cd-con-item-review";
|
||||
if (jobFairBoothId.value && jobFairBoothId.value == booth.jobFairBoothId)
|
||||
return "cd-con-item-mychecked";
|
||||
return "";
|
||||
};
|
||||
|
||||
// 选择图片
|
||||
const chooseImage = () => {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['original', 'compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
const tempFilePath = res.tempFilePaths[0];
|
||||
uploadImage(tempFilePath);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 上传图片
|
||||
const uploadImage = (tempFilePath) => {
|
||||
uni.uploadFile({
|
||||
url: uploadUrl,
|
||||
filePath: tempFilePath,
|
||||
name: 'file',
|
||||
success: (uploadFileRes) => {
|
||||
try {
|
||||
const response = JSON.parse(uploadFileRes.data);
|
||||
handleAvatarSuccess(response);
|
||||
} catch (e) {
|
||||
uni.showToast({
|
||||
title: '上传失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('上传失败:', err);
|
||||
uni.showToast({
|
||||
title: '上传失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 切换岗位选择
|
||||
const toggleJobSelection = (item) => {
|
||||
const index = checkList.value.indexOf(item);
|
||||
if (index > -1) {
|
||||
checkList.value.splice(index, 1);
|
||||
} else {
|
||||
checkList.value.push(item);
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
showDialog
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
type.value = props.signType;
|
||||
if (props.jobFairId) {
|
||||
id.value = props.jobFairId;
|
||||
getJobList();
|
||||
if (props.signType == 2) {
|
||||
getAreaAndBoothInfo();
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// 监听jobFairId变化
|
||||
watch(() => props.jobFairId, (newVal) => {
|
||||
if (newVal) {
|
||||
id.value = newVal;
|
||||
getJobList();
|
||||
if (type.value === 2) {
|
||||
getAreaAndBoothInfo();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.del-icon {
|
||||
margin-left: 30rpx;
|
||||
}
|
||||
|
||||
.btn-box {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.btn-box button {
|
||||
padding: 0 80rpx;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
}
|
||||
|
||||
.avatar-uploader {
|
||||
border: 2rpx solid #0983ff;
|
||||
border-radius: 12rpx;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 400rpx;
|
||||
height: 200rpx;
|
||||
}
|
||||
|
||||
.avatar-uploader-icon {
|
||||
font-size: 56rpx;
|
||||
color: #007AFF;
|
||||
line-height: 200rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.job-dialog {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
padding: 0 20rpx;
|
||||
height: calc(100% - 17vh);
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.checkbox-group {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.checkbox-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 2rpx solid #b5d3ff;
|
||||
padding: 30rpx 0;
|
||||
}
|
||||
|
||||
.job-item {
|
||||
width: 97%;
|
||||
}
|
||||
|
||||
.checkbox-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border: 2rpx solid #ddd;
|
||||
border-radius: 8rpx;
|
||||
margin-right: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.checkbox-icon.checked {
|
||||
background-color: #409eff;
|
||||
border-color: #409eff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.job-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.detail-item .gw-label {
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.detail-item .gw-value {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.detail-item .gw-value .cd-detail {
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
margin-bottom: 28rpx;
|
||||
margin-top: 28rpx;
|
||||
}
|
||||
|
||||
.detail-item .gw-value .cd-detail .cd-name {
|
||||
background: #d3e8ff;
|
||||
color: #0076d9;
|
||||
font-size: 40rpx;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
padding: 0 40rpx;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.detail-item .gw-value .cd-detail .cd-name::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 10rpx;
|
||||
height: 100%;
|
||||
background: #349cfc;
|
||||
}
|
||||
|
||||
.detail-item .gw-value .cd-detail .cd-con {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
padding: 30rpx 40rpx;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.detail-item .gw-value .cd-detail .cd-con .cd-con-item {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
background: #67CFA7;
|
||||
line-height: 80rpx;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
border: 2rpx solid #ddd;
|
||||
border-radius: 20rpx;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.detail-item .gw-value .cd-detail .cd-con .cd-con-item-review {
|
||||
background-color: #F8BB92;
|
||||
}
|
||||
|
||||
.detail-item .gw-value .cd-detail .cd-con .cd-con-item-checked {
|
||||
background: #F6A1A1;
|
||||
}
|
||||
|
||||
.detail-item .gw-value .cd-detail .cd-con .cd-con-item-mychecked {
|
||||
background: #79BEFE;
|
||||
}
|
||||
|
||||
.item-checkbox {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.job-name {
|
||||
font-size: 32rpx;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.salary {
|
||||
font-size: 32rpx;
|
||||
color: #ff6e27;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 38rpx;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
padding: 20rpx;
|
||||
padding-bottom: 40rpx;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.header-title image {
|
||||
width: 14rpx;
|
||||
height: 33rpx;
|
||||
margin-right: 14rpx;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 400rpx;
|
||||
height: 200rpx;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
/* 展位状态说明样式 */
|
||||
.status-description {
|
||||
margin-top: 30rpx;
|
||||
padding: 20rpx;
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.status-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 16rpx;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.status-item {
|
||||
width: 43%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 30rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.status-color {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.status-color.available {
|
||||
background-color: #67CFA7;
|
||||
border: 2rpx solid #ddd;
|
||||
}
|
||||
|
||||
.status-color.occupied {
|
||||
background-color: #F6A1A1;
|
||||
}
|
||||
|
||||
.status-color.pending {
|
||||
background-color: #F8BB92;
|
||||
}
|
||||
|
||||
.status-color.selected {
|
||||
background-color: #79BEFE;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
/* 透明按钮样式 */
|
||||
.transparent-btn {
|
||||
background: transparent !important;
|
||||
border: 2rpx dashed #0983ff !important;
|
||||
}
|
||||
</style>
|
||||
@@ -1,203 +0,0 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-popup :show="visible">
|
||||
<view style="position: relative;height: 100vh;width: 100%;">
|
||||
<view class="button-area" style="padding: 8vh 32rpx 24rpx 32rpx; margin: 0;border: 0;position: relative;z-index: 2;display: block; top: 10rpx; border-radius: 0;">
|
||||
<u-input style="margin-bottom: 16px;" v-model="placeInput" @change="getLocations" placeholder="请输入并选择相应地点"></u-input>
|
||||
<view v-if="checkedMarker&&checkedMarker.name" class="selected">您已选择:{{ checkedMarker.name }}<text v-if="checkedMarker.address">({{ checkedMarker.address }})</text></view>
|
||||
<view v-for="(item, index) in placeList" :key="index" :label="item.name" :value="item.name" @click="addIcon(item.name)" class="place-list">
|
||||
<view style="display: flex;justify-content: space-between;">{{ item.name }}
|
||||
<view style="color: #8492a6; font-size: 13px;width: 50%">{{ item.address }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="map" id="map"></view>
|
||||
<view class="button-area">
|
||||
<view class="btn" @click="cancel">取 消</view>
|
||||
<view class="btn save" @click="submitForm">确 定</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
//import { jsonp } from "vue-jsonp";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
map: '',
|
||||
placeList: [],
|
||||
placeInput: '',
|
||||
markerList: [],
|
||||
checkedMarker: '',
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// this.openDialog();
|
||||
},
|
||||
methods: {
|
||||
submitForm() {
|
||||
if(this.checkedMarker&&this.checkedMarker.name){
|
||||
this.$emit('selected', this.checkedMarker)
|
||||
this.visible = false;
|
||||
}else{
|
||||
this.$message.warning('您尚未选择地点!')
|
||||
}
|
||||
},
|
||||
cancel() {
|
||||
this.visible = false;
|
||||
if (this.map) {
|
||||
this.map.removeEventListener('click', this.handleMapClick);
|
||||
}
|
||||
},
|
||||
openDialog() {
|
||||
this.visible = true;
|
||||
this.$nextTick(() => {
|
||||
this.map = new BMapGL.Map("map");
|
||||
var point = new BMapGL.Point(117.123237,36.657017);
|
||||
this.map.centerAndZoom(point, 15);
|
||||
this.map.enableScrollWheelZoom();
|
||||
var locationCtrl = new BMapGL.LocationControl();
|
||||
this.map.addControl(locationCtrl)
|
||||
this.map.addEventListener('click', this.handleMapClick);
|
||||
})
|
||||
},
|
||||
handleMapClick(e) {
|
||||
const lng = e.latlng.lng;
|
||||
const lat = e.latlng.lat;
|
||||
// 逆地理编码
|
||||
jsonp("https://api.map.baidu.com/reverse_geocoding/v3/", {
|
||||
ak: "qr93Dm5Ph6Vb4n1aTfvHG9KZkvG8S4YU",
|
||||
output: "json",
|
||||
location: `${lat},${lng}`,
|
||||
}).then(res => {
|
||||
if (res.status === 0) {
|
||||
// 清除原有标记
|
||||
this.removeOverlay();
|
||||
// 新建标记
|
||||
const point = new BMapGL.Point(lng, lat);
|
||||
const marker = new BMapGL.Marker(point);
|
||||
this.map.addOverlay(marker);
|
||||
this.markerList = [marker];
|
||||
// 保存选中信息
|
||||
this.checkedMarker = {
|
||||
name: res.result.formatted_address,
|
||||
address: res.result.sematic_description,
|
||||
location: { lng, lat }
|
||||
};
|
||||
this.$forceUpdate();
|
||||
}
|
||||
});
|
||||
},
|
||||
getLocations(place) {
|
||||
jsonp("https://api.map.baidu.com/place/v2/suggestion", {
|
||||
q: place,
|
||||
ak: "qr93Dm5Ph6Vb4n1aTfvHG9KZkvG8S4YU",
|
||||
region: '济南市',
|
||||
output: "json",
|
||||
})
|
||||
.then((json) => {
|
||||
console.log(json,23423434)
|
||||
this.placeList = json.result
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
addIcon(e) {
|
||||
let arr = this.placeList.filter(ele => ele.name == e)
|
||||
if(arr.length){
|
||||
this.addMaker(arr)
|
||||
this.clickMaker(arr[0]);
|
||||
}else{
|
||||
this.addMaker(JSON.parse(JSON.stringify(this.placeList)))
|
||||
}
|
||||
this.placeList = []
|
||||
},
|
||||
removeOverlay() {
|
||||
this.markerList.forEach(ele => {
|
||||
this.map.removeOverlay(ele)
|
||||
})
|
||||
},
|
||||
addMaker(list) {
|
||||
this.removeOverlay()
|
||||
list.forEach((ele, index) => {
|
||||
let point = new BMapGL.Point(ele.location.lng, ele.location.lat);
|
||||
if(index == 0){
|
||||
this.map.centerAndZoom(point, 15)
|
||||
}
|
||||
let marker = new BMapGL.Marker(point); // 创建标注
|
||||
this.map.addOverlay(marker);
|
||||
let that = this;
|
||||
this.markerList.push(marker)
|
||||
marker.addEventListener("click", function(){
|
||||
that.clickMaker(ele)
|
||||
});
|
||||
})
|
||||
},
|
||||
clickMaker(e){
|
||||
this.checkedMarker = e;
|
||||
this.$forceUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.selected {
|
||||
margin-bottom: 16px;
|
||||
position: relative;z-index: 2;
|
||||
background: #DCE2E9;
|
||||
border-radius: 8rpx;
|
||||
padding: 12rpx 24rpx;
|
||||
}
|
||||
.map{
|
||||
width: 100%;
|
||||
margin-top: 16px;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.button-area{
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
bottom: 0;
|
||||
padding: 24rpx 32rpx 68rpx;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
margin-top: 40rpx;
|
||||
border-radius: 16px 16px 0px 0px;
|
||||
.btn{
|
||||
line-height: 72rpx;
|
||||
width: 176rpx;
|
||||
margin-right: 16rpx;
|
||||
font-size: 28rpx;
|
||||
border: 1px solid #B8C5D4;
|
||||
color: #282828;
|
||||
text-align: center;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
.reset{
|
||||
background: #DCE2E9;
|
||||
}
|
||||
.save{
|
||||
background: linear-gradient(103deg, #1D64CF 0%, #1590D4 99%);
|
||||
color: #fff;
|
||||
border: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
.place-list{
|
||||
line-height: 32rpx;
|
||||
padding: 16rpx 0;
|
||||
border-bottom: 1px solid #DCE2E9;
|
||||
}
|
||||
</style>
|
||||
@@ -4,6 +4,8 @@ export default {
|
||||
|
||||
LCBaseUrl:'http://10.110.145.145:9100',//招聘、培训、帮扶
|
||||
LCBaseUrlInner:'http://10.110.145.145:10100',//内网端口
|
||||
imgBaseUrl:'http://10.110.145.145/images', //图片基础url
|
||||
trainVideoImgUrl:'http://10.110.145.145:9100/file/file/minio',
|
||||
// sseAI+
|
||||
// StreamBaseURl: 'http://39.98.44.136:8000',
|
||||
StreamBaseURl: 'https://qd.zhaopinzao8dian.com/ai',
|
||||
|
||||
167
main.js
167
main.js
@@ -1,20 +1,14 @@
|
||||
/*
|
||||
* @Date: 2025-10-23 14:48:48
|
||||
* @Date: 2025-11-03 10:52:09
|
||||
* @LastEditors: shirlwang
|
||||
* @LastEditTime: 2025-11-03 09:39:18
|
||||
* @LastEditTime: 2025-11-04 11:14:21
|
||||
*/
|
||||
import App from './App'
|
||||
import App from '@/App'
|
||||
import * as Pinia from 'pinia'
|
||||
import globalFunction from './common/globalFunction'
|
||||
import './lib/string-similarity.min.js'
|
||||
import similarityJobs from './utils/similarity_Job.js';
|
||||
import config from './config.js';
|
||||
// 导入主包中的request.js用于字典服务
|
||||
// 在uni-app小程序环境中,主包不能直接引用分包中的模块
|
||||
import { request, get, post, packageRcRequest, packageRcGet, packageRcPost } from './utils/request.js';
|
||||
// 将request, get, post函数挂载到全局,方便使用
|
||||
// 挂载分包专用的请求函数(使用固定baseURL和token)
|
||||
|
||||
import globalFunction from '@/common/globalFunction'
|
||||
import '@/lib/string-similarity.min.js'
|
||||
import similarityJobs from '@/utils/similarity_Job.js';
|
||||
import config from '@/config.js';
|
||||
// 组件
|
||||
import AppLayout from './components/AppLayout/AppLayout.vue';
|
||||
import Empty from './components/empty/empty.vue';
|
||||
@@ -24,6 +18,13 @@ import SelectPopup from '@/components/selectPopup/selectPopup.vue'
|
||||
import SelectPopupPlugin from '@/components/selectPopup/selectPopupPlugin';
|
||||
import RenderJobs from '@/components/renderJobs/renderJobs.vue';
|
||||
import RenderCompanys from '@/components/renderCompanys/renderCompanys.vue';
|
||||
import uniIcons from './uni_modules/uni-icons/components/uni-icons/uni-icons.vue'
|
||||
import uniPopup from './uni_modules/uni-popup/components/uni-popup/uni-popup.vue'
|
||||
import uniDataSelect from './uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue'
|
||||
import uniSwipeAction from './uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue'
|
||||
import uniSwipeActionItem from './uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue'
|
||||
import storeRc from './utilsRc/store/index.js'
|
||||
import {processFileUrl,} from '@/utilsRc/common.js'
|
||||
// iconfont.css 已在 App.vue 中通过 @import 引入,无需在此处重复引入
|
||||
// import Tabbar from '@/components/tabbar/midell-box.vue'
|
||||
// 自动导入 directives 目录下所有指令
|
||||
@@ -31,90 +32,18 @@ const directives = import.meta.glob('./directives/*.js', {
|
||||
eager: true
|
||||
});
|
||||
|
||||
import { createSSRApp } from 'vue'
|
||||
// import { createStore } from 'vuex'
|
||||
// 导入已安装的uni-ui组件
|
||||
import uniIcons from './uni_modules/uni-icons/components/uni-icons/uni-icons.vue'
|
||||
import uniPopup from './uni_modules/uni-popup/components/uni-popup/uni-popup.vue'
|
||||
import {
|
||||
createSSRApp,
|
||||
} from 'vue'
|
||||
|
||||
// // 创建Vuex store实例,避免从分包导入
|
||||
// const storeRc = createStore({
|
||||
// state() {
|
||||
// return {
|
||||
// userInfo: null,
|
||||
// token: '',
|
||||
// roles: []
|
||||
// }
|
||||
// },
|
||||
// mutations: {
|
||||
// setUserInfo(state, userInfo) {
|
||||
// state.userInfo = userInfo
|
||||
// },
|
||||
// setToken(state, token) {
|
||||
// state.token = token
|
||||
// },
|
||||
// setRoles(state, roles) {
|
||||
// state.roles = roles
|
||||
// },
|
||||
// logout(state) {
|
||||
// state.userInfo = null
|
||||
// state.token = ''
|
||||
// state.roles = []
|
||||
// }
|
||||
// },
|
||||
// actions: {
|
||||
// async login({ commit }, userData) {
|
||||
// // 登录逻辑
|
||||
// commit('setUserInfo', userData)
|
||||
// commit('setToken', 'mock-token')
|
||||
// commit('setRoles', ['user'])
|
||||
// }
|
||||
// },
|
||||
// getters: {
|
||||
// roles: state => state.roles
|
||||
// }
|
||||
// })
|
||||
|
||||
import storeRc from './utilsRc/store/index.js'
|
||||
// const foldFeature = window.visualViewport && 'segments' in window.visualViewport
|
||||
// console.log('是否支持多段屏幕:', foldFeature)
|
||||
|
||||
import { getDict } from '@/apiRc/system/dict.js';
|
||||
// 全局组件
|
||||
// 字典缓存,避免重复请求
|
||||
const dictCache = new Map();
|
||||
|
||||
// 获取字典数据的方法
|
||||
async function getDict(dictType, forceRefresh = false) {
|
||||
// 检查缓存
|
||||
if (dictCache.has(dictType) && !forceRefresh) {
|
||||
return dictCache.get(dictType);
|
||||
}
|
||||
|
||||
try {
|
||||
// 使用packageRc/utils/request.js中的请求方法
|
||||
// 注意:这里使用的baseURL是 http://10.160.0.5:8907/
|
||||
const response = await request({
|
||||
url: `system/dict/data/type/${dictType}`,
|
||||
method: 'GET',
|
||||
load: true
|
||||
});
|
||||
|
||||
// 处理响应数据
|
||||
if (response.code === 200 && response.data) {
|
||||
// 缓存数据
|
||||
dictCache.set(dictType, response.data);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
return [];
|
||||
} catch (error) {
|
||||
console.error(`获取字典[${dictType}]失败:`, error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
|
||||
app.component('AppLayout', AppLayout)
|
||||
app.component('Empty', Empty)
|
||||
app.component('NoBouncePage', NoBouncePage)
|
||||
@@ -122,36 +51,14 @@ export function createApp() {
|
||||
app.component('SelectPopup', SelectPopup)
|
||||
app.component('RenderJobs', RenderJobs)
|
||||
app.component('RenderCompanys', RenderCompanys)
|
||||
// app.component('tabbar-custom', Tabbar)
|
||||
|
||||
// 注册已安装的uni-ui组件
|
||||
app.component('uni-icons', uniIcons)
|
||||
app.component('uni-popup', uniPopup)
|
||||
// 注意:项目缺少表单相关组件,需要将模板中的uni-ui组件改为原生元素
|
||||
|
||||
for (const path in directives) {
|
||||
const directiveModule = directives[path];
|
||||
// 文件名作为指令名,./directives/fade.js => v-fade
|
||||
const name = path.match(/\/directives\/(.*)\.js$/)[1];
|
||||
app.directive(name, directiveModule.default);
|
||||
}
|
||||
|
||||
app.provide('globalFunction', {
|
||||
...globalFunction,
|
||||
similarityJobs,
|
||||
config
|
||||
});
|
||||
app.provide('deviceInfo', globalFunction.getdeviceInfo());
|
||||
|
||||
// 先注册Pinia
|
||||
app.use(Pinia.createPinia());
|
||||
// 注册vuex
|
||||
app.use(storeRc);
|
||||
|
||||
// 注册其他插件
|
||||
app.use(SelectPopupPlugin);
|
||||
|
||||
// Vue 3 中挂载全局属性 - 字典获取方法
|
||||
app.component('uni-data-select', uniDataSelect)
|
||||
app.component('uni-swipe-action', uniSwipeAction)
|
||||
app.component('uni-swipe-action-item', uniSwipeActionItem)
|
||||
|
||||
|
||||
app.config.globalProperties.$processFileUrl = processFileUrl;
|
||||
app.config.globalProperties.$getDict = getDict;
|
||||
app.config.globalProperties.$store = storeRc;
|
||||
app.config.globalProperties.$getDictSelectOption = async (dictType, isDigital = false, forceRefresh = false) => {
|
||||
@@ -162,11 +69,29 @@ export function createApp() {
|
||||
...item
|
||||
}));
|
||||
};
|
||||
// app.component('tabbar-custom', Tabbar)
|
||||
|
||||
for (const path in directives) {
|
||||
const directiveModule = directives[path];
|
||||
// 文件名作为指令名,./directives/fade.js => v-fade
|
||||
const name = path.match(/\.\/directives\/(.*)\.js$/)[1];
|
||||
app.directive(name, directiveModule.default);
|
||||
}
|
||||
|
||||
app.provide('globalFunction', {
|
||||
...globalFunction,
|
||||
similarityJobs,
|
||||
config
|
||||
});
|
||||
app.provide('deviceInfo', globalFunction.getdeviceInfo());
|
||||
|
||||
app.use(SelectPopupPlugin);
|
||||
app.use(Pinia.createPinia());
|
||||
// 注册vuex
|
||||
app.use(storeRc);
|
||||
|
||||
return {
|
||||
app,
|
||||
Pinia
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
25
node_modules/.package-lock.json
generated
vendored
25
node_modules/.package-lock.json
generated
vendored
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"name": "ks-app-employment-service",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.19",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
|
||||
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="
|
||||
},
|
||||
"node_modules/jsbn": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
|
||||
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
|
||||
},
|
||||
"node_modules/sm-crypto": {
|
||||
"version": "0.3.13",
|
||||
"resolved": "https://registry.npmjs.org/sm-crypto/-/sm-crypto-0.3.13.tgz",
|
||||
"integrity": "sha512-ztNF+pZq6viCPMA1A6KKu3bgpkmYti5avykRHbcFIdSipFdkVmfUw2CnpM2kBJyppIalqvczLNM3wR8OQ0pT5w==",
|
||||
"dependencies": {
|
||||
"jsbn": "^1.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
node_modules/jsbn/.npmignore
generated
vendored
2
node_modules/jsbn/.npmignore
generated
vendored
@@ -1,2 +0,0 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
16
node_modules/jsbn/CHANGELOG.md
generated
vendored
16
node_modules/jsbn/CHANGELOG.md
generated
vendored
@@ -1,16 +0,0 @@
|
||||
# v1.1.0
|
||||
|
||||
- Allow for es6 "default import", e.g. `import BigInteger from 'jsbn'`.
|
||||
- Updated license file to read MIT
|
||||
|
||||
|
||||
# v1.0.0
|
||||
|
||||
- breaking change: `require('jsbn')` no longer returns `BigInteger`. Use `require('jsbn').BigInteger` instead.
|
||||
|
||||
|
||||
|
||||
# v0.1.1
|
||||
|
||||
- fixed backwards-incompatible change in v0.1.0 where `require('jsbn') != BigInteger`. This patch version allows for `var BigInteger = require('jsbn')` or `var BigInteger = require('jsbn').BigInteger`.
|
||||
|
||||
40
node_modules/jsbn/LICENSE
generated
vendored
40
node_modules/jsbn/LICENSE
generated
vendored
@@ -1,40 +0,0 @@
|
||||
Licensing
|
||||
---------
|
||||
|
||||
This software is covered under the following copyright:
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003-2005 Tom Wu
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
||||
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
|
||||
* THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* In addition, the following condition applies:
|
||||
*
|
||||
* All redistributions must retain an intact copy of this copyright notice
|
||||
* and disclaimer.
|
||||
*/
|
||||
|
||||
Address all questions regarding this license to:
|
||||
|
||||
Tom Wu
|
||||
tjw@cs.Stanford.EDU
|
||||
173
node_modules/jsbn/README.md
generated
vendored
173
node_modules/jsbn/README.md
generated
vendored
@@ -1,173 +0,0 @@
|
||||
# jsbn: javascript big number
|
||||
|
||||
[Tom Wu's Original Website](http://www-cs-students.stanford.edu/~tjw/jsbn/)
|
||||
|
||||
I felt compelled to put this on github and publish to npm. I haven't tested every other big integer library out there, but the few that I have tested in comparison to this one have not even come close in performance. I am aware of the `bi` module on npm, however it has been modified and I wanted to publish the original without modifications. This is jsbn and jsbn2 from Tom Wu's original website above, with the module pattern applied to prevent global leaks and to allow for use with node.js on the server side.
|
||||
|
||||
## usage
|
||||
|
||||
var BigInteger = require('jsbn').BigInteger;
|
||||
|
||||
var bi = new BigInteger('91823918239182398123');
|
||||
console.log(bi.bitLength()); // 67
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### bi.toString()
|
||||
|
||||
returns the base-10 number as a string
|
||||
|
||||
### bi.negate()
|
||||
|
||||
returns a new BigInteger equal to the negation of `bi`
|
||||
|
||||
### bi.abs
|
||||
|
||||
returns new BI of absolute value
|
||||
|
||||
### bi.compareTo
|
||||
|
||||
|
||||
|
||||
### bi.bitLength
|
||||
|
||||
|
||||
|
||||
### bi.mod
|
||||
|
||||
|
||||
|
||||
### bi.modPowInt
|
||||
|
||||
|
||||
|
||||
### bi.clone
|
||||
|
||||
|
||||
|
||||
### bi.intValue
|
||||
|
||||
|
||||
|
||||
### bi.byteValue
|
||||
|
||||
|
||||
|
||||
### bi.shortValue
|
||||
|
||||
|
||||
|
||||
### bi.signum
|
||||
|
||||
|
||||
|
||||
### bi.toByteArray
|
||||
|
||||
|
||||
|
||||
### bi.equals
|
||||
|
||||
|
||||
|
||||
### bi.min
|
||||
|
||||
|
||||
|
||||
### bi.max
|
||||
|
||||
|
||||
|
||||
### bi.and
|
||||
|
||||
|
||||
|
||||
### bi.or
|
||||
|
||||
|
||||
|
||||
### bi.xor
|
||||
|
||||
|
||||
|
||||
### bi.andNot
|
||||
|
||||
|
||||
|
||||
### bi.not
|
||||
|
||||
|
||||
|
||||
### bi.shiftLeft
|
||||
|
||||
|
||||
|
||||
### bi.shiftRight
|
||||
|
||||
|
||||
|
||||
### bi.getLowestSetBit
|
||||
|
||||
|
||||
|
||||
### bi.bitCount
|
||||
|
||||
|
||||
|
||||
### bi.testBit
|
||||
|
||||
|
||||
|
||||
### bi.setBit
|
||||
|
||||
|
||||
|
||||
### bi.clearBit
|
||||
|
||||
|
||||
|
||||
### bi.flipBit
|
||||
|
||||
|
||||
|
||||
### bi.add
|
||||
|
||||
|
||||
|
||||
### bi.subtract
|
||||
|
||||
|
||||
|
||||
### bi.multiply
|
||||
|
||||
|
||||
|
||||
### bi.divide
|
||||
|
||||
|
||||
|
||||
### bi.remainder
|
||||
|
||||
|
||||
|
||||
### bi.divideAndRemainder
|
||||
|
||||
|
||||
|
||||
### bi.modPow
|
||||
|
||||
|
||||
|
||||
### bi.modInverse
|
||||
|
||||
|
||||
|
||||
### bi.pow
|
||||
|
||||
|
||||
|
||||
### bi.gcd
|
||||
|
||||
|
||||
|
||||
### bi.isProbablePrime
|
||||
11
node_modules/jsbn/example.html
generated
vendored
11
node_modules/jsbn/example.html
generated
vendored
@@ -1,11 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="index.js"></script>
|
||||
<script src="example.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
5
node_modules/jsbn/example.js
generated
vendored
5
node_modules/jsbn/example.js
generated
vendored
@@ -1,5 +0,0 @@
|
||||
(function () {
|
||||
var BigInteger = jsbn.BigInteger;
|
||||
var a = new BigInteger('91823918239182398123');
|
||||
console.log(a.bitLength());
|
||||
}());
|
||||
1361
node_modules/jsbn/index.js
generated
vendored
1361
node_modules/jsbn/index.js
generated
vendored
File diff suppressed because it is too large
Load Diff
21
node_modules/jsbn/package.json
generated
vendored
21
node_modules/jsbn/package.json
generated
vendored
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"name": "jsbn",
|
||||
"version": "1.1.0",
|
||||
"description": "The jsbn library is a fast, portable implementation of large-number math in pure JavaScript, enabling public-key crypto and other applications on desktop and mobile browsers.",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "mocha test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/andyperlitch/jsbn.git"
|
||||
},
|
||||
"keywords": [
|
||||
"biginteger",
|
||||
"bignumber",
|
||||
"big",
|
||||
"integer"
|
||||
],
|
||||
"author": "Tom Wu",
|
||||
"license": "MIT"
|
||||
}
|
||||
3
node_modules/jsbn/test/es6-import.js
generated
vendored
3
node_modules/jsbn/test/es6-import.js
generated
vendored
@@ -1,3 +0,0 @@
|
||||
import {BigInteger} from '../';
|
||||
|
||||
console.log(typeof BigInteger)
|
||||
3
node_modules/sm-crypto/.babelrc
generated
vendored
3
node_modules/sm-crypto/.babelrc
generated
vendored
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"presets": ["es2015"]
|
||||
}
|
||||
97
node_modules/sm-crypto/.eslintrc.js
generated
vendored
97
node_modules/sm-crypto/.eslintrc.js
generated
vendored
@@ -1,97 +0,0 @@
|
||||
module.exports = {
|
||||
'extends': [
|
||||
'airbnb-base',
|
||||
'plugin:promise/recommended'
|
||||
],
|
||||
'parserOptions': {
|
||||
'ecmaVersion': 9,
|
||||
'ecmaFeatures': {
|
||||
'jsx': false
|
||||
},
|
||||
'sourceType': 'module'
|
||||
},
|
||||
'env': {
|
||||
'es6': true,
|
||||
'node': true,
|
||||
'jest': true
|
||||
},
|
||||
'plugins': [
|
||||
'import',
|
||||
'node',
|
||||
'promise'
|
||||
],
|
||||
'rules': {
|
||||
'arrow-parens': 'off',
|
||||
'comma-dangle': [
|
||||
'error',
|
||||
'only-multiline'
|
||||
],
|
||||
'complexity': ['error', 20],
|
||||
'func-names': 'off',
|
||||
'global-require': 'off',
|
||||
'handle-callback-err': [
|
||||
'error',
|
||||
'^(err|error)$'
|
||||
],
|
||||
'import/no-unresolved': [
|
||||
'error',
|
||||
{
|
||||
'caseSensitive': true,
|
||||
'commonjs': true,
|
||||
'ignore': ['^[^.]']
|
||||
}
|
||||
],
|
||||
'import/prefer-default-export': 'off',
|
||||
'linebreak-style': 'off',
|
||||
'no-catch-shadow': 'error',
|
||||
'no-continue': 'off',
|
||||
'no-div-regex': 'warn',
|
||||
'no-else-return': 'off',
|
||||
'no-param-reassign': 'off',
|
||||
'no-plusplus': 'off',
|
||||
'no-shadow': 'off',
|
||||
'no-multi-assign': 'off',
|
||||
'no-underscore-dangle': 'off',
|
||||
'node/no-deprecated-api': 'error',
|
||||
'node/process-exit-as-throw': 'error',
|
||||
'object-curly-spacing': [
|
||||
'error',
|
||||
'never'
|
||||
],
|
||||
'operator-linebreak': [
|
||||
'error',
|
||||
'after',
|
||||
{
|
||||
'overrides': {
|
||||
':': 'before',
|
||||
'?': 'before'
|
||||
}
|
||||
}
|
||||
],
|
||||
'prefer-arrow-callback': 'off',
|
||||
'prefer-destructuring': 'off',
|
||||
'prefer-template': 'off',
|
||||
'quote-props': [
|
||||
1,
|
||||
'as-needed',
|
||||
{
|
||||
'unnecessary': true
|
||||
}
|
||||
],
|
||||
'semi': [
|
||||
'error',
|
||||
'never'
|
||||
],
|
||||
'max-len': 'off',
|
||||
'no-bitwise': 'off',
|
||||
'no-mixed-operators': 'off',
|
||||
},
|
||||
'globals': {
|
||||
'window': true,
|
||||
'document': true,
|
||||
'App': true,
|
||||
'Page': true,
|
||||
'Component': true,
|
||||
'Behavior': true
|
||||
}
|
||||
}
|
||||
82
node_modules/sm-crypto/CHANGELOG.md
generated
vendored
82
node_modules/sm-crypto/CHANGELOG.md
generated
vendored
@@ -1,82 +0,0 @@
|
||||
## 0.3.13
|
||||
|
||||
* 支持根据私钥获取公钥
|
||||
|
||||
## 0.3.12
|
||||
|
||||
* 优化 sm3 运行性能
|
||||
|
||||
## 0.3.11
|
||||
|
||||
* sm2 支持压缩公钥
|
||||
|
||||
## 0.3.10
|
||||
|
||||
* 支持 sm3 hmac 模式
|
||||
|
||||
|
||||
## 0.3.9
|
||||
|
||||
* 补充 sm4 解密时的 padding 判断
|
||||
|
||||
## 0.3.8
|
||||
|
||||
* sm2 解密时兼容密文可能是大写的情况
|
||||
|
||||
## 0.3.7
|
||||
|
||||
* 默认填充改为 pkcs#7,如传入 pkcs#5 也转到 pkcs#7 逻辑
|
||||
|
||||
## 0.3.6
|
||||
|
||||
* sm2 加解密支持二进制数据
|
||||
|
||||
## 0.3.5
|
||||
|
||||
* sm2.generateKeyPairHex 支持完整的 BigInteger 入参
|
||||
|
||||
## 0.3.4
|
||||
|
||||
* sm2 支持验证公钥接口
|
||||
* sm2 生成密钥时支持自定义随机数
|
||||
|
||||
## 0.3.3
|
||||
|
||||
* dist 输出改成 umd 模式
|
||||
|
||||
## 0.3.2
|
||||
|
||||
* 修复 sm2 在 userId 长度大于 31 时新旧版本验签不通过的问题
|
||||
## 0.3.0
|
||||
|
||||
* sm2、sm3 重构
|
||||
* sm4 支持 cbc 模式
|
||||
|
||||
## 0.2.7
|
||||
|
||||
* 优化 sm3 性能
|
||||
|
||||
## 0.2.5
|
||||
|
||||
* sm3 支持字节数组输入
|
||||
|
||||
## 0.2.4
|
||||
|
||||
* 修复 sm4 四字节字符输出编码
|
||||
|
||||
## 0.2.3
|
||||
|
||||
* sm3/sm4 支持输入四字节字符
|
||||
|
||||
## 0.2.2
|
||||
|
||||
* sm3 支持中文输入
|
||||
|
||||
## 0.2.1
|
||||
|
||||
* 修复 sm2 点 16 进制串可能不满 64 位的问题
|
||||
|
||||
## 0.2.0
|
||||
|
||||
* sm4 默认支持 pkcs#5 填充方式
|
||||
* sm4 支持输入输出为字符串
|
||||
7
node_modules/sm-crypto/LICENCE_MIT
generated
vendored
7
node_modules/sm-crypto/LICENCE_MIT
generated
vendored
@@ -1,7 +0,0 @@
|
||||
Copyright © 2018 june01
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
171
node_modules/sm-crypto/README.md
generated
vendored
171
node_modules/sm-crypto/README.md
generated
vendored
@@ -1,171 +0,0 @@
|
||||
# sm-crypto
|
||||
|
||||
国密算法sm2、sm3和sm4的js实现。
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
npm install --save sm-crypto
|
||||
```
|
||||
|
||||
## sm2
|
||||
|
||||
### 获取密钥对
|
||||
|
||||
```js
|
||||
const sm2 = require('sm-crypto').sm2
|
||||
|
||||
let keypair = sm2.generateKeyPairHex()
|
||||
|
||||
publicKey = keypair.publicKey // 公钥
|
||||
privateKey = keypair.privateKey // 私钥
|
||||
|
||||
// 默认生成公钥 130 位太长,可以压缩公钥到 66 位
|
||||
const compressedPublicKey = sm2.compressPublicKeyHex(publicKey) // compressedPublicKey 和 publicKey 等价
|
||||
sm2.comparePublicKeyHex(publicKey, compressedPublicKey) // 判断公钥是否等价
|
||||
|
||||
// 自定义随机数,参数会直接透传给 jsbn 库的 BigInteger 构造器
|
||||
// 注意:开发者使用自定义随机数,需要自行确保传入的随机数符合密码学安全
|
||||
let keypair2 = sm2.generateKeyPairHex('123123123123123')
|
||||
let keypair3 = sm2.generateKeyPairHex(256, SecureRandom)
|
||||
|
||||
let verifyResult = sm2.verifyPublicKey(publicKey) // 验证公钥
|
||||
verifyResult = sm2.verifyPublicKey(compressedPublicKey) // 验证公钥
|
||||
```
|
||||
|
||||
### 加密解密
|
||||
|
||||
```js
|
||||
const sm2 = require('sm-crypto').sm2
|
||||
const cipherMode = 1 // 1 - C1C3C2,0 - C1C2C3,默认为1
|
||||
|
||||
let encryptData = sm2.doEncrypt(msgString, publicKey, cipherMode) // 加密结果
|
||||
let decryptData = sm2.doDecrypt(encryptData, privateKey, cipherMode) // 解密结果
|
||||
|
||||
encryptData = sm2.doEncrypt(msgArray, publicKey, cipherMode) // 加密结果,输入数组
|
||||
decryptData = sm2.doDecrypt(encryptData, privateKey, cipherMode, {output: 'array'}) // 解密结果,输出数组
|
||||
```
|
||||
|
||||
> ps:密文会在解密时自动补充 `04`,如遇到其他工具补充的 `04` 需手动去除再传入。
|
||||
|
||||
### 签名验签
|
||||
|
||||
> ps:理论上来说,只做纯签名是最快的。
|
||||
|
||||
```js
|
||||
const sm2 = require('sm-crypto').sm2
|
||||
|
||||
// 纯签名 + 生成椭圆曲线点
|
||||
let sigValueHex = sm2.doSignature(msg, privateKey) // 签名
|
||||
let verifyResult = sm2.doVerifySignature(msg, sigValueHex, publicKey) // 验签结果
|
||||
|
||||
// 纯签名
|
||||
let sigValueHex2 = sm2.doSignature(msg, privateKey, {
|
||||
pointPool: [sm2.getPoint(), sm2.getPoint(), sm2.getPoint(), sm2.getPoint()], // 传入事先已生成好的椭圆曲线点,可加快签名速度
|
||||
}) // 签名
|
||||
let verifyResult2 = sm2.doVerifySignature(msg, sigValueHex2, publicKey) // 验签结果
|
||||
|
||||
// 纯签名 + 生成椭圆曲线点 + der编解码
|
||||
let sigValueHex3 = sm2.doSignature(msg, privateKey, {
|
||||
der: true,
|
||||
}) // 签名
|
||||
let verifyResult3 = sm2.doVerifySignature(msg, sigValueHex3, publicKey, {
|
||||
der: true,
|
||||
}) // 验签结果
|
||||
|
||||
// 纯签名 + 生成椭圆曲线点 + sm3杂凑
|
||||
let sigValueHex4 = sm2.doSignature(msg, privateKey, {
|
||||
hash: true,
|
||||
}) // 签名
|
||||
let verifyResult4 = sm2.doVerifySignature(msg, sigValueHex4, publicKey, {
|
||||
hash: true,
|
||||
}) // 验签结果
|
||||
|
||||
// 纯签名 + 生成椭圆曲线点 + sm3杂凑(不做公钥推导)
|
||||
let sigValueHex5 = sm2.doSignature(msg, privateKey, {
|
||||
hash: true,
|
||||
publicKey, // 传入公钥的话,可以去掉sm3杂凑中推导公钥的过程,速度会比纯签名 + 生成椭圆曲线点 + sm3杂凑快
|
||||
})
|
||||
let verifyResult5 = sm2.doVerifySignature(msg, sigValueHex5, publicKey, {
|
||||
hash: true,
|
||||
publicKey,
|
||||
})
|
||||
|
||||
// 纯签名 + 生成椭圆曲线点 + sm3杂凑 + 不做公钥推 + 添加 userId(长度小于 8192)
|
||||
// 默认 userId 值为 1234567812345678
|
||||
let sigValueHex6 = sm2.doSignature(msgString, privateKey, {
|
||||
hash: true,
|
||||
publicKey,
|
||||
userId: 'testUserId',
|
||||
})
|
||||
let verifyResult6 = sm2.doVerifySignature(msgString, sigValueHex6, publicKey, {
|
||||
hash: true,
|
||||
userId: 'testUserId',
|
||||
})
|
||||
```
|
||||
|
||||
### 获取椭圆曲线点
|
||||
|
||||
```js
|
||||
const sm2 = require('sm-crypto').sm2
|
||||
|
||||
let point = sm2.getPoint() // 获取一个椭圆曲线点,可在sm2签名时传入
|
||||
```
|
||||
|
||||
### 根据私钥获取公钥
|
||||
|
||||
```js
|
||||
const sm2 = require('sm-crypto).sm2
|
||||
|
||||
let publicKey = sm2.getPublicKeyFromPrivateKey(privateKey)
|
||||
```
|
||||
|
||||
## sm3
|
||||
|
||||
```js
|
||||
const sm3 = require('sm-crypto').sm3
|
||||
|
||||
let hashData = sm3('abc') // 杂凑
|
||||
|
||||
// hmac
|
||||
hashData = sm3('abc', {
|
||||
key: 'daac25c1512fe50f79b0e4526b93f5c0e1460cef40b6dd44af13caec62e8c60e0d885f3c6d6fb51e530889e6fd4ac743a6d332e68a0f2a3923f42585dceb93e9', // 要求为 16 进制串或字节数组
|
||||
})
|
||||
```
|
||||
|
||||
## sm4
|
||||
|
||||
### 加密
|
||||
|
||||
```js
|
||||
const sm4 = require('sm-crypto').sm4
|
||||
const msg = 'hello world! 我是 juneandgreen.' // 可以为 utf8 串或字节数组
|
||||
const key = '0123456789abcdeffedcba9876543210' // 可以为 16 进制串或字节数组,要求为 128 比特
|
||||
|
||||
let encryptData = sm4.encrypt(msg, key) // 加密,默认输出 16 进制字符串,默认使用 pkcs#7 填充(传 pkcs#5 也会走 pkcs#7 填充)
|
||||
let encryptData = sm4.encrypt(msg, key, {padding: 'none'}) // 加密,不使用 padding
|
||||
let encryptData = sm4.encrypt(msg, key, {padding: 'none', output: 'array'}) // 加密,不使用 padding,输出为字节数组
|
||||
let encryptData = sm4.encrypt(msg, key, {mode: 'cbc', iv: 'fedcba98765432100123456789abcdef'}) // 加密,cbc 模式
|
||||
```
|
||||
|
||||
### 解密
|
||||
|
||||
```js
|
||||
const sm4 = require('sm-crypto').sm4
|
||||
const encryptData = '0e395deb10f6e8a17e17823e1fd9bd98a1bff1df508b5b8a1efb79ec633d1bb129432ac1b74972dbe97bab04f024e89c' // 可以为 16 进制串或字节数组
|
||||
const key = '0123456789abcdeffedcba9876543210' // 可以为 16 进制串或字节数组,要求为 128 比特
|
||||
|
||||
let decryptData = sm4.decrypt(encryptData, key) // 解密,默认输出 utf8 字符串,默认使用 pkcs#7 填充(传 pkcs#5 也会走 pkcs#7 填充)
|
||||
let decryptData = sm4.decrypt(encryptData, key, {padding: 'none'}) // 解密,不使用 padding
|
||||
let decryptData = sm4.decrypt(encryptData, key, {padding: 'none', output: 'array'}) // 解密,不使用 padding,输出为字节数组
|
||||
let decryptData = sm4.decrypt(encryptData, key, {mode: 'cbc', iv: 'fedcba98765432100123456789abcdef'}) // 解密,cbc 模式
|
||||
```
|
||||
|
||||
## 其他实现
|
||||
|
||||
* 小程序移植版:[https://github.com/wechat-miniprogram/sm-crypto](https://github.com/wechat-miniprogram/sm-crypto)
|
||||
* java 实现(感谢 @antherd 提供):[https://github.com/antherd/sm-crypto](https://github.com/antherd/sm-crypto)
|
||||
* dart 实现(感谢 @luckykellan 提供):[https://github.com/luckykellan/dart_sm](https://github.com/luckykellan/dart_sm)
|
||||
## 协议
|
||||
|
||||
MIT
|
||||
1
node_modules/sm-crypto/dist/sm2.js
generated
vendored
1
node_modules/sm-crypto/dist/sm2.js
generated
vendored
File diff suppressed because one or more lines are too long
1
node_modules/sm-crypto/dist/sm3.js
generated
vendored
1
node_modules/sm-crypto/dist/sm3.js
generated
vendored
@@ -1 +0,0 @@
|
||||
!function(r,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.sm3=n():r.sm3=n()}("undefined"!=typeof self?self:this,function(){return function(r){function n(e){if(t[e])return t[e].exports;var o=t[e]={i:e,l:!1,exports:{}};return r[e].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var t={};return n.m=r,n.c=t,n.d=function(r,t,e){n.o(r,t)||Object.defineProperty(r,t,{configurable:!1,enumerable:!0,get:e})},n.n=function(r){var t=r&&r.__esModule?function(){return r.default}:function(){return r};return n.d(t,"a",t),t},n.o=function(r,n){return Object.prototype.hasOwnProperty.call(r,n)},n.p="",n(n.s=6)}({1:function(r,n,t){"use strict";function e(r){if(Array.isArray(r)){for(var n=0,t=Array(r.length);n<r.length;n++)t[n]=r[n];return t}return Array.from(r)}function o(r,n){var t=31&n;return r<<t|r>>>32-t}function u(r,n){for(var t=[],e=r.length-1;e>=0;e--)t[e]=255&(r[e]^n[e]);return t}function i(r){return r^o(r,9)^o(r,17)}function f(r){return r^o(r,15)^o(r,23)}function a(r){var n=8*r.length,t=n%512;t=t>=448?512-t%448-1:448-t-1;for(var u=new Array((t-7)/8),a=new Array(8),s=0,p=u.length;s<p;s++)u[s]=0;for(var h=0,v=a.length;h<v;h++)a[h]=0;n=n.toString(2);for(var y=7;y>=0;y--)if(n.length>8){var g=n.length-8;a[y]=parseInt(n.substr(g),2),n=n.substr(0,g)}else n.length>0&&(a[y]=parseInt(n,2),n="");for(var d=new Uint8Array([].concat(e(r),[128],u,a)),w=new DataView(d.buffer,0),m=d.length/64,A=new Uint32Array([1937774191,1226093241,388252375,3666478592,2842636476,372324522,3817729613,2969243214]),b=0;b<m;b++){c.fill(0),l.fill(0);for(var x=16*b,j=0;j<16;j++)c[j]=w.getUint32(4*(x+j),!1);for(var U=16;U<68;U++)c[U]=f(c[U-16]^c[U-9]^o(c[U-3],15))^o(c[U-13],7)^c[U-6];for(var E=0;E<64;E++)l[E]=c[E]^c[E+4];for(var I=A[0],O=A[1],P=A[2],k=A[3],S=A[4],_=A[5],D=A[6],M=A[7],V=void 0,q=void 0,z=void 0,B=void 0,C=void 0,F=0;F<64;F++)C=F>=0&&F<=15?2043430169:2055708042,V=o(o(I,12)+S+o(C,F),7),q=V^o(I,12),z=(F>=0&&F<=15?I^O^P:I&O|I&P|O&P)+k+q+l[F],B=(F>=0&&F<=15?S^_^D:S&_|~S&D)+M+V+c[F],k=P,P=o(O,9),O=I,I=z,M=D,D=o(_,19),_=S,S=i(B);A[0]^=I,A[1]^=O,A[2]^=P,A[3]^=k,A[4]^=S,A[5]^=_,A[6]^=D,A[7]^=M}for(var G=[],H=0,J=A.length;H<J;H++){var K=A[H];G.push((4278190080&K)>>>24,(16711680&K)>>>16,(65280&K)>>>8,255&K)}return G}function s(r,n){for(n.length>p&&(n=a(n));n.length<p;)n.push(0);var t=u(n,h),o=u(n,v),i=a([].concat(e(t),e(r)));return a([].concat(e(o),e(i)))}for(var c=new Uint32Array(68),l=new Uint32Array(64),p=64,h=new Uint8Array(p),v=new Uint8Array(p),y=0;y<p;y++)h[y]=54,v[y]=92;r.exports={sm3:a,hmac:s}},6:function(r,n,t){"use strict";function e(r,n){return r.length>=n?r:new Array(n-r.length+1).join("0")+r}function o(r){return r.map(function(r){return r=r.toString(16),1===r.length?"0"+r:r}).join("")}function u(r){var n=[],t=r.length;t%2!=0&&(r=e(r,t+1)),t=r.length;for(var o=0;o<t;o+=2)n.push(parseInt(r.substr(o,2),16));return n}function i(r){for(var n=[],t=0,e=r.length;t<e;t++){var o=r.codePointAt(t);if(o<=127)n.push(o);else if(o<=2047)n.push(192|o>>>6),n.push(128|63&o);else if(o<=55295||o>=57344&&o<=65535)n.push(224|o>>>12),n.push(128|o>>>6&63),n.push(128|63&o);else{if(!(o>=65536&&o<=1114111))throw n.push(o),new Error("input is not supported");t++,n.push(240|o>>>18&28),n.push(128|o>>>12&63),n.push(128|o>>>6&63),n.push(128|63&o)}}return n}var f=t(1),a=f.sm3,s=f.hmac;r.exports=function(r,n){if(r="string"==typeof r?i(r):Array.prototype.slice.call(r),n){if("hmac"!==(n.mode||"hmac"))throw new Error("invalid mode");var t=n.key;if(!t)throw new Error("invalid key");return t="string"==typeof t?u(t):Array.prototype.slice.call(t),o(s(r,t))}return o(a(r))}}})});
|
||||
1
node_modules/sm-crypto/dist/sm4.js
generated
vendored
1
node_modules/sm-crypto/dist/sm4.js
generated
vendored
File diff suppressed because one or more lines are too long
42
node_modules/sm-crypto/package.json
generated
vendored
42
node_modules/sm-crypto/package.json
generated
vendored
@@ -1,42 +0,0 @@
|
||||
{
|
||||
"name": "sm-crypto",
|
||||
"version": "0.3.13",
|
||||
"description": "sm-crypto",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"prepublish": "npm run build",
|
||||
"test": "jest ./test/*",
|
||||
"lint": "eslint \"src/**/*.js\" --fix",
|
||||
"build": "npm run lint && webpack"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/JuneAndGreen/sm-crypto.git"
|
||||
},
|
||||
"keywords": [
|
||||
"sm",
|
||||
"js",
|
||||
"crypto"
|
||||
],
|
||||
"jest": {
|
||||
"testEnvironment": "jsdom",
|
||||
"testURL": "https://jest.test"
|
||||
},
|
||||
"author": "june_01",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jsbn": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"jest": "^22.1.4",
|
||||
"webpack": "^3.10.0",
|
||||
"eslint": "^5.3.0",
|
||||
"eslint-config-airbnb-base": "13.1.0",
|
||||
"eslint-plugin-import": "^2.14.0",
|
||||
"eslint-plugin-node": "^7.0.1",
|
||||
"eslint-plugin-promise": "^3.8.0"
|
||||
}
|
||||
}
|
||||
5
node_modules/sm-crypto/src/index.js
generated
vendored
5
node_modules/sm-crypto/src/index.js
generated
vendored
@@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
sm2: require('./sm2/index'),
|
||||
sm3: require('./sm3/index'),
|
||||
sm4: require('./sm4/index'),
|
||||
}
|
||||
161
node_modules/sm-crypto/src/sm2/asn1.js
generated
vendored
161
node_modules/sm-crypto/src/sm2/asn1.js
generated
vendored
@@ -1,161 +0,0 @@
|
||||
/* eslint-disable class-methods-use-this */
|
||||
const {BigInteger} = require('jsbn')
|
||||
|
||||
function bigintToValue(bigint) {
|
||||
let h = bigint.toString(16)
|
||||
if (h[0] !== '-') {
|
||||
// 正数
|
||||
if (h.length % 2 === 1) h = '0' + h // 补齐到整字节
|
||||
else if (!h.match(/^[0-7]/)) h = '00' + h // 非0开头,则补一个全0字节
|
||||
} else {
|
||||
// 负数
|
||||
h = h.substr(1)
|
||||
|
||||
let len = h.length
|
||||
if (len % 2 === 1) len += 1 // 补齐到整字节
|
||||
else if (!h.match(/^[0-7]/)) len += 2 // 非0开头,则补一个全0字节
|
||||
|
||||
let mask = ''
|
||||
for (let i = 0; i < len; i++) mask += 'f'
|
||||
mask = new BigInteger(mask, 16)
|
||||
|
||||
// 对绝对值取反,加1
|
||||
h = mask.xor(bigint).add(BigInteger.ONE)
|
||||
h = h.toString(16).replace(/^-/, '')
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
class ASN1Object {
|
||||
constructor() {
|
||||
this.tlv = null
|
||||
this.t = '00'
|
||||
this.l = '00'
|
||||
this.v = ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 der 编码比特流16进制串
|
||||
*/
|
||||
getEncodedHex() {
|
||||
if (!this.tlv) {
|
||||
this.v = this.getValue()
|
||||
this.l = this.getLength()
|
||||
this.tlv = this.t + this.l + this.v
|
||||
}
|
||||
return this.tlv
|
||||
}
|
||||
|
||||
getLength() {
|
||||
const n = this.v.length / 2 // 字节数
|
||||
let nHex = n.toString(16)
|
||||
if (nHex.length % 2 === 1) nHex = '0' + nHex // 补齐到整字节
|
||||
|
||||
if (n < 128) {
|
||||
// 短格式,以 0 开头
|
||||
return nHex
|
||||
} else {
|
||||
// 长格式,以 1 开头
|
||||
const head = 128 + nHex.length / 2 // 1(1位) + 真正的长度占用字节数(7位) + 真正的长度
|
||||
return head.toString(16) + nHex
|
||||
}
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
class DERInteger extends ASN1Object {
|
||||
constructor(bigint) {
|
||||
super()
|
||||
|
||||
this.t = '02' // 整型标签说明
|
||||
if (bigint) this.v = bigintToValue(bigint)
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.v
|
||||
}
|
||||
}
|
||||
|
||||
class DERSequence extends ASN1Object {
|
||||
constructor(asn1Array) {
|
||||
super()
|
||||
|
||||
this.t = '30' // 序列标签说明
|
||||
this.asn1Array = asn1Array
|
||||
}
|
||||
|
||||
getValue() {
|
||||
this.v = this.asn1Array.map(asn1Object => asn1Object.getEncodedHex()).join('')
|
||||
return this.v
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 l 占用字节数
|
||||
*/
|
||||
function getLenOfL(str, start) {
|
||||
if (+str[start + 2] < 8) return 1 // l 以0开头,则表示短格式,只占一个字节
|
||||
return +str.substr(start + 2, 2) & 0x7f + 1 // 长格式,取第一个字节后7位作为长度真正占用字节数,再加上本身
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 l
|
||||
*/
|
||||
function getL(str, start) {
|
||||
// 获取 l
|
||||
const len = getLenOfL(str, start)
|
||||
const l = str.substr(start + 2, len * 2)
|
||||
|
||||
if (!l) return -1
|
||||
const bigint = +l[0] < 8 ? new BigInteger(l, 16) : new BigInteger(l.substr(2), 16)
|
||||
|
||||
return bigint.intValue()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 v 的位置
|
||||
*/
|
||||
function getStartOfV(str, start) {
|
||||
const len = getLenOfL(str, start)
|
||||
return start + (len + 1) * 2
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* ASN.1 der 编码,针对 sm2 签名
|
||||
*/
|
||||
encodeDer(r, s) {
|
||||
const derR = new DERInteger(r)
|
||||
const derS = new DERInteger(s)
|
||||
const derSeq = new DERSequence([derR, derS])
|
||||
|
||||
return derSeq.getEncodedHex()
|
||||
},
|
||||
|
||||
/**
|
||||
* 解析 ASN.1 der,针对 sm2 验签
|
||||
*/
|
||||
decodeDer(input) {
|
||||
// 结构:
|
||||
// input = | tSeq | lSeq | vSeq |
|
||||
// vSeq = | tR | lR | vR | tS | lS | vS |
|
||||
const start = getStartOfV(input, 0)
|
||||
|
||||
const vIndexR = getStartOfV(input, start)
|
||||
const lR = getL(input, start)
|
||||
const vR = input.substr(vIndexR, lR * 2)
|
||||
|
||||
const nextStart = vIndexR + vR.length
|
||||
const vIndexS = getStartOfV(input, nextStart)
|
||||
const lS = getL(input, nextStart)
|
||||
const vS = input.substr(vIndexS, lS * 2)
|
||||
|
||||
const r = new BigInteger(vR, 16)
|
||||
const s = new BigInteger(vS, 16)
|
||||
|
||||
return {r, s}
|
||||
}
|
||||
}
|
||||
332
node_modules/sm-crypto/src/sm2/ec.js
generated
vendored
332
node_modules/sm-crypto/src/sm2/ec.js
generated
vendored
@@ -1,332 +0,0 @@
|
||||
/* eslint-disable no-case-declarations, max-len */
|
||||
const {BigInteger} = require('jsbn')
|
||||
|
||||
/**
|
||||
* thanks for Tom Wu : http://www-cs-students.stanford.edu/~tjw/jsbn/
|
||||
*
|
||||
* Basic Javascript Elliptic Curve implementation
|
||||
* Ported loosely from BouncyCastle's Java EC code
|
||||
* Only Fp curves implemented for now
|
||||
*/
|
||||
|
||||
const TWO = new BigInteger('2')
|
||||
const THREE = new BigInteger('3')
|
||||
|
||||
/**
|
||||
* 椭圆曲线域元素
|
||||
*/
|
||||
class ECFieldElementFp {
|
||||
constructor(q, x) {
|
||||
this.x = x
|
||||
this.q = q
|
||||
// TODO if (x.compareTo(q) >= 0) error
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断相等
|
||||
*/
|
||||
equals(other) {
|
||||
if (other === this) return true
|
||||
return (this.q.equals(other.q) && this.x.equals(other.x))
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回具体数值
|
||||
*/
|
||||
toBigInteger() {
|
||||
return this.x
|
||||
}
|
||||
|
||||
/**
|
||||
* 取反
|
||||
*/
|
||||
negate() {
|
||||
return new ECFieldElementFp(this.q, this.x.negate().mod(this.q))
|
||||
}
|
||||
|
||||
/**
|
||||
* 相加
|
||||
*/
|
||||
add(b) {
|
||||
return new ECFieldElementFp(this.q, this.x.add(b.toBigInteger()).mod(this.q))
|
||||
}
|
||||
|
||||
/**
|
||||
* 相减
|
||||
*/
|
||||
subtract(b) {
|
||||
return new ECFieldElementFp(this.q, this.x.subtract(b.toBigInteger()).mod(this.q))
|
||||
}
|
||||
|
||||
/**
|
||||
* 相乘
|
||||
*/
|
||||
multiply(b) {
|
||||
return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger()).mod(this.q))
|
||||
}
|
||||
|
||||
/**
|
||||
* 相除
|
||||
*/
|
||||
divide(b) {
|
||||
return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger().modInverse(this.q)).mod(this.q))
|
||||
}
|
||||
|
||||
/**
|
||||
* 平方
|
||||
*/
|
||||
square() {
|
||||
return new ECFieldElementFp(this.q, this.x.square().mod(this.q))
|
||||
}
|
||||
}
|
||||
|
||||
class ECPointFp {
|
||||
constructor(curve, x, y, z) {
|
||||
this.curve = curve
|
||||
this.x = x
|
||||
this.y = y
|
||||
// 标准射影坐标系:zinv == null 或 z * zinv == 1
|
||||
this.z = z == null ? BigInteger.ONE : z
|
||||
this.zinv = null
|
||||
// TODO: compression flag
|
||||
}
|
||||
|
||||
getX() {
|
||||
if (this.zinv === null) this.zinv = this.z.modInverse(this.curve.q)
|
||||
|
||||
return this.curve.fromBigInteger(this.x.toBigInteger().multiply(this.zinv).mod(this.curve.q))
|
||||
}
|
||||
|
||||
getY() {
|
||||
if (this.zinv === null) this.zinv = this.z.modInverse(this.curve.q)
|
||||
|
||||
return this.curve.fromBigInteger(this.y.toBigInteger().multiply(this.zinv).mod(this.curve.q))
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断相等
|
||||
*/
|
||||
equals(other) {
|
||||
if (other === this) return true
|
||||
if (this.isInfinity()) return other.isInfinity()
|
||||
if (other.isInfinity()) return this.isInfinity()
|
||||
|
||||
// u = y2 * z1 - y1 * z2
|
||||
const u = other.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(other.z)).mod(this.curve.q)
|
||||
if (!u.equals(BigInteger.ZERO)) return false
|
||||
|
||||
// v = x2 * z1 - x1 * z2
|
||||
const v = other.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(other.z)).mod(this.curve.q)
|
||||
return v.equals(BigInteger.ZERO)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是无穷远点
|
||||
*/
|
||||
isInfinity() {
|
||||
if ((this.x === null) && (this.y === null)) return true
|
||||
return this.z.equals(BigInteger.ZERO) && !this.y.toBigInteger().equals(BigInteger.ZERO)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取反,x 轴对称点
|
||||
*/
|
||||
negate() {
|
||||
return new ECPointFp(this.curve, this.x, this.y.negate(), this.z)
|
||||
}
|
||||
|
||||
/**
|
||||
* 相加
|
||||
*
|
||||
* 标准射影坐标系:
|
||||
*
|
||||
* λ1 = x1 * z2
|
||||
* λ2 = x2 * z1
|
||||
* λ3 = λ1 − λ2
|
||||
* λ4 = y1 * z2
|
||||
* λ5 = y2 * z1
|
||||
* λ6 = λ4 − λ5
|
||||
* λ7 = λ1 + λ2
|
||||
* λ8 = z1 * z2
|
||||
* λ9 = λ3^2
|
||||
* λ10 = λ3 * λ9
|
||||
* λ11 = λ8 * λ6^2 − λ7 * λ9
|
||||
* x3 = λ3 * λ11
|
||||
* y3 = λ6 * (λ9 * λ1 − λ11) − λ4 * λ10
|
||||
* z3 = λ10 * λ8
|
||||
*/
|
||||
add(b) {
|
||||
if (this.isInfinity()) return b
|
||||
if (b.isInfinity()) return this
|
||||
|
||||
const x1 = this.x.toBigInteger()
|
||||
const y1 = this.y.toBigInteger()
|
||||
const z1 = this.z
|
||||
const x2 = b.x.toBigInteger()
|
||||
const y2 = b.y.toBigInteger()
|
||||
const z2 = b.z
|
||||
const q = this.curve.q
|
||||
|
||||
const w1 = x1.multiply(z2).mod(q)
|
||||
const w2 = x2.multiply(z1).mod(q)
|
||||
const w3 = w1.subtract(w2)
|
||||
const w4 = y1.multiply(z2).mod(q)
|
||||
const w5 = y2.multiply(z1).mod(q)
|
||||
const w6 = w4.subtract(w5)
|
||||
|
||||
if (BigInteger.ZERO.equals(w3)) {
|
||||
if (BigInteger.ZERO.equals(w6)) {
|
||||
return this.twice() // this == b,计算自加
|
||||
}
|
||||
return this.curve.infinity // this == -b,则返回无穷远点
|
||||
}
|
||||
|
||||
const w7 = w1.add(w2)
|
||||
const w8 = z1.multiply(z2).mod(q)
|
||||
const w9 = w3.square().mod(q)
|
||||
const w10 = w3.multiply(w9).mod(q)
|
||||
const w11 = w8.multiply(w6.square()).subtract(w7.multiply(w9)).mod(q)
|
||||
|
||||
const x3 = w3.multiply(w11).mod(q)
|
||||
const y3 = w6.multiply(w9.multiply(w1).subtract(w11)).subtract(w4.multiply(w10)).mod(q)
|
||||
const z3 = w10.multiply(w8).mod(q)
|
||||
|
||||
return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3)
|
||||
}
|
||||
|
||||
/**
|
||||
* 自加
|
||||
*
|
||||
* 标准射影坐标系:
|
||||
*
|
||||
* λ1 = 3 * x1^2 + a * z1^2
|
||||
* λ2 = 2 * y1 * z1
|
||||
* λ3 = y1^2
|
||||
* λ4 = λ3 * x1 * z1
|
||||
* λ5 = λ2^2
|
||||
* λ6 = λ1^2 − 8 * λ4
|
||||
* x3 = λ2 * λ6
|
||||
* y3 = λ1 * (4 * λ4 − λ6) − 2 * λ5 * λ3
|
||||
* z3 = λ2 * λ5
|
||||
*/
|
||||
twice() {
|
||||
if (this.isInfinity()) return this
|
||||
if (!this.y.toBigInteger().signum()) return this.curve.infinity
|
||||
|
||||
const x1 = this.x.toBigInteger()
|
||||
const y1 = this.y.toBigInteger()
|
||||
const z1 = this.z
|
||||
const q = this.curve.q
|
||||
const a = this.curve.a.toBigInteger()
|
||||
|
||||
const w1 = x1.square().multiply(THREE).add(a.multiply(z1.square())).mod(q)
|
||||
const w2 = y1.shiftLeft(1).multiply(z1).mod(q)
|
||||
const w3 = y1.square().mod(q)
|
||||
const w4 = w3.multiply(x1).multiply(z1).mod(q)
|
||||
const w5 = w2.square().mod(q)
|
||||
const w6 = w1.square().subtract(w4.shiftLeft(3)).mod(q)
|
||||
|
||||
const x3 = w2.multiply(w6).mod(q)
|
||||
const y3 = w1.multiply(w4.shiftLeft(2).subtract(w6)).subtract(w5.shiftLeft(1).multiply(w3)).mod(q)
|
||||
const z3 = w2.multiply(w5).mod(q)
|
||||
|
||||
return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3)
|
||||
}
|
||||
|
||||
/**
|
||||
* 倍点计算
|
||||
*/
|
||||
multiply(k) {
|
||||
if (this.isInfinity()) return this
|
||||
if (!k.signum()) return this.curve.infinity
|
||||
|
||||
// 使用加减法
|
||||
const k3 = k.multiply(THREE)
|
||||
const neg = this.negate()
|
||||
let Q = this
|
||||
|
||||
for (let i = k3.bitLength() - 2; i > 0; i--) {
|
||||
Q = Q.twice()
|
||||
|
||||
const k3Bit = k3.testBit(i)
|
||||
const kBit = k.testBit(i)
|
||||
|
||||
if (k3Bit !== kBit) {
|
||||
Q = Q.add(k3Bit ? this : neg)
|
||||
}
|
||||
}
|
||||
|
||||
return Q
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 椭圆曲线 y^2 = x^3 + ax + b
|
||||
*/
|
||||
class ECCurveFp {
|
||||
constructor(q, a, b) {
|
||||
this.q = q
|
||||
this.a = this.fromBigInteger(a)
|
||||
this.b = this.fromBigInteger(b)
|
||||
this.infinity = new ECPointFp(this, null, null) // 无穷远点
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断两个椭圆曲线是否相等
|
||||
*/
|
||||
equals(other) {
|
||||
if (other === this) return true
|
||||
return (this.q.equals(other.q) && this.a.equals(other.a) && this.b.equals(other.b))
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成椭圆曲线域元素
|
||||
*/
|
||||
fromBigInteger(x) {
|
||||
return new ECFieldElementFp(this.q, x)
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 16 进制串为椭圆曲线点
|
||||
*/
|
||||
decodePointHex(s) {
|
||||
switch (parseInt(s.substr(0, 2), 16)) {
|
||||
// 第一个字节
|
||||
case 0:
|
||||
return this.infinity
|
||||
case 2:
|
||||
case 3:
|
||||
// 压缩
|
||||
const x = this.fromBigInteger(new BigInteger(s.substr(2), 16))
|
||||
// 对 p ≡ 3 (mod4),即存在正整数 u,使得 p = 4u + 3
|
||||
// 计算 y = (√ (x^3 + ax + b) % p)^(u + 1) modp
|
||||
let y = this.fromBigInteger(x.multiply(x.square()).add(
|
||||
x.multiply(this.a)
|
||||
).add(this.b).toBigInteger()
|
||||
.modPow(
|
||||
this.q.divide(new BigInteger('4')).add(BigInteger.ONE), this.q
|
||||
))
|
||||
// 算出结果 2 进制最后 1 位不等于第 1 个字节减 2 则取反
|
||||
if (!y.toBigInteger().mod(TWO).equals(new BigInteger(s.substr(0, 2), 16).subtract(TWO))) {
|
||||
y = y.negate()
|
||||
}
|
||||
return new ECPointFp(this, x, y)
|
||||
case 4:
|
||||
case 6:
|
||||
case 7:
|
||||
const len = (s.length - 2) / 2
|
||||
const xHex = s.substr(2, len)
|
||||
const yHex = s.substr(len + 2, len)
|
||||
|
||||
return new ECPointFp(this, this.fromBigInteger(new BigInteger(xHex, 16)), this.fromBigInteger(new BigInteger(yHex, 16)))
|
||||
default:
|
||||
// 不支持
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ECPointFp,
|
||||
ECCurveFp,
|
||||
}
|
||||
261
node_modules/sm-crypto/src/sm2/index.js
generated
vendored
261
node_modules/sm-crypto/src/sm2/index.js
generated
vendored
@@ -1,261 +0,0 @@
|
||||
/* eslint-disable no-use-before-define */
|
||||
const {BigInteger} = require('jsbn')
|
||||
const {encodeDer, decodeDer} = require('./asn1')
|
||||
const _ = require('./utils')
|
||||
const sm3 = require('./sm3').sm3
|
||||
|
||||
const {G, curve, n} = _.generateEcparam()
|
||||
const C1C2C3 = 0
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*/
|
||||
function doEncrypt(msg, publicKey, cipherMode = 1) {
|
||||
msg = typeof msg === 'string' ? _.hexToArray(_.utf8ToHex(msg)) : Array.prototype.slice.call(msg)
|
||||
publicKey = _.getGlobalCurve().decodePointHex(publicKey) // 先将公钥转成点
|
||||
|
||||
const keypair = _.generateKeyPairHex()
|
||||
const k = new BigInteger(keypair.privateKey, 16) // 随机数 k
|
||||
|
||||
// c1 = k * G
|
||||
let c1 = keypair.publicKey
|
||||
if (c1.length > 128) c1 = c1.substr(c1.length - 128)
|
||||
|
||||
// (x2, y2) = k * publicKey
|
||||
const p = publicKey.multiply(k)
|
||||
const x2 = _.hexToArray(_.leftPad(p.getX().toBigInteger().toRadix(16), 64))
|
||||
const y2 = _.hexToArray(_.leftPad(p.getY().toBigInteger().toRadix(16), 64))
|
||||
|
||||
// c3 = hash(x2 || msg || y2)
|
||||
const c3 = _.arrayToHex(sm3([].concat(x2, msg, y2)))
|
||||
|
||||
let ct = 1
|
||||
let offset = 0
|
||||
let t = [] // 256 位
|
||||
const z = [].concat(x2, y2)
|
||||
const nextT = () => {
|
||||
// (1) Hai = hash(z || ct)
|
||||
// (2) ct++
|
||||
t = sm3([...z, ct >> 24 & 0x00ff, ct >> 16 & 0x00ff, ct >> 8 & 0x00ff, ct & 0x00ff])
|
||||
ct++
|
||||
offset = 0
|
||||
}
|
||||
nextT() // 先生成 Ha1
|
||||
|
||||
for (let i = 0, len = msg.length; i < len; i++) {
|
||||
// t = Ha1 || Ha2 || Ha3 || Ha4
|
||||
if (offset === t.length) nextT()
|
||||
|
||||
// c2 = msg ^ t
|
||||
msg[i] ^= t[offset++] & 0xff
|
||||
}
|
||||
const c2 = _.arrayToHex(msg)
|
||||
|
||||
return cipherMode === C1C2C3 ? c1 + c2 + c3 : c1 + c3 + c2
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密
|
||||
*/
|
||||
function doDecrypt(encryptData, privateKey, cipherMode = 1, {
|
||||
output = 'string',
|
||||
} = {}) {
|
||||
privateKey = new BigInteger(privateKey, 16)
|
||||
|
||||
let c3 = encryptData.substr(128, 64)
|
||||
let c2 = encryptData.substr(128 + 64)
|
||||
|
||||
if (cipherMode === C1C2C3) {
|
||||
c3 = encryptData.substr(encryptData.length - 64)
|
||||
c2 = encryptData.substr(128, encryptData.length - 128 - 64)
|
||||
}
|
||||
|
||||
const msg = _.hexToArray(c2)
|
||||
const c1 = _.getGlobalCurve().decodePointHex('04' + encryptData.substr(0, 128))
|
||||
|
||||
const p = c1.multiply(privateKey)
|
||||
const x2 = _.hexToArray(_.leftPad(p.getX().toBigInteger().toRadix(16), 64))
|
||||
const y2 = _.hexToArray(_.leftPad(p.getY().toBigInteger().toRadix(16), 64))
|
||||
|
||||
let ct = 1
|
||||
let offset = 0
|
||||
let t = [] // 256 位
|
||||
const z = [].concat(x2, y2)
|
||||
const nextT = () => {
|
||||
// (1) Hai = hash(z || ct)
|
||||
// (2) ct++
|
||||
t = sm3([...z, ct >> 24 & 0x00ff, ct >> 16 & 0x00ff, ct >> 8 & 0x00ff, ct & 0x00ff])
|
||||
ct++
|
||||
offset = 0
|
||||
}
|
||||
nextT() // 先生成 Ha1
|
||||
|
||||
for (let i = 0, len = msg.length; i < len; i++) {
|
||||
// t = Ha1 || Ha2 || Ha3 || Ha4
|
||||
if (offset === t.length) nextT()
|
||||
|
||||
// c2 = msg ^ t
|
||||
msg[i] ^= t[offset++] & 0xff
|
||||
}
|
||||
|
||||
// c3 = hash(x2 || msg || y2)
|
||||
const checkC3 = _.arrayToHex(sm3([].concat(x2, msg, y2)))
|
||||
|
||||
if (checkC3 === c3.toLowerCase()) {
|
||||
return output === 'array' ? msg : _.arrayToUtf8(msg)
|
||||
} else {
|
||||
return output === 'array' ? [] : ''
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 签名
|
||||
*/
|
||||
function doSignature(msg, privateKey, {
|
||||
pointPool, der, hash, publicKey, userId
|
||||
} = {}) {
|
||||
let hashHex = typeof msg === 'string' ? _.utf8ToHex(msg) : _.arrayToHex(msg)
|
||||
|
||||
if (hash) {
|
||||
// sm3杂凑
|
||||
publicKey = publicKey || getPublicKeyFromPrivateKey(privateKey)
|
||||
hashHex = getHash(hashHex, publicKey, userId)
|
||||
}
|
||||
|
||||
const dA = new BigInteger(privateKey, 16)
|
||||
const e = new BigInteger(hashHex, 16)
|
||||
|
||||
// k
|
||||
let k = null
|
||||
let r = null
|
||||
let s = null
|
||||
|
||||
do {
|
||||
do {
|
||||
let point
|
||||
if (pointPool && pointPool.length) {
|
||||
point = pointPool.pop()
|
||||
} else {
|
||||
point = getPoint()
|
||||
}
|
||||
k = point.k
|
||||
|
||||
// r = (e + x1) mod n
|
||||
r = e.add(point.x1).mod(n)
|
||||
} while (r.equals(BigInteger.ZERO) || r.add(k).equals(n))
|
||||
|
||||
// s = ((1 + dA)^-1 * (k - r * dA)) mod n
|
||||
s = dA.add(BigInteger.ONE).modInverse(n).multiply(k.subtract(r.multiply(dA))).mod(n)
|
||||
} while (s.equals(BigInteger.ZERO))
|
||||
|
||||
if (der) return encodeDer(r, s) // asn.1 der 编码
|
||||
|
||||
return _.leftPad(r.toString(16), 64) + _.leftPad(s.toString(16), 64)
|
||||
}
|
||||
|
||||
/**
|
||||
* 验签
|
||||
*/
|
||||
function doVerifySignature(msg, signHex, publicKey, {der, hash, userId} = {}) {
|
||||
let hashHex = typeof msg === 'string' ? _.utf8ToHex(msg) : _.arrayToHex(msg)
|
||||
|
||||
if (hash) {
|
||||
// sm3杂凑
|
||||
hashHex = getHash(hashHex, publicKey, userId)
|
||||
}
|
||||
|
||||
let r; let
|
||||
s
|
||||
if (der) {
|
||||
const decodeDerObj = decodeDer(signHex) // asn.1 der 解码
|
||||
r = decodeDerObj.r
|
||||
s = decodeDerObj.s
|
||||
} else {
|
||||
r = new BigInteger(signHex.substring(0, 64), 16)
|
||||
s = new BigInteger(signHex.substring(64), 16)
|
||||
}
|
||||
|
||||
const PA = curve.decodePointHex(publicKey)
|
||||
const e = new BigInteger(hashHex, 16)
|
||||
|
||||
// t = (r + s) mod n
|
||||
const t = r.add(s).mod(n)
|
||||
|
||||
if (t.equals(BigInteger.ZERO)) return false
|
||||
|
||||
// x1y1 = s * G + t * PA
|
||||
const x1y1 = G.multiply(s).add(PA.multiply(t))
|
||||
|
||||
// R = (e + x1) mod n
|
||||
const R = e.add(x1y1.getX().toBigInteger()).mod(n)
|
||||
|
||||
return r.equals(R)
|
||||
}
|
||||
|
||||
/**
|
||||
* sm3杂凑算法
|
||||
*/
|
||||
function getHash(hashHex, publicKey, userId = '1234567812345678') {
|
||||
// z = hash(entl || userId || a || b || gx || gy || px || py)
|
||||
userId = _.utf8ToHex(userId)
|
||||
const a = _.leftPad(G.curve.a.toBigInteger().toRadix(16), 64)
|
||||
const b = _.leftPad(G.curve.b.toBigInteger().toRadix(16), 64)
|
||||
const gx = _.leftPad(G.getX().toBigInteger().toRadix(16), 64)
|
||||
const gy = _.leftPad(G.getY().toBigInteger().toRadix(16), 64)
|
||||
let px
|
||||
let py
|
||||
if (publicKey.length === 128) {
|
||||
px = publicKey.substr(0, 64)
|
||||
py = publicKey.substr(64, 64)
|
||||
} else {
|
||||
const point = G.curve.decodePointHex(publicKey)
|
||||
px = _.leftPad(point.getX().toBigInteger().toRadix(16), 64)
|
||||
py = _.leftPad(point.getY().toBigInteger().toRadix(16), 64)
|
||||
}
|
||||
const data = _.hexToArray(userId + a + b + gx + gy + px + py)
|
||||
|
||||
const entl = userId.length * 4
|
||||
data.unshift(entl & 0x00ff)
|
||||
data.unshift(entl >> 8 & 0x00ff)
|
||||
|
||||
const z = sm3(data)
|
||||
|
||||
// e = hash(z || msg)
|
||||
return _.arrayToHex(sm3(z.concat(_.hexToArray(hashHex))))
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算公钥
|
||||
*/
|
||||
function getPublicKeyFromPrivateKey(privateKey) {
|
||||
const PA = G.multiply(new BigInteger(privateKey, 16))
|
||||
const x = _.leftPad(PA.getX().toBigInteger().toString(16), 64)
|
||||
const y = _.leftPad(PA.getY().toBigInteger().toString(16), 64)
|
||||
return '04' + x + y
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取椭圆曲线点
|
||||
*/
|
||||
function getPoint() {
|
||||
const keypair = _.generateKeyPairHex()
|
||||
const PA = curve.decodePointHex(keypair.publicKey)
|
||||
|
||||
keypair.k = new BigInteger(keypair.privateKey, 16)
|
||||
keypair.x1 = PA.getX().toBigInteger()
|
||||
|
||||
return keypair
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generateKeyPairHex: _.generateKeyPairHex,
|
||||
compressPublicKeyHex: _.compressPublicKeyHex,
|
||||
comparePublicKeyHex: _.comparePublicKeyHex,
|
||||
doEncrypt,
|
||||
doDecrypt,
|
||||
doSignature,
|
||||
doVerifySignature,
|
||||
getPublicKeyFromPrivateKey,
|
||||
getPoint,
|
||||
verifyPublicKey: _.verifyPublicKey,
|
||||
}
|
||||
170
node_modules/sm-crypto/src/sm2/sm3.js
generated
vendored
170
node_modules/sm-crypto/src/sm2/sm3.js
generated
vendored
@@ -1,170 +0,0 @@
|
||||
// 消息扩展
|
||||
const W = new Uint32Array(68)
|
||||
const M = new Uint32Array(64) // W'
|
||||
|
||||
/**
|
||||
* 循环左移
|
||||
*/
|
||||
function rotl(x, n) {
|
||||
const s = n & 31
|
||||
return (x << s) | (x >>> (32 - s))
|
||||
}
|
||||
|
||||
/**
|
||||
* 二进制异或运算
|
||||
*/
|
||||
function xor(x, y) {
|
||||
const result = []
|
||||
for (let i = x.length - 1; i >= 0; i--) result[i] = (x[i] ^ y[i]) & 0xff
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩函数中的置换函数 P0(X) = X xor (X <<< 9) xor (X <<< 17)
|
||||
*/
|
||||
function P0(X) {
|
||||
return (X ^ rotl(X, 9)) ^ rotl(X, 17)
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息扩展中的置换函数 P1(X) = X xor (X <<< 15) xor (X <<< 23)
|
||||
*/
|
||||
function P1(X) {
|
||||
return (X ^ rotl(X, 15)) ^ rotl(X, 23)
|
||||
}
|
||||
|
||||
/**
|
||||
* sm3 本体
|
||||
*/
|
||||
function sm3(array) {
|
||||
let len = array.length * 8
|
||||
|
||||
// k 是满足 len + 1 + k = 448mod512 的最小的非负整数
|
||||
let k = len % 512
|
||||
// 如果 448 <= (512 % len) < 512,需要多补充 (len % 448) 比特'0'以满足总比特长度为512的倍数
|
||||
k = k >= 448 ? 512 - (k % 448) - 1 : 448 - k - 1
|
||||
|
||||
// 填充
|
||||
const kArr = new Array((k - 7) / 8)
|
||||
const lenArr = new Array(8)
|
||||
for (let i = 0, len = kArr.length; i < len; i++) kArr[i] = 0
|
||||
for (let i = 0, len = lenArr.length; i < len; i++) lenArr[i] = 0
|
||||
len = len.toString(2)
|
||||
for (let i = 7; i >= 0; i--) {
|
||||
if (len.length > 8) {
|
||||
const start = len.length - 8
|
||||
lenArr[i] = parseInt(len.substr(start), 2)
|
||||
len = len.substr(0, start)
|
||||
} else if (len.length > 0) {
|
||||
lenArr[i] = parseInt(len, 2)
|
||||
len = ''
|
||||
}
|
||||
}
|
||||
const m = new Uint8Array([...array, 0x80, ...kArr, ...lenArr])
|
||||
const dataView = new DataView(m.buffer, 0)
|
||||
|
||||
// 迭代压缩
|
||||
const n = m.length / 64
|
||||
const V = new Uint32Array([0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e])
|
||||
for (let i = 0; i < n; i++) {
|
||||
W.fill(0)
|
||||
M.fill(0)
|
||||
|
||||
// 将消息分组B划分为 16 个字 W0, W1,……,W15
|
||||
const start = 16 * i
|
||||
for (let j = 0; j < 16; j++) {
|
||||
W[j] = dataView.getUint32((start + j) * 4, false)
|
||||
}
|
||||
|
||||
// W16 ~ W67:W[j] <- P1(W[j−16] xor W[j−9] xor (W[j−3] <<< 15)) xor (W[j−13] <<< 7) xor W[j−6]
|
||||
for (let j = 16; j < 68; j++) {
|
||||
W[j] = (P1((W[j - 16] ^ W[j - 9]) ^ rotl(W[j - 3], 15)) ^ rotl(W[j - 13], 7)) ^ W[j - 6]
|
||||
}
|
||||
|
||||
// W′0 ~ W′63:W′[j] = W[j] xor W[j+4]
|
||||
for (let j = 0; j < 64; j++) {
|
||||
M[j] = W[j] ^ W[j + 4]
|
||||
}
|
||||
|
||||
// 压缩
|
||||
const T1 = 0x79cc4519
|
||||
const T2 = 0x7a879d8a
|
||||
// 字寄存器
|
||||
let A = V[0]
|
||||
let B = V[1]
|
||||
let C = V[2]
|
||||
let D = V[3]
|
||||
let E = V[4]
|
||||
let F = V[5]
|
||||
let G = V[6]
|
||||
let H = V[7]
|
||||
// 中间变量
|
||||
let SS1
|
||||
let SS2
|
||||
let TT1
|
||||
let TT2
|
||||
let T
|
||||
for (let j = 0; j < 64; j++) {
|
||||
T = j >= 0 && j <= 15 ? T1 : T2
|
||||
SS1 = rotl(rotl(A, 12) + E + rotl(T, j), 7)
|
||||
SS2 = SS1 ^ rotl(A, 12)
|
||||
|
||||
TT1 = (j >= 0 && j <= 15 ? ((A ^ B) ^ C) : (((A & B) | (A & C)) | (B & C))) + D + SS2 + M[j]
|
||||
TT2 = (j >= 0 && j <= 15 ? ((E ^ F) ^ G) : ((E & F) | ((~E) & G))) + H + SS1 + W[j]
|
||||
|
||||
D = C
|
||||
C = rotl(B, 9)
|
||||
B = A
|
||||
A = TT1
|
||||
H = G
|
||||
G = rotl(F, 19)
|
||||
F = E
|
||||
E = P0(TT2)
|
||||
}
|
||||
|
||||
V[0] ^= A
|
||||
V[1] ^= B
|
||||
V[2] ^= C
|
||||
V[3] ^= D
|
||||
V[4] ^= E
|
||||
V[5] ^= F
|
||||
V[6] ^= G
|
||||
V[7] ^= H
|
||||
}
|
||||
|
||||
// 转回 uint8
|
||||
const result = []
|
||||
for (let i = 0, len = V.length; i < len; i++) {
|
||||
const word = V[i]
|
||||
result.push((word & 0xff000000) >>> 24, (word & 0xff0000) >>> 16, (word & 0xff00) >>> 8, word & 0xff)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* hmac 实现
|
||||
*/
|
||||
const blockLen = 64
|
||||
const iPad = new Uint8Array(blockLen)
|
||||
const oPad = new Uint8Array(blockLen)
|
||||
for (let i = 0; i < blockLen; i++) {
|
||||
iPad[i] = 0x36
|
||||
oPad[i] = 0x5c
|
||||
}
|
||||
function hmac(input, key) {
|
||||
// 密钥填充
|
||||
if (key.length > blockLen) key = sm3(key)
|
||||
while (key.length < blockLen) key.push(0)
|
||||
|
||||
const iPadKey = xor(key, iPad)
|
||||
const oPadKey = xor(key, oPad)
|
||||
|
||||
const hash = sm3([...iPadKey, ...input])
|
||||
return sm3([...oPadKey, ...hash])
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sm3,
|
||||
hmac,
|
||||
}
|
||||
194
node_modules/sm-crypto/src/sm2/utils.js
generated
vendored
194
node_modules/sm-crypto/src/sm2/utils.js
generated
vendored
@@ -1,194 +0,0 @@
|
||||
/* eslint-disable no-bitwise, no-mixed-operators, no-use-before-define, max-len */
|
||||
const {BigInteger, SecureRandom} = require('jsbn')
|
||||
const {ECCurveFp} = require('./ec')
|
||||
|
||||
const rng = new SecureRandom()
|
||||
const {curve, G, n} = generateEcparam()
|
||||
|
||||
/**
|
||||
* 获取公共椭圆曲线
|
||||
*/
|
||||
function getGlobalCurve() {
|
||||
return curve
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成ecparam
|
||||
*/
|
||||
function generateEcparam() {
|
||||
// 椭圆曲线
|
||||
const p = new BigInteger('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 16)
|
||||
const a = new BigInteger('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', 16)
|
||||
const b = new BigInteger('28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93', 16)
|
||||
const curve = new ECCurveFp(p, a, b)
|
||||
|
||||
// 基点
|
||||
const gxHex = '32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7'
|
||||
const gyHex = 'BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0'
|
||||
const G = curve.decodePointHex('04' + gxHex + gyHex)
|
||||
|
||||
const n = new BigInteger('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123', 16)
|
||||
|
||||
return {curve, G, n}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成密钥对:publicKey = privateKey * G
|
||||
*/
|
||||
function generateKeyPairHex(a, b, c) {
|
||||
const random = a ? new BigInteger(a, b, c) : new BigInteger(n.bitLength(), rng)
|
||||
const d = random.mod(n.subtract(BigInteger.ONE)).add(BigInteger.ONE) // 随机数
|
||||
const privateKey = leftPad(d.toString(16), 64)
|
||||
|
||||
const P = G.multiply(d) // P = dG,p 为公钥,d 为私钥
|
||||
const Px = leftPad(P.getX().toBigInteger().toString(16), 64)
|
||||
const Py = leftPad(P.getY().toBigInteger().toString(16), 64)
|
||||
const publicKey = '04' + Px + Py
|
||||
|
||||
return {privateKey, publicKey}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成压缩公钥
|
||||
*/
|
||||
function compressPublicKeyHex(s) {
|
||||
if (s.length !== 130) throw new Error('Invalid public key to compress')
|
||||
|
||||
const len = (s.length - 2) / 2
|
||||
const xHex = s.substr(2, len)
|
||||
const y = new BigInteger(s.substr(len + 2, len), 16)
|
||||
|
||||
let prefix = '03'
|
||||
if (y.mod(new BigInteger('2')).equals(BigInteger.ZERO)) prefix = '02'
|
||||
|
||||
return prefix + xHex
|
||||
}
|
||||
|
||||
/**
|
||||
* utf8串转16进制串
|
||||
*/
|
||||
function utf8ToHex(input) {
|
||||
input = unescape(encodeURIComponent(input))
|
||||
|
||||
const length = input.length
|
||||
|
||||
// 转换到字数组
|
||||
const words = []
|
||||
for (let i = 0; i < length; i++) {
|
||||
words[i >>> 2] |= (input.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8)
|
||||
}
|
||||
|
||||
// 转换到16进制
|
||||
const hexChars = []
|
||||
for (let i = 0; i < length; i++) {
|
||||
const bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff
|
||||
hexChars.push((bite >>> 4).toString(16))
|
||||
hexChars.push((bite & 0x0f).toString(16))
|
||||
}
|
||||
|
||||
return hexChars.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* 补全16进制字符串
|
||||
*/
|
||||
function leftPad(input, num) {
|
||||
if (input.length >= num) return input
|
||||
|
||||
return (new Array(num - input.length + 1)).join('0') + input
|
||||
}
|
||||
|
||||
/**
|
||||
* 转成16进制串
|
||||
*/
|
||||
function arrayToHex(arr) {
|
||||
return arr.map(item => {
|
||||
item = item.toString(16)
|
||||
return item.length === 1 ? '0' + item : item
|
||||
}).join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* 转成utf8串
|
||||
*/
|
||||
function arrayToUtf8(arr) {
|
||||
const words = []
|
||||
let j = 0
|
||||
for (let i = 0; i < arr.length * 2; i += 2) {
|
||||
words[i >>> 3] |= parseInt(arr[j], 10) << (24 - (i % 8) * 4)
|
||||
j++
|
||||
}
|
||||
|
||||
try {
|
||||
const latin1Chars = []
|
||||
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff
|
||||
latin1Chars.push(String.fromCharCode(bite))
|
||||
}
|
||||
|
||||
return decodeURIComponent(escape(latin1Chars.join('')))
|
||||
} catch (e) {
|
||||
throw new Error('Malformed UTF-8 data')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转成字节数组
|
||||
*/
|
||||
function hexToArray(hexStr) {
|
||||
const words = []
|
||||
let hexStrLength = hexStr.length
|
||||
|
||||
if (hexStrLength % 2 !== 0) {
|
||||
hexStr = leftPad(hexStr, hexStrLength + 1)
|
||||
}
|
||||
|
||||
hexStrLength = hexStr.length
|
||||
|
||||
for (let i = 0; i < hexStrLength; i += 2) {
|
||||
words.push(parseInt(hexStr.substr(i, 2), 16))
|
||||
}
|
||||
return words
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证公钥是否为椭圆曲线上的点
|
||||
*/
|
||||
function verifyPublicKey(publicKey) {
|
||||
const point = curve.decodePointHex(publicKey)
|
||||
if (!point) return false
|
||||
|
||||
const x = point.getX()
|
||||
const y = point.getY()
|
||||
|
||||
// 验证 y^2 是否等于 x^3 + ax + b
|
||||
return y.square().equals(x.multiply(x.square()).add(x.multiply(curve.a)).add(curve.b))
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证公钥是否等价,等价返回true
|
||||
*/
|
||||
function comparePublicKeyHex(publicKey1, publicKey2) {
|
||||
const point1 = curve.decodePointHex(publicKey1)
|
||||
if (!point1) return false
|
||||
|
||||
const point2 = curve.decodePointHex(publicKey2)
|
||||
if (!point2) return false
|
||||
|
||||
return point1.equals(point2)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getGlobalCurve,
|
||||
generateEcparam,
|
||||
generateKeyPairHex,
|
||||
compressPublicKeyHex,
|
||||
utf8ToHex,
|
||||
leftPad,
|
||||
arrayToHex,
|
||||
arrayToUtf8,
|
||||
hexToArray,
|
||||
verifyPublicKey,
|
||||
comparePublicKeyHex,
|
||||
}
|
||||
94
node_modules/sm-crypto/src/sm3/index.js
generated
vendored
94
node_modules/sm-crypto/src/sm3/index.js
generated
vendored
@@ -1,94 +0,0 @@
|
||||
const {sm3, hmac} = require('../sm2/sm3')
|
||||
|
||||
/**
|
||||
* 补全16进制字符串
|
||||
*/
|
||||
function leftPad(input, num) {
|
||||
if (input.length >= num) return input
|
||||
|
||||
return (new Array(num - input.length + 1)).join('0') + input
|
||||
}
|
||||
|
||||
/**
|
||||
* 字节数组转 16 进制串
|
||||
*/
|
||||
function ArrayToHex(arr) {
|
||||
return arr.map(item => {
|
||||
item = item.toString(16)
|
||||
return item.length === 1 ? '0' + item : item
|
||||
}).join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* 转成字节数组
|
||||
*/
|
||||
function hexToArray(hexStr) {
|
||||
const words = []
|
||||
let hexStrLength = hexStr.length
|
||||
|
||||
if (hexStrLength % 2 !== 0) {
|
||||
hexStr = leftPad(hexStr, hexStrLength + 1)
|
||||
}
|
||||
|
||||
hexStrLength = hexStr.length
|
||||
|
||||
for (let i = 0; i < hexStrLength; i += 2) {
|
||||
words.push(parseInt(hexStr.substr(i, 2), 16))
|
||||
}
|
||||
return words
|
||||
}
|
||||
|
||||
/**
|
||||
* utf8 串转字节数组
|
||||
*/
|
||||
function utf8ToArray(str) {
|
||||
const arr = []
|
||||
|
||||
for (let i = 0, len = str.length; i < len; i++) {
|
||||
const point = str.codePointAt(i)
|
||||
|
||||
if (point <= 0x007f) {
|
||||
// 单字节,标量值:00000000 00000000 0zzzzzzz
|
||||
arr.push(point)
|
||||
} else if (point <= 0x07ff) {
|
||||
// 双字节,标量值:00000000 00000yyy yyzzzzzz
|
||||
arr.push(0xc0 | (point >>> 6)) // 110yyyyy(0xc0-0xdf)
|
||||
arr.push(0x80 | (point & 0x3f)) // 10zzzzzz(0x80-0xbf)
|
||||
} else if (point <= 0xD7FF || (point >= 0xE000 && point <= 0xFFFF)) {
|
||||
// 三字节:标量值:00000000 xxxxyyyy yyzzzzzz
|
||||
arr.push(0xe0 | (point >>> 12)) // 1110xxxx(0xe0-0xef)
|
||||
arr.push(0x80 | ((point >>> 6) & 0x3f)) // 10yyyyyy(0x80-0xbf)
|
||||
arr.push(0x80 | (point & 0x3f)) // 10zzzzzz(0x80-0xbf)
|
||||
} else if (point >= 0x010000 && point <= 0x10FFFF) {
|
||||
// 四字节:标量值:000wwwxx xxxxyyyy yyzzzzzz
|
||||
i++
|
||||
arr.push((0xf0 | (point >>> 18) & 0x1c)) // 11110www(0xf0-0xf7)
|
||||
arr.push((0x80 | ((point >>> 12) & 0x3f))) // 10xxxxxx(0x80-0xbf)
|
||||
arr.push((0x80 | ((point >>> 6) & 0x3f))) // 10yyyyyy(0x80-0xbf)
|
||||
arr.push((0x80 | (point & 0x3f))) // 10zzzzzz(0x80-0xbf)
|
||||
} else {
|
||||
// 五、六字节,暂时不支持
|
||||
arr.push(point)
|
||||
throw new Error('input is not supported')
|
||||
}
|
||||
}
|
||||
|
||||
return arr
|
||||
}
|
||||
|
||||
module.exports = function (input, options) {
|
||||
input = typeof input === 'string' ? utf8ToArray(input) : Array.prototype.slice.call(input)
|
||||
|
||||
if (options) {
|
||||
const mode = options.mode || 'hmac'
|
||||
if (mode !== 'hmac') throw new Error('invalid mode')
|
||||
|
||||
let key = options.key
|
||||
if (!key) throw new Error('invalid key')
|
||||
|
||||
key = typeof key === 'string' ? hexToArray(key) : Array.prototype.slice.call(key)
|
||||
return ArrayToHex(hmac(input, key))
|
||||
}
|
||||
|
||||
return ArrayToHex(sm3(input))
|
||||
}
|
||||
359
node_modules/sm-crypto/src/sm4/index.js
generated
vendored
359
node_modules/sm-crypto/src/sm4/index.js
generated
vendored
@@ -1,359 +0,0 @@
|
||||
/* eslint-disable no-bitwise, no-mixed-operators, complexity */
|
||||
const DECRYPT = 0
|
||||
const ROUND = 32
|
||||
const BLOCK = 16
|
||||
|
||||
const Sbox = [
|
||||
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
|
||||
0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
|
||||
0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
|
||||
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
|
||||
0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
|
||||
0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
|
||||
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
|
||||
0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
|
||||
0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
|
||||
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
|
||||
0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
|
||||
0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
|
||||
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
|
||||
0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
|
||||
0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
|
||||
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
|
||||
]
|
||||
|
||||
const CK = [
|
||||
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
|
||||
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
|
||||
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
|
||||
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
|
||||
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
|
||||
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
|
||||
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
|
||||
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
|
||||
]
|
||||
|
||||
/**
|
||||
* 16 进制串转字节数组
|
||||
*/
|
||||
function hexToArray(str) {
|
||||
const arr = []
|
||||
for (let i = 0, len = str.length; i < len; i += 2) {
|
||||
arr.push(parseInt(str.substr(i, 2), 16))
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
/**
|
||||
* 字节数组转 16 进制串
|
||||
*/
|
||||
function ArrayToHex(arr) {
|
||||
return arr.map(item => {
|
||||
item = item.toString(16)
|
||||
return item.length === 1 ? '0' + item : item
|
||||
}).join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* utf8 串转字节数组
|
||||
*/
|
||||
function utf8ToArray(str) {
|
||||
const arr = []
|
||||
|
||||
for (let i = 0, len = str.length; i < len; i++) {
|
||||
const point = str.codePointAt(i)
|
||||
|
||||
if (point <= 0x007f) {
|
||||
// 单字节,标量值:00000000 00000000 0zzzzzzz
|
||||
arr.push(point)
|
||||
} else if (point <= 0x07ff) {
|
||||
// 双字节,标量值:00000000 00000yyy yyzzzzzz
|
||||
arr.push(0xc0 | (point >>> 6)) // 110yyyyy(0xc0-0xdf)
|
||||
arr.push(0x80 | (point & 0x3f)) // 10zzzzzz(0x80-0xbf)
|
||||
} else if (point <= 0xD7FF || (point >= 0xE000 && point <= 0xFFFF)) {
|
||||
// 三字节:标量值:00000000 xxxxyyyy yyzzzzzz
|
||||
arr.push(0xe0 | (point >>> 12)) // 1110xxxx(0xe0-0xef)
|
||||
arr.push(0x80 | ((point >>> 6) & 0x3f)) // 10yyyyyy(0x80-0xbf)
|
||||
arr.push(0x80 | (point & 0x3f)) // 10zzzzzz(0x80-0xbf)
|
||||
} else if (point >= 0x010000 && point <= 0x10FFFF) {
|
||||
// 四字节:标量值:000wwwxx xxxxyyyy yyzzzzzz
|
||||
i++
|
||||
arr.push((0xf0 | (point >>> 18) & 0x1c)) // 11110www(0xf0-0xf7)
|
||||
arr.push((0x80 | ((point >>> 12) & 0x3f))) // 10xxxxxx(0x80-0xbf)
|
||||
arr.push((0x80 | ((point >>> 6) & 0x3f))) // 10yyyyyy(0x80-0xbf)
|
||||
arr.push((0x80 | (point & 0x3f))) // 10zzzzzz(0x80-0xbf)
|
||||
} else {
|
||||
// 五、六字节,暂时不支持
|
||||
arr.push(point)
|
||||
throw new Error('input is not supported')
|
||||
}
|
||||
}
|
||||
|
||||
return arr
|
||||
}
|
||||
|
||||
/**
|
||||
* 字节数组转 utf8 串
|
||||
*/
|
||||
function arrayToUtf8(arr) {
|
||||
const str = []
|
||||
for (let i = 0, len = arr.length; i < len; i++) {
|
||||
if (arr[i] >= 0xf0 && arr[i] <= 0xf7) {
|
||||
// 四字节
|
||||
str.push(String.fromCodePoint(((arr[i] & 0x07) << 18) + ((arr[i + 1] & 0x3f) << 12) + ((arr[i + 2] & 0x3f) << 6) + (arr[i + 3] & 0x3f)))
|
||||
i += 3
|
||||
} else if (arr[i] >= 0xe0 && arr[i] <= 0xef) {
|
||||
// 三字节
|
||||
str.push(String.fromCodePoint(((arr[i] & 0x0f) << 12) + ((arr[i + 1] & 0x3f) << 6) + (arr[i + 2] & 0x3f)))
|
||||
i += 2
|
||||
} else if (arr[i] >= 0xc0 && arr[i] <= 0xdf) {
|
||||
// 双字节
|
||||
str.push(String.fromCodePoint(((arr[i] & 0x1f) << 6) + (arr[i + 1] & 0x3f)))
|
||||
i++
|
||||
} else {
|
||||
// 单字节
|
||||
str.push(String.fromCodePoint(arr[i]))
|
||||
}
|
||||
}
|
||||
|
||||
return str.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* 32 比特循环左移
|
||||
*/
|
||||
function rotl(x, n) {
|
||||
const s = n & 31
|
||||
return (x << s) | (x >>> (32 - s))
|
||||
}
|
||||
|
||||
/**
|
||||
* 非线性变换
|
||||
*/
|
||||
function byteSub(a) {
|
||||
return (Sbox[a >>> 24 & 0xFF] & 0xFF) << 24 |
|
||||
(Sbox[a >>> 16 & 0xFF] & 0xFF) << 16 |
|
||||
(Sbox[a >>> 8 & 0xFF] & 0xFF) << 8 |
|
||||
(Sbox[a & 0xFF] & 0xFF)
|
||||
}
|
||||
|
||||
/**
|
||||
* 线性变换,加密/解密用
|
||||
*/
|
||||
function l1(b) {
|
||||
return b ^ rotl(b, 2) ^ rotl(b, 10) ^ rotl(b, 18) ^ rotl(b, 24)
|
||||
}
|
||||
|
||||
/**
|
||||
* 线性变换,生成轮密钥用
|
||||
*/
|
||||
function l2(b) {
|
||||
return b ^ rotl(b, 13) ^ rotl(b, 23)
|
||||
}
|
||||
|
||||
/**
|
||||
* 以一组 128 比特进行加密/解密操作
|
||||
*/
|
||||
function sms4Crypt(input, output, roundKey) {
|
||||
const x = new Array(4)
|
||||
|
||||
// 字节数组转成字数组(此处 1 字 = 32 比特)
|
||||
const tmp = new Array(4)
|
||||
for (let i = 0; i < 4; i++) {
|
||||
tmp[0] = input[4 * i] & 0xff
|
||||
tmp[1] = input[4 * i + 1] & 0xff
|
||||
tmp[2] = input[4 * i + 2] & 0xff
|
||||
tmp[3] = input[4 * i + 3] & 0xff
|
||||
x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]
|
||||
}
|
||||
|
||||
// x[i + 4] = x[i] ^ l1(byteSub(x[i + 1] ^ x[i + 2] ^ x[i + 3] ^ roundKey[i]))
|
||||
for (let r = 0, mid; r < 32; r += 4) {
|
||||
mid = x[1] ^ x[2] ^ x[3] ^ roundKey[r + 0]
|
||||
x[0] ^= l1(byteSub(mid)) // x[4]
|
||||
|
||||
mid = x[2] ^ x[3] ^ x[0] ^ roundKey[r + 1]
|
||||
x[1] ^= l1(byteSub(mid)) // x[5]
|
||||
|
||||
mid = x[3] ^ x[0] ^ x[1] ^ roundKey[r + 2]
|
||||
x[2] ^= l1(byteSub(mid)) // x[6]
|
||||
|
||||
mid = x[0] ^ x[1] ^ x[2] ^ roundKey[r + 3]
|
||||
x[3] ^= l1(byteSub(mid)) // x[7]
|
||||
}
|
||||
|
||||
// 反序变换
|
||||
for (let j = 0; j < 16; j += 4) {
|
||||
output[j] = x[3 - j / 4] >>> 24 & 0xff
|
||||
output[j + 1] = x[3 - j / 4] >>> 16 & 0xff
|
||||
output[j + 2] = x[3 - j / 4] >>> 8 & 0xff
|
||||
output[j + 3] = x[3 - j / 4] & 0xff
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 密钥扩展算法
|
||||
*/
|
||||
function sms4KeyExt(key, roundKey, cryptFlag) {
|
||||
const x = new Array(4)
|
||||
|
||||
// 字节数组转成字数组(此处 1 字 = 32 比特)
|
||||
const tmp = new Array(4)
|
||||
for (let i = 0; i < 4; i++) {
|
||||
tmp[0] = key[0 + 4 * i] & 0xff
|
||||
tmp[1] = key[1 + 4 * i] & 0xff
|
||||
tmp[2] = key[2 + 4 * i] & 0xff
|
||||
tmp[3] = key[3 + 4 * i] & 0xff
|
||||
x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]
|
||||
}
|
||||
|
||||
// 与系统参数做异或
|
||||
x[0] ^= 0xa3b1bac6
|
||||
x[1] ^= 0x56aa3350
|
||||
x[2] ^= 0x677d9197
|
||||
x[3] ^= 0xb27022dc
|
||||
|
||||
// roundKey[i] = x[i + 4] = x[i] ^ l2(byteSub(x[i + 1] ^ x[i + 2] ^ x[i + 3] ^ CK[i]))
|
||||
for (let r = 0, mid; r < 32; r += 4) {
|
||||
mid = x[1] ^ x[2] ^ x[3] ^ CK[r + 0]
|
||||
roundKey[r + 0] = x[0] ^= l2(byteSub(mid)) // x[4]
|
||||
|
||||
mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1]
|
||||
roundKey[r + 1] = x[1] ^= l2(byteSub(mid)) // x[5]
|
||||
|
||||
mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2]
|
||||
roundKey[r + 2] = x[2] ^= l2(byteSub(mid)) // x[6]
|
||||
|
||||
mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3]
|
||||
roundKey[r + 3] = x[3] ^= l2(byteSub(mid)) // x[7]
|
||||
}
|
||||
|
||||
// 解密时使用反序的轮密钥
|
||||
if (cryptFlag === DECRYPT) {
|
||||
for (let r = 0, mid; r < 16; r++) {
|
||||
mid = roundKey[r]
|
||||
roundKey[r] = roundKey[31 - r]
|
||||
roundKey[31 - r] = mid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sm4(inArray, key, cryptFlag, {
|
||||
padding = 'pkcs#7', mode, iv = [], output = 'string'
|
||||
} = {}) {
|
||||
if (mode === 'cbc') {
|
||||
// CBC 模式,默认走 ECB 模式
|
||||
if (typeof iv === 'string') iv = hexToArray(iv)
|
||||
if (iv.length !== (128 / 8)) {
|
||||
// iv 不是 128 比特
|
||||
throw new Error('iv is invalid')
|
||||
}
|
||||
}
|
||||
|
||||
// 检查 key
|
||||
if (typeof key === 'string') key = hexToArray(key)
|
||||
if (key.length !== (128 / 8)) {
|
||||
// key 不是 128 比特
|
||||
throw new Error('key is invalid')
|
||||
}
|
||||
|
||||
// 检查输入
|
||||
if (typeof inArray === 'string') {
|
||||
if (cryptFlag !== DECRYPT) {
|
||||
// 加密,输入为 utf8 串
|
||||
inArray = utf8ToArray(inArray)
|
||||
} else {
|
||||
// 解密,输入为 16 进制串
|
||||
inArray = hexToArray(inArray)
|
||||
}
|
||||
} else {
|
||||
inArray = [...inArray]
|
||||
}
|
||||
|
||||
// 新增填充,sm4 是 16 个字节一个分组,所以统一走到 pkcs#7
|
||||
if ((padding === 'pkcs#5' || padding === 'pkcs#7') && cryptFlag !== DECRYPT) {
|
||||
const paddingCount = BLOCK - inArray.length % BLOCK
|
||||
for (let i = 0; i < paddingCount; i++) inArray.push(paddingCount)
|
||||
}
|
||||
|
||||
// 生成轮密钥
|
||||
const roundKey = new Array(ROUND)
|
||||
sms4KeyExt(key, roundKey, cryptFlag)
|
||||
|
||||
const outArray = []
|
||||
let lastVector = iv
|
||||
let restLen = inArray.length
|
||||
let point = 0
|
||||
while (restLen >= BLOCK) {
|
||||
const input = inArray.slice(point, point + 16)
|
||||
const output = new Array(16)
|
||||
|
||||
if (mode === 'cbc') {
|
||||
for (let i = 0; i < BLOCK; i++) {
|
||||
if (cryptFlag !== DECRYPT) {
|
||||
// 加密过程在组加密前进行异或
|
||||
input[i] ^= lastVector[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sms4Crypt(input, output, roundKey)
|
||||
|
||||
|
||||
for (let i = 0; i < BLOCK; i++) {
|
||||
if (mode === 'cbc') {
|
||||
if (cryptFlag === DECRYPT) {
|
||||
// 解密过程在组解密后进行异或
|
||||
output[i] ^= lastVector[i]
|
||||
}
|
||||
}
|
||||
|
||||
outArray[point + i] = output[i]
|
||||
}
|
||||
|
||||
if (mode === 'cbc') {
|
||||
if (cryptFlag !== DECRYPT) {
|
||||
// 使用上一次输出作为加密向量
|
||||
lastVector = output
|
||||
} else {
|
||||
// 使用上一次输入作为解密向量
|
||||
lastVector = input
|
||||
}
|
||||
}
|
||||
|
||||
restLen -= BLOCK
|
||||
point += BLOCK
|
||||
}
|
||||
|
||||
// 去除填充,sm4 是 16 个字节一个分组,所以统一走到 pkcs#7
|
||||
if ((padding === 'pkcs#5' || padding === 'pkcs#7') && cryptFlag === DECRYPT) {
|
||||
const len = outArray.length
|
||||
const paddingCount = outArray[len - 1]
|
||||
for (let i = 1; i <= paddingCount; i++) {
|
||||
if (outArray[len - i] !== paddingCount) throw new Error('padding is invalid')
|
||||
}
|
||||
outArray.splice(len - paddingCount, paddingCount)
|
||||
}
|
||||
|
||||
// 调整输出
|
||||
if (output !== 'array') {
|
||||
if (cryptFlag !== DECRYPT) {
|
||||
// 加密,输出转 16 进制串
|
||||
return ArrayToHex(outArray)
|
||||
} else {
|
||||
// 解密,输出转 utf8 串
|
||||
return arrayToUtf8(outArray)
|
||||
}
|
||||
} else {
|
||||
return outArray
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
encrypt(inArray, key, options) {
|
||||
return sm4(inArray, key, 1, options)
|
||||
},
|
||||
decrypt(inArray, key, options) {
|
||||
return sm4(inArray, key, 0, options)
|
||||
}
|
||||
}
|
||||
26
node_modules/sm-crypto/webpack.config.js
generated
vendored
26
node_modules/sm-crypto/webpack.config.js
generated
vendored
@@ -1,26 +0,0 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
sm2: './src/sm2/index.js',
|
||||
sm3: './src/sm3/index.js',
|
||||
sm4: './src/sm4/index.js',
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: '[name].js',
|
||||
library: '[name]',
|
||||
libraryTarget: 'umd',
|
||||
},
|
||||
module: {
|
||||
loaders: [{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'babel-loader'
|
||||
}]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.UglifyJsPlugin(),
|
||||
]
|
||||
};
|
||||
18
package-lock.json
generated
18
package-lock.json
generated
@@ -1,14 +1,18 @@
|
||||
{
|
||||
"name": "ks-app-employment-service",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-ui": "^1.5.11",
|
||||
"dayjs": "^1.11.19",
|
||||
"sm-crypto": "^0.3.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@dcloudio/uni-ui": {
|
||||
"version": "1.5.11",
|
||||
"resolved": "https://registry.npmjs.org/@dcloudio/uni-ui/-/uni-ui-1.5.11.tgz",
|
||||
"integrity": "sha512-DBtk046ofmeFd82zRI7d89SoEwrAxYzUN3WVPm1DIBkpLPG5F5QDNkHMnZGu2wNrMEmGBjBpUh3vqEY1L3jaMw=="
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.19",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
|
||||
@@ -21,14 +25,20 @@
|
||||
},
|
||||
"node_modules/sm-crypto": {
|
||||
"version": "0.3.13",
|
||||
"resolved": "https://registry.npmjs.org/sm-crypto/-/sm-crypto-0.3.13.tgz",
|
||||
"resolved": "https://registry.npmmirror.com/sm-crypto/-/sm-crypto-0.3.13.tgz",
|
||||
"integrity": "sha512-ztNF+pZq6viCPMA1A6KKu3bgpkmYti5avykRHbcFIdSipFdkVmfUw2CnpM2kBJyppIalqvczLNM3wR8OQ0pT5w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jsbn": "^1.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-ui": {
|
||||
"version": "1.5.11",
|
||||
"resolved": "https://registry.npmjs.org/@dcloudio/uni-ui/-/uni-ui-1.5.11.tgz",
|
||||
"integrity": "sha512-DBtk046ofmeFd82zRI7d89SoEwrAxYzUN3WVPm1DIBkpLPG5F5QDNkHMnZGu2wNrMEmGBjBpUh3vqEY1L3jaMw=="
|
||||
},
|
||||
"dayjs": {
|
||||
"version": "1.11.19",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
|
||||
@@ -41,7 +51,7 @@
|
||||
},
|
||||
"sm-crypto": {
|
||||
"version": "0.3.13",
|
||||
"resolved": "https://registry.npmjs.org/sm-crypto/-/sm-crypto-0.3.13.tgz",
|
||||
"resolved": "https://registry.npmmirror.com/sm-crypto/-/sm-crypto-0.3.13.tgz",
|
||||
"integrity": "sha512-ztNF+pZq6viCPMA1A6KKu3bgpkmYti5avykRHbcFIdSipFdkVmfUw2CnpM2kBJyppIalqvczLNM3wR8OQ0pT5w==",
|
||||
"requires": {
|
||||
"jsbn": "^1.1.0"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-ui": "^1.5.11",
|
||||
"dayjs": "^1.11.19",
|
||||
"sm-crypto": "^0.3.13"
|
||||
}
|
||||
|
||||
@@ -1,329 +1,417 @@
|
||||
<template>
|
||||
<AppLayout title="" :use-scroll-view="false">
|
||||
<template #headerleft>
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
<template #headerright>
|
||||
<view class="btn mar_ri10">
|
||||
<image
|
||||
src="@/static/icon/collect3.png"
|
||||
v-if="!companyInfo.isCollection"
|
||||
></image>
|
||||
<image src="@/static/icon/collect2.png" v-else></image>
|
||||
</view>
|
||||
</template>
|
||||
<view class="content">
|
||||
<view class="content-top">
|
||||
<view class="companyinfo-left">
|
||||
<image src="@/static/icon/companyIcon.png" mode=""></image>
|
||||
</view>
|
||||
<view class="companyinfo-right">
|
||||
<view class="row1">{{ companyInfo?.companyName }}</view>
|
||||
<view class="row2">
|
||||
{{ companyInfo?.scale }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="conetent-info" :class="{ expanded: isExpanded }">
|
||||
<view class="info-title">公司介绍</view>
|
||||
<view class="info-desirption">{{
|
||||
<AppLayout title="" :use-scroll-view="false">
|
||||
<template #headerleft>
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
<template #headerright>
|
||||
<view class="btn mar_ri10">
|
||||
<image src="@/static/icon/collect3.png" v-if="!companyInfo.isCollection"></image>
|
||||
<image src="@/static/icon/collect2.png" v-else></image>
|
||||
</view>
|
||||
</template>
|
||||
<view class="content">
|
||||
<view class="content-top">
|
||||
<view class="companyinfo-left">
|
||||
<image src="@/static/icon/companyIcon.png" mode=""></image>
|
||||
</view>
|
||||
<view class="companyinfo-right">
|
||||
<view class="row1">{{ companyInfo?.companyName }}</view>
|
||||
<view class="row2">
|
||||
{{ companyInfo?.scale }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="conetent-info" :class="{ expanded: isExpanded }">
|
||||
<view class="info-title">公司介绍</view>
|
||||
<view class="info-desirption">{{
|
||||
companyInfo.companyIntroduction
|
||||
}}</view>
|
||||
<!-- <view class="info-title title2">公司地址</view>
|
||||
<!-- <view class="info-title title2">公司地址</view>
|
||||
<view class="locationCompany"></view> -->
|
||||
</view>
|
||||
<view class="expand" @click="expand">
|
||||
<text>{{ isExpanded ? "收起" : "展开" }}</text>
|
||||
<image
|
||||
class="expand-img"
|
||||
:class="{ 'expand-img-active': !isExpanded }"
|
||||
src="@/static/icon/downs.png"
|
||||
></image>
|
||||
</view>
|
||||
<scroll-view scroll-y class="Detailscroll-view">
|
||||
<view class="views">
|
||||
<view class="Detail-title"><text class="title">在招职位</text></view>
|
||||
<template v-if="companyInfo.jobInfoList.length != 0">
|
||||
<view v-for="job in companyInfo.jobInfoList" :key="job.id">
|
||||
<view class="cards" @click="navTo(`/packageA/pages/post/post?jobId=${JSON.stringify(job)}`)">
|
||||
<view class="card-company">
|
||||
<text class="company">{{ job.jobTitle }}</text>
|
||||
<view class="salary"> {{ job.salaryRange }}元 </view>
|
||||
</view>
|
||||
<view class="card-companyName">{{ job.companyName }}</view>
|
||||
<view class="card-companyName">{{ job.jobDescription }}</view>
|
||||
<view class="card-tags">
|
||||
<view class="tag">
|
||||
{{ job.educationRequirement }}
|
||||
</view>
|
||||
<view class="tag">
|
||||
{{ job.experienceRequirement }}
|
||||
</view>
|
||||
<!-- <view class="tag">
|
||||
{{ vacanciesTo(job.vacancies) }}
|
||||
</view> -->
|
||||
<view class="tag" v-if="job.jobRequirement">
|
||||
{{ job.jobRequirement }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-bottom">
|
||||
<view>{{ job.postingDate }}</view>
|
||||
<view>
|
||||
<convert-distance
|
||||
:alat="job.latitude"
|
||||
:along="job.longitude"
|
||||
:blat="latitude"
|
||||
:blong="longitude"
|
||||
></convert-distance>
|
||||
<dict-Label
|
||||
class="mar_le10"
|
||||
dictType="area"
|
||||
:value="job.jobLocationAreaCode"
|
||||
></dict-Label>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<empty v-else pdTop="200"></empty>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</AppLayout>
|
||||
</view>
|
||||
<view class="expand" @click="expand">
|
||||
<text>{{ isExpanded ? "收起" : "展开" }}</text>
|
||||
<image class="expand-img" :class="{ 'expand-img-active': !isExpanded }" src="@/static/icon/downs.png">
|
||||
</image>
|
||||
</view>
|
||||
<scroll-view scroll-y class="Detailscroll-view">
|
||||
<view class="views">
|
||||
<view class="Detail-title"><text class="title">在招职位</text></view>
|
||||
<template v-if="companyInfo.jobInfoList.length != 0">
|
||||
<view v-for="job in companyInfo.jobInfoList" :key="job.id">
|
||||
<!-- @click="navTo(`/packageA/pages/post/post?jobId=${JSON.stringify(job)}`)" -->
|
||||
<!-- :style="getItemBackgroundStyle('bj2.png')" -->
|
||||
<view class="cards">
|
||||
<view class="card-company">
|
||||
<text class="company">{{ job.jobTitle }}</text>
|
||||
<view class="salary"> ¥{{ job.salaryRange }}/月 </view>
|
||||
</view>
|
||||
<view class="card-tags">
|
||||
<view class="tag jy">
|
||||
<image :src="`${baseUrl}/jobfair/jy.png`" mode=""></image>
|
||||
{{ job.experienceRequirement }}
|
||||
</view>
|
||||
<view class="tag xl">
|
||||
<image :src="`${baseUrl}/jobfair/xx.png`" mode=""></image>
|
||||
{{ job.educationRequirement }}
|
||||
</view>
|
||||
<view class="tag yd" v-if="job.jobRequirement">
|
||||
<image :src="`${baseUrl}/jobfair/lx-1.png`" mode=""></image>
|
||||
{{ job.jobRequirement }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-companyName">
|
||||
{{ job.jobDescription }}
|
||||
</view>
|
||||
<view class="deliver-box">
|
||||
<view class="deliver-btn" @click="deliverResume">
|
||||
简历投递
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<empty v-else pdTop="200"></empty>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import point from "@/static/icon/point.png";
|
||||
import { reactive, inject, watch, ref, onMounted, computed } from "vue";
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||
import dictLabel from "@/components/dict-Label/dict-Label.vue";
|
||||
import { storeToRefs } from "pinia";
|
||||
import useLocationStore from "@/stores/useLocationStore";
|
||||
const { longitudeVal, latitudeVal } = storeToRefs(useLocationStore());
|
||||
const { $api, navTo, vacanciesTo, navBack } = inject("globalFunction");
|
||||
import {
|
||||
reactive,
|
||||
inject,
|
||||
watch,
|
||||
ref,
|
||||
onMounted,
|
||||
computed
|
||||
} from "vue";
|
||||
import {
|
||||
onLoad,
|
||||
onShow
|
||||
} from "@dcloudio/uni-app";
|
||||
import dictLabel from "@/components/dict-Label/dict-Label.vue";
|
||||
import config from "@/config.js";
|
||||
import {
|
||||
storeToRefs
|
||||
} from "pinia";
|
||||
import useLocationStore from "@/stores/useLocationStore";
|
||||
const {
|
||||
longitudeVal,
|
||||
latitudeVal
|
||||
} = storeToRefs(useLocationStore());
|
||||
const {
|
||||
$api,
|
||||
navTo,
|
||||
vacanciesTo,
|
||||
navBack
|
||||
} = inject("globalFunction");
|
||||
const isExpanded = ref(false);
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
list: [],
|
||||
total: 0,
|
||||
maxPage: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
const companyInfo = ref({
|
||||
jobInfoList: [],
|
||||
});
|
||||
|
||||
const isExpanded = ref(false);
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
list: [],
|
||||
total: 0,
|
||||
maxPage: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
const companyInfo = ref({});
|
||||
const baseUrl = config.imgBaseUrl;
|
||||
const getItemBackgroundStyle = (imageName) => ({
|
||||
backgroundImage: `url(${baseUrl}/jobfair/${imageName})`,
|
||||
backgroundSize: "100% 100%", // 覆盖整个容器
|
||||
backgroundPosition: "center", // 居中
|
||||
backgroundRepeat: "no-repeat",
|
||||
});
|
||||
|
||||
onLoad((options) => {
|
||||
companyInfo.value = JSON.parse(options.job);
|
||||
console.log(companyInfo.value, "companyInfo.value");
|
||||
});
|
||||
onLoad((options) => {
|
||||
companyInfo.value = JSON.parse(options.job);
|
||||
});
|
||||
|
||||
function expand() {
|
||||
isExpanded.value = !isExpanded.value;
|
||||
}
|
||||
function expand() {
|
||||
isExpanded.value = !isExpanded.value;
|
||||
}
|
||||
|
||||
function deliverResume() {
|
||||
const raw = uni.getStorageSync("Padmin-Token");
|
||||
const token = typeof raw === "string" ? raw.trim() : "";
|
||||
const headers = token ? {
|
||||
Authorization: raw.startsWith("Bearer ") ? raw : `Bearer ${token}`
|
||||
} : {};
|
||||
|
||||
$api.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers).then((resData1) => {
|
||||
if (resData1.code == 200) {
|
||||
$api.myRequest("/system/user/login/user/info", {}, "GET", 10100, headers).then((resData) => {
|
||||
$api.myRequest("/jobfair/public/job-fair-person-job/insert", {}, "GET", 9100, {
|
||||
"Content-Type": "application/json"
|
||||
}).then((data) => {
|
||||
if (data && data.code === 200) {
|
||||
$api.msg("简历投递成功");
|
||||
} else {
|
||||
$api.msg((data && data.msg) || "简历投递失败");
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$api.msg('请先登录')
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.btnback {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
.btnback {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
image {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.content-top {
|
||||
padding: 28rpx;
|
||||
padding-top: 50rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
.content-top {
|
||||
padding: 28rpx;
|
||||
padding-top: 50rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
.companyinfo-left {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
.companyinfo-left {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.companyinfo-right {
|
||||
.row1 {
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.companyinfo-right {
|
||||
.row1 {
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.row2 {
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
line-height: 45rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.row2 {
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
line-height: 45rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.conetent-info {
|
||||
padding: 0 28rpx;
|
||||
overflow: hidden;
|
||||
max-height: 0rpx;
|
||||
transition: max-height 0.3s ease;
|
||||
.conetent-info {
|
||||
padding: 0 28rpx;
|
||||
overflow: hidden;
|
||||
max-height: 0rpx;
|
||||
transition: max-height 0.3s ease;
|
||||
|
||||
.info-title {
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
}
|
||||
.info-title {
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.info-desirption {
|
||||
margin-top: 12rpx;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #495265;
|
||||
text-align: justified;
|
||||
}
|
||||
.info-desirption {
|
||||
margin-top: 12rpx;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #495265;
|
||||
text-align: justified;
|
||||
}
|
||||
|
||||
.title2 {
|
||||
margin-top: 48rpx;
|
||||
}
|
||||
}
|
||||
.title2 {
|
||||
margin-top: 48rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.expanded {
|
||||
max-height: 1000rpx; // 足够显示完整内容
|
||||
}
|
||||
.expanded {
|
||||
max-height: 1000rpx; // 足够显示完整内容
|
||||
}
|
||||
|
||||
.expand {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
white-space: nowrap;
|
||||
justify-content: center;
|
||||
margin-top: 20rpx;
|
||||
margin-bottom: 28rpx;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #256BFA;
|
||||
.expand {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
white-space: nowrap;
|
||||
justify-content: center;
|
||||
margin-top: 20rpx;
|
||||
margin-bottom: 28rpx;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #256BFA;
|
||||
|
||||
.expand-img {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
.expand-img {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
.expand-img-active {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
.expand-img-active {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.Detailscroll-view {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
background: #F4F4F4;
|
||||
.Detailscroll-view {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
background: #F4F4F4;
|
||||
|
||||
.views {
|
||||
padding: 28rpx;
|
||||
.views {
|
||||
padding: 28rpx;
|
||||
|
||||
.Detail-title {
|
||||
font-weight: 600;
|
||||
font-size: 32rpx;
|
||||
color: #000000;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.Detail-title {
|
||||
font-weight: 600;
|
||||
font-size: 32rpx;
|
||||
color: #000000;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.title {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
.title {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.Detail-title::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
left: -14rpx;
|
||||
bottom: 0;
|
||||
height: 16rpx;
|
||||
width: 108rpx;
|
||||
background: linear-gradient(to right, #CBDEFF, #FFFFFF);
|
||||
border-radius: 8rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
.Detail-title::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
left: -14rpx;
|
||||
bottom: 0;
|
||||
height: 16rpx;
|
||||
width: 108rpx;
|
||||
background: linear-gradient(to right, #CBDEFF, #FFFFFF);
|
||||
border-radius: 8rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.cards {
|
||||
padding: 32rpx;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0, 0, 0, 0.04);
|
||||
border-radius: 20rpx 20rpx 20rpx 20rpx;
|
||||
margin-top: 22rpx;
|
||||
.cards {
|
||||
padding: 32rpx;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0, 0, 0, 0.04);
|
||||
border-radius: 20rpx 20rpx 20rpx 20rpx;
|
||||
margin-top: 22rpx;
|
||||
padding-bottom: 18rpx;
|
||||
background: #f2f8fc;
|
||||
|
||||
.card-company {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
.card-company {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
border-bottom: 1rpx solid #c2d7ea;
|
||||
|
||||
.company {
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.company {
|
||||
font-weight: 600;
|
||||
font-size: 32rpx;
|
||||
color: #207AC7;
|
||||
}
|
||||
|
||||
.salary {
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #4C6EFB;
|
||||
white-space: nowrap;
|
||||
line-height: 48rpx;
|
||||
}
|
||||
}
|
||||
.salary {
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
color: #F83A3C;
|
||||
white-space: nowrap;
|
||||
line-height: 48rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.card-companyName {
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
}
|
||||
.deliver-box {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-top: 5rpx;
|
||||
|
||||
.card-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.deliver-btn {
|
||||
padding: 10rpx 25rpx;
|
||||
background: #53ACFF;
|
||||
width: max-content;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.tag {
|
||||
width: fit-content;
|
||||
height: 30rpx;
|
||||
background: #F4F4F4;
|
||||
border-radius: 4rpx;
|
||||
padding: 6rpx 20rpx;
|
||||
line-height: 30rpx;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #6C7282;
|
||||
text-align: center;
|
||||
margin-top: 14rpx;
|
||||
white-space: nowrap;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
}
|
||||
.card-companyName {
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
margin-top: 23rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.card-bottom {
|
||||
margin-top: 32rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
image {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.card-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 25rpx 0 35rpx;
|
||||
|
||||
image {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.jy {
|
||||
background: #D9EDFF;
|
||||
color: #0086FF;
|
||||
}
|
||||
|
||||
.xl {
|
||||
background: #FFF1D5;
|
||||
color: #FF7F01;
|
||||
}
|
||||
|
||||
.yd {
|
||||
background: #FFD8D8;
|
||||
color: #F83A3C;
|
||||
}
|
||||
|
||||
.tag {
|
||||
width: fit-content;
|
||||
height: 30rpx;
|
||||
border-radius: 4rpx;
|
||||
padding: 6rpx 20rpx;
|
||||
line-height: 30rpx;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
margin-right: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.card-bottom {
|
||||
margin-top: 32rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
<template>
|
||||
<AppLayout title="我的浏览" :show-bg-image="false" :use-scroll-view="false">
|
||||
<template #headerleft>
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
<view class="collection-content">
|
||||
<view class="collection-search">
|
||||
<view class="search-content">
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
<template>
|
||||
<AppLayout title="我的收藏" :show-bg-image="false" :use-scroll-view="false">
|
||||
<template #headerleft>
|
||||
<view class="btn">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
<view class="collection-content">
|
||||
<view class="header">
|
||||
<view class="button-click" :class="{ active: type === 0 }" @click="changeType(0)">工作职位</view>
|
||||
|
||||
@@ -68,48 +68,61 @@
|
||||
<text class="title">参会单位({{ companyList.length }})</text>
|
||||
</view>
|
||||
<view v-for="job in companyList" :key="job.id">
|
||||
<view class="cards" @click="navTo('/packageA/pages/UnitDetails/UnitDetails?job='+JSON.stringify(job))">
|
||||
<view class="card-company">
|
||||
<text class="company line_1">{{ job.companyName }}</text>
|
||||
</view>
|
||||
<view class="card-bottom">
|
||||
<view class="fl_box fs_14">
|
||||
{{ job.scale }}
|
||||
</view>
|
||||
<view class="ris">
|
||||
<text class="fs_14">
|
||||
在招职位·
|
||||
<text class="color_256BFA">{{ job.jobInfoList.length || '-' }}</text>
|
||||
个
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-tags">
|
||||
<view class="tag" v-if="job.industry">
|
||||
{{ job.industry }}
|
||||
</view>
|
||||
<view class="tag">
|
||||
{{ job.companyType }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cards" :style="getItemBackgroundStyle('bj.png')"
|
||||
@click="navTo('/packageA/pages/UnitDetails/UnitDetails?job='+JSON.stringify(job))">
|
||||
<view class="card-company">
|
||||
<view class="company line_1">
|
||||
<image :src="`${baseUrl}/jobfair/mc.png`" mode=""></image>
|
||||
{{ job.companyName }}
|
||||
</view>
|
||||
<view class="ris">
|
||||
<text class="fs_14">
|
||||
在招职位:
|
||||
{{ job.jobInfoList.length || '-' }}
|
||||
个
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-bottom">
|
||||
<view class="fl_box fs_14">
|
||||
{{ job.scale }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-tags">
|
||||
<view class="tag" v-if="job.industry">
|
||||
<image :src="`${baseUrl}/jobfair/hy.png`" mode=""></image>
|
||||
{{ job.industry }}
|
||||
</view>
|
||||
<view class="tag">
|
||||
<image :src="`${baseUrl}/jobfair/lx.png`" mode=""></image>
|
||||
{{ job.companyType }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<template #footer>
|
||||
<view class="footer" v-if="hasnext">
|
||||
<view class="btn-wq button-click" :class="{ 'btn-desbel': fairInfo.isCollection }"
|
||||
<view class="btn-wq button-click" :class="{ 'btn-desbel': fairInfo.isSignUp==1 }"
|
||||
@click="applyExhibitors">
|
||||
{{ fairInfo.isCollection ? '已预约招聘会' : '预约招聘会' }}
|
||||
{{ fairInfo.isSignUp==1 ? '已报名' : '报名招聘会' }}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<uni-popup ref="CompanySignPopup" background-color="#fff" :mask-click="false">
|
||||
<view class="popup-content">
|
||||
<signDialog v-if="signDialogisshow" :signType="signType" :signRole="signRole"
|
||||
:jobFairId="fairInfo.jobFairId" @closePopup="closePopup"></signDialog>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import point from '@/static/icon/point.png';
|
||||
import signDialog from '@/components/jobfair/signDialog.vue';
|
||||
import config from "@/config.js"
|
||||
import {
|
||||
reactive,
|
||||
inject,
|
||||
@@ -122,7 +135,6 @@
|
||||
onLoad,
|
||||
onShow
|
||||
} from '@dcloudio/uni-app';
|
||||
import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
const {
|
||||
$api,
|
||||
@@ -142,29 +154,77 @@
|
||||
const fairInfo = ref({});
|
||||
const companyList = ref([]);
|
||||
const hasnext = ref(true);
|
||||
const userInfo = ref({});
|
||||
const signDialogisshow = ref(false)
|
||||
// 弹窗
|
||||
const signType = ref(1);
|
||||
// person个人 ent企业
|
||||
const signRole = ref('ent');
|
||||
const CompanySignPopup = ref(null)
|
||||
|
||||
const jobFairId = ref(null)
|
||||
|
||||
const baseUrl = config.imgBaseUrl
|
||||
const getItemBackgroundStyle = (imageName) => ({
|
||||
backgroundImage: `url(${baseUrl}/jobfair/${imageName})`,
|
||||
backgroundSize: '100% 100%', // 覆盖整个容器
|
||||
backgroundPosition: 'center', // 居中
|
||||
backgroundRepeat: 'no-repeat'
|
||||
});
|
||||
onLoad((options) => {
|
||||
getCompanyInfo(options.jobFairId);
|
||||
jobFairId.value=options.jobFairId
|
||||
const raw = uni.getStorageSync("Padmin-Token");
|
||||
const token = typeof raw === "string" ? raw.trim() : "";
|
||||
const headers = token ? {
|
||||
Authorization: raw.startsWith("Bearer ") ? raw : `Bearer ${token}`
|
||||
} : {};
|
||||
|
||||
$api.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers).then((resData) => {
|
||||
if (resData.code == 200) {
|
||||
$api.myRequest("/system/user/login/user/info", {}, "GET", 10100, {
|
||||
Authorization: `Bearer ${uni.getStorageSync("Padmin-Token")}`
|
||||
}).then((userinfo) => {
|
||||
userInfo.value = userinfo
|
||||
getCompanyInfo(userInfo.value.info.userId, options.jobFairId);
|
||||
});
|
||||
} else {
|
||||
getCompanyInfo('', options.jobFairId);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function getCompanyInfo(id) {
|
||||
// $api.createRequest(`/app/fair/${id}`).then((resData) => {
|
||||
// fairInfo.value = resData.data;
|
||||
// companyList.value = resData.data.companyList;
|
||||
// hasAppointment();
|
||||
// });
|
||||
$api.myRequest('/jobfair/public/jobfair/detail', {
|
||||
jobFairId: id
|
||||
}).then((resData) => {
|
||||
console.log(resData, 'resData');
|
||||
function closePopup() {
|
||||
CompanySignPopup.value.close()
|
||||
getCompanyInfo(userInfo.value.info.userId, jobFairId.value)
|
||||
}
|
||||
|
||||
function getCompanyInfo(userId, id) {
|
||||
let data={}
|
||||
if (userInfo.value&&userInfo.value.userType == 'ent') {
|
||||
data={
|
||||
jobFairId: id,
|
||||
enterpriseId: userId,
|
||||
code:userInfo.value.info.entCreditCode
|
||||
}
|
||||
}else if(userInfo.value&&userInfo.value.userType == 'ent'){
|
||||
data={
|
||||
jobFairId: id,
|
||||
personId: userId,
|
||||
idCard:userInfo.value.info.personCardNo
|
||||
}
|
||||
}else{
|
||||
data={
|
||||
jobFairId: id,
|
||||
personId: userId
|
||||
}
|
||||
}
|
||||
$api.myRequest('/jobfair/public/jobfair/detail', data).then((resData) => {
|
||||
fairInfo.value = resData.data;
|
||||
console.log(fairInfo.value, 'fairInfo.value');
|
||||
// hasAppointment()
|
||||
});
|
||||
$api.myRequest('/jobfair/public/jobfair/enterprises-with-jobs-by-job-fair-id', {
|
||||
jobFairId: id
|
||||
}).then((resData) => {
|
||||
companyList.value = resData.data;
|
||||
// hasAppointment()
|
||||
});
|
||||
};
|
||||
|
||||
@@ -191,21 +251,56 @@
|
||||
isExpanded.value = !isExpanded.value;
|
||||
}
|
||||
|
||||
// 取消/收藏岗位
|
||||
// 报名招聘会
|
||||
function applyExhibitors() {
|
||||
const fairId = fairInfo.value.jobFairId;
|
||||
if (fairInfo.value.isCollection) {
|
||||
// $api.createRequest(`/app/fair/collection/${fairId}`, {}, 'DELETE').then((resData) => {
|
||||
// getCompanyInfo(fairId);
|
||||
// $api.msg('取消预约成功');
|
||||
// });
|
||||
$api.msg('已预约成功');
|
||||
} else {
|
||||
$api.createRequest(`/app/fair/collection/${fairId}`, {}, 'POST').then((resData) => {
|
||||
getCompanyInfo(fairId);
|
||||
$api.msg('预约成功');
|
||||
});
|
||||
if (fairInfo.value.isSignUp == 1) {
|
||||
$api.msg('请勿重复报名');
|
||||
return
|
||||
}
|
||||
const raw = uni.getStorageSync("Padmin-Token");
|
||||
const token = typeof raw === "string" ? raw.trim() : "";
|
||||
const headers = token ? {
|
||||
Authorization: raw.startsWith("Bearer ") ? raw : `Bearer ${token}`
|
||||
} : {};
|
||||
|
||||
$api.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers).then((resData) => {
|
||||
if (resData.code == 200) {
|
||||
if (userInfo.value.userType == 'ent') {
|
||||
// 企业
|
||||
signType.value = fairInfo.value.jobFairType;
|
||||
signRole.value = userInfo.userType;
|
||||
signDialogisshow.value = true
|
||||
CompanySignPopup.value.open()
|
||||
}else{
|
||||
$api.myRequest("/jobfair/public/job-fair-sign-up-person/sign-up", {
|
||||
personId: userInfo.value.info.userId,
|
||||
jobFairId: jobFairId.value,
|
||||
idCard:userInfo.value.info.personCardNo
|
||||
}, "POST", 9100, { "Content-Type": "application/json",...headers }).then((res) => {
|
||||
if (res.code === 200) {
|
||||
uni.showToast({
|
||||
title: '报名成功',
|
||||
icon: 'success'
|
||||
});
|
||||
getCompanyInfo(userInfo.value.info.userId, jobFairId.value)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.msg || '报名失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
} else {
|
||||
$api.msg('请先登录');
|
||||
setTimeout(() => {
|
||||
uni.redirectTo({
|
||||
url: '/packageB/login'
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function parseDateTime(datetimeStr) {
|
||||
@@ -241,19 +336,24 @@
|
||||
// 判断状态:0 开始中,1 过期,2 待开始
|
||||
let status = 0;
|
||||
let statusText = '开始中';
|
||||
let color = '#13C57C'; // 进行中 - 绿色
|
||||
if (now < startTime) {
|
||||
status = 2; // 待开始
|
||||
statusText = '待开始';
|
||||
color = '#015EEA'; // 未开始 - 蓝色
|
||||
} else if (now > endTime) {
|
||||
status = 1; // 已过期
|
||||
statusText = '已过期';
|
||||
color = '#999999'; // 已过期 - 灰色
|
||||
} else {
|
||||
status = 0; // 进行中
|
||||
statusText = '进行中';
|
||||
color = '#13C57C'; // 进行中 - 绿色
|
||||
}
|
||||
return {
|
||||
status, // 0: 进行中,1: 已过期,2: 待开始
|
||||
statusText,
|
||||
color
|
||||
};
|
||||
}
|
||||
|
||||
@@ -269,6 +369,12 @@
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.popup-content {
|
||||
width: 90vw;
|
||||
height: 80vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.btnback {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
@@ -291,25 +397,30 @@
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.content-top {
|
||||
padding: 28rpx;
|
||||
padding-top: 50rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
.companyinfo-left {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.companyinfo-right {
|
||||
flex: 1;
|
||||
|
||||
.row1 {
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
||||
}
|
||||
|
||||
.row2 {
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
@@ -348,6 +459,7 @@
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
white-space: nowrap;
|
||||
|
||||
.info-title {
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
@@ -496,10 +608,20 @@
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
|
||||
.company {
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
image {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
margin-right: 10rpx;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.salary {
|
||||
@@ -508,6 +630,13 @@
|
||||
white-space: nowrap;
|
||||
line-height: 48rpx;
|
||||
}
|
||||
|
||||
.ris {
|
||||
background: #53ACFF;
|
||||
color: #fff;
|
||||
padding: 7rpx 20rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.card-companyName {
|
||||
@@ -519,25 +648,34 @@
|
||||
.card-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.tag {
|
||||
width: fit-content;
|
||||
height: 30rpx;
|
||||
background: #F4F4F4;
|
||||
background: #E0F0FF;
|
||||
border-radius: 4rpx;
|
||||
padding: 6rpx 20rpx;
|
||||
padding: 6rpx 26rpx;
|
||||
line-height: 30rpx;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #6C7282;
|
||||
color: #595959;
|
||||
text-align: center;
|
||||
margin-top: 14rpx;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 20rpx;
|
||||
|
||||
image {
|
||||
width: 22rpx;
|
||||
height: 22rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-bottom {
|
||||
margin-top: 32rpx;
|
||||
margin-top: 15rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 28rpx;
|
||||
@@ -552,14 +690,17 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24rpx 30rpx 10rpx 30rpx;
|
||||
|
||||
.time-left,
|
||||
.time-right {
|
||||
text-align: center;
|
||||
|
||||
.left-date {
|
||||
font-weight: 500;
|
||||
font-size: 48rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.left-dateDay {
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
@@ -567,23 +708,27 @@
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
width: 40rpx;
|
||||
height: 0rpx;
|
||||
border: 2rpx solid #D4D4D4;
|
||||
margin-top: 64rpx;
|
||||
}
|
||||
|
||||
.time-center {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.center-date {
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #FF881A;
|
||||
}
|
||||
|
||||
.center-dateDay {
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
@@ -621,4 +766,4 @@
|
||||
box-shadow: 0rpx -4rpx 24rpx 0rpx rgba(11, 44, 112, 0.12);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
@@ -122,7 +122,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 4. 新增:简历上传区域(固定在页面底部) -->
|
||||
<!-- <view class="resume-upload-section">
|
||||
<view class="resume-upload-section">
|
||||
<button class="upload-btn" @click="handleResumeUpload" :loading="isUploading" :disabled="isUploading">
|
||||
<uni-icons type="cloud-upload" size="20"></uni-icons>
|
||||
<text class="upload-text">
|
||||
@@ -138,7 +138,7 @@
|
||||
<text class="file-name">{{ uploadedResumeName }}</text>
|
||||
<button class="delete-file-btn" size="mini" @click.stop="handleDeleteResume">删除</button>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -267,12 +267,202 @@ const handleDeleteItem = async (item, index) => {
|
||||
};
|
||||
|
||||
// 简历上传核心逻辑
|
||||
const handleResumeUpload = () => {};
|
||||
const handleResumeUpload = () => {
|
||||
// 从缓存获取用户ID(参考首页实现方式)
|
||||
// 优先从store获取,如果为空则从缓存获取
|
||||
const storeUserId = userInfo.value?.userId;
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
const cachedUserId = cachedUserInfo.userId;
|
||||
|
||||
// 获取用户ID:优先使用store中的userId,如果store中没有,使用缓存中的userId
|
||||
const userId = storeUserId || cachedUserId;
|
||||
|
||||
if (!userId) {
|
||||
$api.msg('请先登录');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否正在上传
|
||||
if (isUploading.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 选择文件(微信小程序使用 wx.chooseMessageFile,uni-app 中对应 uni.chooseMessageFile)
|
||||
uni.chooseMessageFile({
|
||||
count: 1, // 只能选择一个文件
|
||||
type: 'file', // 选择任意文件类型
|
||||
success: (res) => {
|
||||
// 注意:文件路径在 res.tempFiles[0].path
|
||||
const file = res.tempFiles[0];
|
||||
const tempFilePath = file.path; // 获取临时文件路径
|
||||
const fileName = file.name; // 获取文件名
|
||||
|
||||
// 检查文件大小(20MB = 20 * 1024 * 1024 字节)
|
||||
const maxSize = 20 * 1024 * 1024;
|
||||
if (file.size > maxSize) {
|
||||
$api.msg('文件大小不能超过 20MB');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查文件类型
|
||||
const allowedTypes = ['pdf', 'doc', 'docx'];
|
||||
const fileExtension = fileName.split('.').pop()?.toLowerCase();
|
||||
if (!fileExtension || !allowedTypes.includes(fileExtension)) {
|
||||
$api.msg('仅支持 PDF、Word 格式');
|
||||
return;
|
||||
}
|
||||
|
||||
// 开始上传
|
||||
uploadResumeFile(tempFilePath, fileName, userId);
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('选择文件失败:', err);
|
||||
// 用户取消选择不提示错误
|
||||
if (err.errMsg && !err.errMsg.includes('cancel')) {
|
||||
$api.msg('选择文件失败,请重试');
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 上传简历文件到服务器(使用 wx.uploadFile,uni-app 中对应 uni.uploadFile)
|
||||
const uploadResumeFile = (filePath, fileName, userId) => {
|
||||
// 确保 userId 存在且有效
|
||||
if (!userId) {
|
||||
// 如果传入的userId为空,尝试从缓存再次获取
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
const cachedUserId = cachedUserInfo.userId;
|
||||
|
||||
if (!cachedUserId) {
|
||||
$api.msg('用户ID不存在,无法上传');
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用缓存中的userId
|
||||
userId = cachedUserId;
|
||||
}
|
||||
|
||||
isUploading.value = true;
|
||||
|
||||
// 获取token(从缓存获取,参考首页实现方式)
|
||||
let Authorization = '';
|
||||
const tokenValue = uni.getStorageSync('token') || '';
|
||||
if (tokenValue) {
|
||||
Authorization = tokenValue;
|
||||
} else {
|
||||
// 如果缓存中没有token,尝试从store获取
|
||||
const userStore = useUserStore();
|
||||
if (userStore.token) {
|
||||
Authorization = userStore.token;
|
||||
}
|
||||
}
|
||||
|
||||
// 根据接口文档,bussinessId 应该作为 Query 参数传递,而不是 formData
|
||||
// 将 bussinessId 拼接到 URL 上作为查询参数
|
||||
const uploadUrl = `${config.baseUrl}/app/file/upload?bussinessId=${encodeURIComponent(String(userId))}`;
|
||||
|
||||
// 打印调试信息
|
||||
console.log('上传文件参数:', {
|
||||
url: uploadUrl,
|
||||
fileName: fileName,
|
||||
bussinessId: userId,
|
||||
userId: userId,
|
||||
token: Authorization ? '已获取' : '未获取'
|
||||
});
|
||||
|
||||
// 上传文件(参考微信小程序 wx.uploadFile API)
|
||||
uni.uploadFile({
|
||||
url: uploadUrl, // 开发者服务器的上传接口(必须是 HTTPS),bussinessId 作为 Query 参数
|
||||
filePath: filePath, // 本地文件路径(临时路径)
|
||||
name: 'file', // 服务器端接收文件的字段名(需与后端一致)
|
||||
// 注意:根据接口文档,bussinessId 通过 Query 参数传递,不需要 formData
|
||||
header: {
|
||||
'Authorization': encodeURIComponent(Authorization)
|
||||
},
|
||||
success: (uploadRes) => {
|
||||
try {
|
||||
// 注意:res.data 是字符串,需转为 JSON(如果后端返回 JSON)
|
||||
// 参考方案:const result = JSON.parse(data);
|
||||
let resData;
|
||||
if (typeof uploadRes.data === 'string') {
|
||||
resData = JSON.parse(uploadRes.data);
|
||||
} else {
|
||||
resData = uploadRes.data;
|
||||
}
|
||||
|
||||
// 判断上传是否成功
|
||||
if (uploadRes.statusCode === 200 && resData.code === 200) {
|
||||
// 上传成功,处理返回结果
|
||||
uploadedResumeName.value = fileName;
|
||||
uploadedResumeUrl.value = resData.data || resData.msg || resData.url || '';
|
||||
$api.msg('简历上传成功');
|
||||
console.log('上传成功', resData);
|
||||
|
||||
// 可以在这里保存简历信息到后端(如果需要)
|
||||
// saveResumeInfo(userId, uploadedResumeUrl.value, fileName);
|
||||
} else {
|
||||
// 上传失败
|
||||
const errorMsg = resData.msg || resData.message || '上传失败,请重试';
|
||||
$api.msg(errorMsg);
|
||||
console.error('上传失败:', resData);
|
||||
}
|
||||
} catch (error) {
|
||||
// 解析响应数据失败
|
||||
console.error('解析上传响应失败:', error);
|
||||
console.error('原始响应数据:', uploadRes.data);
|
||||
$api.msg('上传失败,请重试');
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
// 上传失败
|
||||
console.error('上传文件失败:', err);
|
||||
$api.msg('上传失败,请检查网络连接');
|
||||
},
|
||||
// 上传进度监听(可选)
|
||||
progress: (res) => {
|
||||
const progress = res.progress; // 上传进度(0-100)
|
||||
console.log('上传进度:', progress + '%');
|
||||
// 可以在这里更新进度条 UI(如果需要)
|
||||
},
|
||||
complete: () => {
|
||||
// 上传完成(无论成功或失败)
|
||||
isUploading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 删除已上传的简历
|
||||
const handleDeleteResume = () => {};
|
||||
const handleDeleteResume = () => {
|
||||
if (!uploadedResumeName.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
uni.showModal({
|
||||
title: '确认删除',
|
||||
content: '确定要删除已上传的简历吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 清除本地数据
|
||||
uploadedResumeName.value = '';
|
||||
uploadedResumeUrl.value = '';
|
||||
$api.msg('已删除');
|
||||
|
||||
// 如果需要,可以调用后端接口删除服务器上的文件
|
||||
// deleteResumeFile(userId);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
/* 修复页面滚动问题:覆盖全局的 overflow: hidden */
|
||||
page {
|
||||
overflow-y: auto !important;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
image{
|
||||
width: 100%;
|
||||
|
||||
@@ -16,25 +16,52 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
// 获取雷达图数据
|
||||
function getRadarData() {
|
||||
if (!props.value || !props.value.radarChart) {
|
||||
// 如果没有数据,使用默认值0
|
||||
const defaultRadarChart = {
|
||||
skill: 0,
|
||||
experience: 0,
|
||||
education: 0,
|
||||
salary: 0,
|
||||
age: 0,
|
||||
location: 0
|
||||
};
|
||||
const labels = ['学历', '年龄', '工作地', '技能', '工作经验', '期望薪资'];
|
||||
const data = [defaultRadarChart.education, defaultRadarChart.age, defaultRadarChart.location,
|
||||
defaultRadarChart.skill, defaultRadarChart.experience, defaultRadarChart.salary].map((item) => item * 0.05);
|
||||
return { labels, data };
|
||||
}
|
||||
|
||||
const { skill, experience, education, salary, age, location } = props.value.radarChart;
|
||||
const labels = ['学历', '年龄', '工作地', '技能', '工作经验', '期望薪资'];
|
||||
const data = [education, age, location, skill, experience, salary].map((item) => item * 0.05);
|
||||
return { labels, data };
|
||||
}
|
||||
|
||||
// 监听页面初始化
|
||||
onMounted(() => {
|
||||
if (Object.keys(props.value).length > 0) {
|
||||
rawRadarChart();
|
||||
}
|
||||
// 延迟执行,确保 canvas 已经渲染
|
||||
setTimeout(() => {
|
||||
const { labels, data } = getRadarData();
|
||||
rawRadarChart(labels, data);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// 监听 props.value 变化
|
||||
watch(
|
||||
() => props.value,
|
||||
(newVal) => {
|
||||
if (newVal && Object.keys(newVal).length > 0) {
|
||||
const { skill, experience, education, salary, age, location } = newVal.radarChart;
|
||||
const labels = ['学历', '年龄', '工作地', '技能', '工作经验', '期望薪资'];
|
||||
const data = [education, age, location, skill, experience, salary].map((item) => item * 0.05);
|
||||
rawRadarChart(labels, data);
|
||||
if (newVal) {
|
||||
// 延迟执行,确保数据更新完成
|
||||
setTimeout(() => {
|
||||
const { labels, data } = getRadarData();
|
||||
rawRadarChart(labels, data);
|
||||
}, 50);
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: false } // deep 递归监听对象内部变化
|
||||
{ deep: true, immediate: true } // deep 递归监听对象内部变化,immediate 立即执行一次
|
||||
);
|
||||
|
||||
function rawRadarChart(labels, data) {
|
||||
|
||||
@@ -208,7 +208,20 @@ const jobInfo = ref({});
|
||||
const state = reactive({});
|
||||
const mapCovers = ref([]);
|
||||
const jobIdRef = ref();
|
||||
const raderData = ref({});
|
||||
// 竞争力分析数据,初始化为包含默认值的完整结构,确保雷达图能正常渲染
|
||||
const raderData = ref({
|
||||
matchScore: 0,
|
||||
rank: 0,
|
||||
percentile: 0,
|
||||
radarChart: {
|
||||
skill: 0,
|
||||
experience: 0,
|
||||
education: 0,
|
||||
salary: 0,
|
||||
age: 0,
|
||||
location: 0
|
||||
}
|
||||
});
|
||||
const videoPalyerRef = ref(null);
|
||||
const explainUrlRef = ref('');
|
||||
|
||||
@@ -240,16 +253,24 @@ const applicants = ref([
|
||||
]);
|
||||
|
||||
onLoad((option) => {
|
||||
console.log(option, 'option');
|
||||
if (option.jobId) {
|
||||
initLoad(option);
|
||||
}
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
const option = parseQueryParams(); // 兼容微信内置浏览器
|
||||
if (option.jobId) {
|
||||
initLoad(option);
|
||||
// 仅在 H5 环境中从 URL 获取参数(小程序环境中 onShow 不会传递 URL 参数)
|
||||
// #ifdef H5
|
||||
try {
|
||||
const option = parseQueryParams(); // 兼容微信内置浏览器
|
||||
if (option.jobId) {
|
||||
initLoad(option);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('onShow 中解析 URL 参数失败:', e);
|
||||
}
|
||||
// #endif
|
||||
});
|
||||
|
||||
function initLoad(option) {
|
||||
@@ -317,8 +338,59 @@ function getTextWidth(text, size = 12) {
|
||||
|
||||
function getCompetivetuveness(jobId) {
|
||||
$api.createRequest(`/app/job/competitiveness/${jobId}`, {}, 'GET').then((resData) => {
|
||||
raderData.value = resData.data;
|
||||
currentStep.value = resData.data.matchScore * 0.04;
|
||||
// 如果接口返回的数据为 null 或空,使用默认值0
|
||||
if (resData && resData.data) {
|
||||
// 确保 radarChart 字段存在,如果不存在则使用默认值
|
||||
const radarChart = resData.data.radarChart || {
|
||||
skill: 0,
|
||||
experience: 0,
|
||||
education: 0,
|
||||
salary: 0,
|
||||
age: 0,
|
||||
location: 0
|
||||
};
|
||||
|
||||
raderData.value = {
|
||||
matchScore: resData.data.matchScore || 0,
|
||||
rank: resData.data.rank || 0,
|
||||
percentile: resData.data.percentile || 0,
|
||||
radarChart: radarChart
|
||||
};
|
||||
currentStep.value = (resData.data.matchScore || 0) * 0.04;
|
||||
} else {
|
||||
// 接口返回 null 或空数据时,使用默认值0
|
||||
raderData.value = {
|
||||
matchScore: 0,
|
||||
rank: 0,
|
||||
percentile: 0,
|
||||
radarChart: {
|
||||
skill: 0,
|
||||
experience: 0,
|
||||
education: 0,
|
||||
salary: 0,
|
||||
age: 0,
|
||||
location: 0
|
||||
}
|
||||
};
|
||||
currentStep.value = 0;
|
||||
}
|
||||
}).catch((error) => {
|
||||
// 接口请求失败时,使用默认值0
|
||||
console.error('获取竞争力分析失败:', error);
|
||||
raderData.value = {
|
||||
matchScore: 0,
|
||||
rank: 0,
|
||||
percentile: 0,
|
||||
radarChart: {
|
||||
skill: 0,
|
||||
experience: 0,
|
||||
education: 0,
|
||||
salary: 0,
|
||||
age: 0,
|
||||
location: 0
|
||||
}
|
||||
};
|
||||
currentStep.value = 0;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,559 +0,0 @@
|
||||
<template>
|
||||
<AppLayout title="" :use-scroll-view="false">
|
||||
<template #headerleft>
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template>
|
||||
<view class="content">
|
||||
<view class="content-top">
|
||||
<view class="companyinfo-left">
|
||||
<image src="@/static/icon/companyIcon.png" mode=""></image>
|
||||
</view>
|
||||
<view class="companyinfo-right">
|
||||
<view class="row1 line_2">{{ fairInfo?.name }}</view>
|
||||
<view class="row2">
|
||||
<text>{{ fairInfo.location }}</text>
|
||||
<convert-distance
|
||||
:alat="fairInfo.latitude"
|
||||
:along="fairInfo.longitude"
|
||||
:blat="latitudeVal"
|
||||
:blong="longitudeVal"
|
||||
></convert-distance>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="locations">
|
||||
<image class="location-img" src="/static/icon/mapLine.png"></image>
|
||||
<view class="location-info">
|
||||
<view class="info">
|
||||
<text class="info-title">{{ fairInfo.address }}</text>
|
||||
<text class="info-text">位置</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="conetent-info" :class="{ expanded: isExpanded }">
|
||||
<view class="info-title">内容描述</view>
|
||||
<view class="info-desirption">{{ fairInfo.description }}</view>
|
||||
<!-- <view class="info-title title2">公司地址</view>
|
||||
<view class="locationCompany"></view> -->
|
||||
<view class="company-times">
|
||||
<view class="info-title">内容描述</view>
|
||||
<view class="card-times">
|
||||
<view class="time-left">
|
||||
<view class="left-date">{{ parseDateTime(fairInfo.startTime).time }}</view>
|
||||
<view class="left-dateDay">{{ parseDateTime(fairInfo.startTime).date }}</view>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="time-center">
|
||||
<view class="center-date">
|
||||
{{ getTimeStatus(fairInfo.startTime, fairInfo.endTime).statusText }}
|
||||
</view>
|
||||
<view class="center-dateDay">
|
||||
{{ getHoursBetween(fairInfo.startTime, fairInfo.endTime) }}小时
|
||||
</view>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="time-right">
|
||||
<view class="left-date">{{ parseDateTime(fairInfo.endTime).time }}</view>
|
||||
<view class="left-dateDay">{{ parseDateTime(fairInfo.endTime).date }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="expand" @click="expand">
|
||||
<text>{{ isExpanded ? '收起' : '展开' }}</text>
|
||||
<image
|
||||
class="expand-img"
|
||||
:class="{ 'expand-img-active': !isExpanded }"
|
||||
src="@/static/icon/downs.png"
|
||||
></image>
|
||||
</view>
|
||||
<scroll-view scroll-y class="Detailscroll-view">
|
||||
<view class="views">
|
||||
<view class="Detail-title">
|
||||
<text class="title">参会单位({{ companyList.length }})</text>
|
||||
</view>
|
||||
<renderCompanys
|
||||
v-if="companyList.length"
|
||||
:list="companyList"
|
||||
:longitude="longitudeVal"
|
||||
:latitude="latitudeVal"
|
||||
></renderCompanys>
|
||||
<empty v-else pdTop="200"></empty>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<template #footer>
|
||||
<view class="footer" v-if="hasnext">
|
||||
<view
|
||||
class="btn-wq button-click"
|
||||
:class="{ 'btn-desbel': fairInfo.isCollection }"
|
||||
@click="applyExhibitors"
|
||||
>
|
||||
{{ fairInfo.isCollection ? '已预约招聘会' : '预约招聘会' }}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import point from '@/static/icon/point.png';
|
||||
import { reactive, inject, watch, ref, onMounted, computed } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
const { $api, navTo, vacanciesTo, navBack } = inject('globalFunction');
|
||||
import { storeToRefs } from 'pinia';
|
||||
const { longitudeVal, latitudeVal } = storeToRefs(useLocationStore());
|
||||
|
||||
const isExpanded = ref(false);
|
||||
const fairInfo = ref({});
|
||||
const companyList = ref([]);
|
||||
const hasnext = ref(true);
|
||||
onLoad((options) => {
|
||||
getCompanyInfo(options.jobFairId);
|
||||
});
|
||||
|
||||
function getCompanyInfo(id) {
|
||||
$api.createRequest(`/app/fair/${id}`).then((resData) => {
|
||||
fairInfo.value = resData.data;
|
||||
companyList.value = resData.data.companyList;
|
||||
hasAppointment();
|
||||
});
|
||||
}
|
||||
|
||||
const hasAppointment = () => {
|
||||
const isTimePassed = (timeStr) => {
|
||||
const targetTime = new Date(timeStr.replace(/-/g, '/')).getTime(); // 兼容格式
|
||||
const now = Date.now();
|
||||
return now < targetTime;
|
||||
};
|
||||
|
||||
hasnext.value = isTimePassed(fairInfo.value.startTime);
|
||||
};
|
||||
|
||||
function openMap(lat, lng, name = '位置') {
|
||||
const isConfirmed = window.confirm('是否打开地图查看位置?');
|
||||
if (!isConfirmed) return;
|
||||
|
||||
// 使用高德地图或百度地图的 H5 链接打开
|
||||
const url = `https://uri.amap.com/marker?position=${lng},${lat}&name=${encodeURIComponent(name)}`;
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
function expand() {
|
||||
isExpanded.value = !isExpanded.value;
|
||||
}
|
||||
|
||||
// 取消/收藏岗位
|
||||
function applyExhibitors() {
|
||||
const fairId = fairInfo.value.jobFairId;
|
||||
if (fairInfo.value.isCollection) {
|
||||
// $api.createRequest(`/app/fair/collection/${fairId}`, {}, 'DELETE').then((resData) => {
|
||||
// getCompanyInfo(fairId);
|
||||
// $api.msg('取消预约成功');
|
||||
// });
|
||||
$api.msg('已预约成功');
|
||||
} else {
|
||||
$api.createRequest(`/app/fair/collection/${fairId}`, {}, 'POST').then((resData) => {
|
||||
getCompanyInfo(fairId);
|
||||
$api.msg('预约成功');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toIOSDate(input) {
|
||||
if (!input) return null;
|
||||
if (input instanceof Date) return isNaN(input.getTime()) ? null : input;
|
||||
if (typeof input === 'number') {
|
||||
const d = new Date(input);
|
||||
return isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
if (typeof input !== 'string') return null;
|
||||
let s = input.trim();
|
||||
if (/^\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}(:\d{2})?$/.test(s)) {
|
||||
s = s.replace(' ', 'T');
|
||||
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(s)) {
|
||||
s = s + ':00';
|
||||
}
|
||||
}
|
||||
const d = new Date(s);
|
||||
return isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
|
||||
function parseDateTime(datetimeStr) {
|
||||
if (!datetimeStr) return { time: '', date: '' };
|
||||
|
||||
const dateObj = toIOSDate(datetimeStr);
|
||||
|
||||
if (isNaN(dateObj.getTime())) return { time: '', date: '' }; // 无效时间
|
||||
|
||||
const year = dateObj.getFullYear();
|
||||
const month = String(dateObj.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(dateObj.getDate()).padStart(2, '0');
|
||||
const hours = String(dateObj.getHours()).padStart(2, '0');
|
||||
const minutes = String(dateObj.getMinutes()).padStart(2, '0');
|
||||
|
||||
return {
|
||||
time: `${hours}:${minutes}`,
|
||||
date: `${year}年${month}月${day}日`,
|
||||
};
|
||||
}
|
||||
|
||||
function getTimeStatus(startTimeStr, endTimeStr) {
|
||||
const now = new Date();
|
||||
const startTime = toIOSDate(startTimeStr);
|
||||
const endTime = toIOSDate(endTimeStr);
|
||||
|
||||
if (!startTime || !endTime) {
|
||||
return { status: 1, statusText: '时间异常' };
|
||||
}
|
||||
|
||||
let status = 0;
|
||||
let statusText = '开始中';
|
||||
if (now < startTime) {
|
||||
status = 2;
|
||||
statusText = '待开始';
|
||||
} else if (now > endTime) {
|
||||
status = 1;
|
||||
statusText = '已过期';
|
||||
} else {
|
||||
status = 0;
|
||||
statusText = '进行中';
|
||||
}
|
||||
return { status, statusText };
|
||||
}
|
||||
|
||||
function getHoursBetween(startTimeStr, endTimeStr) {
|
||||
const start = toIOSDate(startTimeStr);
|
||||
const end = toIOSDate(endTimeStr);
|
||||
if (!start || !end) return 0;
|
||||
const diffMs = end - start;
|
||||
const diffHours = diffMs / (1000 * 60 * 60);
|
||||
return +diffHours.toFixed(2);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.btnback{
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
image {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.content{
|
||||
height: 100%
|
||||
display: flex;
|
||||
flex-direction: column
|
||||
.content-top{
|
||||
padding: 28rpx
|
||||
padding-top: 50rpx
|
||||
display: flex
|
||||
flex-direction: row
|
||||
flex-wrap: nowrap
|
||||
.companyinfo-left{
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
margin-right: 24rpx
|
||||
}
|
||||
.companyinfo-right{
|
||||
flex: 1
|
||||
.row1{
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
||||
}
|
||||
.row2{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
line-height: 45rpx;
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
}
|
||||
}
|
||||
}
|
||||
.locations{
|
||||
padding: 0 28rpx
|
||||
height: 86rpx;
|
||||
position: relative
|
||||
margin-bottom: 36rpx
|
||||
.location-img{
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
border: 2rpx solid #EFEFEF;
|
||||
}
|
||||
.location-info{
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
width: 100%
|
||||
height: 100%
|
||||
|
||||
.info{
|
||||
padding: 0 60rpx
|
||||
height: 100%
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: space-between
|
||||
white-space: nowrap
|
||||
padding-top: rpx
|
||||
.info-title{
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.info-text{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #9B9B9B;
|
||||
position: relative;
|
||||
padding-right: 20rpx
|
||||
|
||||
}
|
||||
.info-text::before{
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
content: '';
|
||||
width: 4rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 2rpx
|
||||
background: #9B9B9B;
|
||||
transform: translate(0, -75%) rotate(-45deg)
|
||||
}
|
||||
|
||||
.info-text::after {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
content: '';
|
||||
width: 4rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 2rpx
|
||||
background: #9B9B9B;
|
||||
transform: translate(0, -25%) rotate(45deg)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
.conetent-info{
|
||||
padding: 0 28rpx
|
||||
overflow: hidden;
|
||||
max-height: 0rpx;
|
||||
transition: max-height 0.3s ease;
|
||||
.info-title{
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
}
|
||||
.info-desirption{
|
||||
margin-top: 12rpx
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #495265;
|
||||
text-align: justified;
|
||||
}
|
||||
.title2{
|
||||
margin-top: 48rpx
|
||||
}
|
||||
}
|
||||
.company-times{
|
||||
padding-top: 40rpx
|
||||
.info-title{
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
.expanded {
|
||||
max-height: 1000rpx; // 足够显示完整内容
|
||||
}
|
||||
.expand{
|
||||
display: flex
|
||||
flex-wrap: nowrap
|
||||
white-space: nowrap
|
||||
justify-content: center
|
||||
margin-bottom: 46rpx
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #256BFA;
|
||||
.expand-img{
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
.expand-img-active{
|
||||
transform: rotate(180deg)
|
||||
}
|
||||
}
|
||||
}
|
||||
.Detailscroll-view{
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
background: #F4F4F4;
|
||||
.views{
|
||||
padding: 28rpx
|
||||
.Detail-title{
|
||||
font-weight: 600;
|
||||
font-size: 32rpx;
|
||||
color: #000000;
|
||||
position: relative;
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
.title{
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
.Detail-title::before{
|
||||
position: absolute
|
||||
content: '';
|
||||
left: -14rpx
|
||||
bottom: 0
|
||||
height: 16rpx;
|
||||
width: 108rpx;
|
||||
background: linear-gradient(to right, #CBDEFF, #FFFFFF);
|
||||
border-radius: 8rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
.cards{
|
||||
padding: 32rpx;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0,0,0,0.04);
|
||||
border-radius: 20rpx 20rpx 20rpx 20rpx;
|
||||
margin-top: 22rpx;
|
||||
.card-company{
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
align-items: flex-start
|
||||
.company{
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.salary{
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #4C6EFB;
|
||||
white-space: nowrap
|
||||
line-height: 48rpx
|
||||
}
|
||||
}
|
||||
.card-companyName{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
}
|
||||
.card-tags{
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
.tag{
|
||||
width: fit-content;
|
||||
height: 30rpx;
|
||||
background: #F4F4F4;
|
||||
border-radius: 4rpx;
|
||||
padding: 6rpx 20rpx;
|
||||
line-height: 30rpx;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #6C7282;
|
||||
text-align: center;
|
||||
margin-top: 14rpx;
|
||||
white-space: nowrap
|
||||
margin-right: 20rpx
|
||||
}
|
||||
}
|
||||
.card-bottom{
|
||||
margin-top: 32rpx
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
font-size: 28rpx;
|
||||
color: #6C7282;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.card-times{
|
||||
display: flex;
|
||||
justify-content: space-between
|
||||
align-items: center
|
||||
padding: 24rpx 30rpx 10rpx 30rpx
|
||||
.time-left,
|
||||
.time-right{
|
||||
text-align: center
|
||||
.left-date{
|
||||
font-weight: 500;
|
||||
font-size: 48rpx;
|
||||
color: #333333;
|
||||
}
|
||||
.left-dateDay{
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
margin-top: 12rpx
|
||||
}
|
||||
}
|
||||
.line{
|
||||
width: 40rpx;
|
||||
height: 0rpx;
|
||||
border: 2rpx solid #D4D4D4;
|
||||
margin-top: 64rpx
|
||||
}
|
||||
.time-center{
|
||||
text-align: center;
|
||||
display: flex
|
||||
flex-direction: column
|
||||
justify-content: center
|
||||
align-items: center
|
||||
.center-date{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #FF881A;
|
||||
padding-top: 10rpx
|
||||
}
|
||||
.center-dateDay{
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
margin-top: 6rpx
|
||||
line-height: 48rpx;
|
||||
width: 104rpx;
|
||||
height: 48rpx;
|
||||
background: #F9F9F9;
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx -4rpx 24rpx 0rpx rgba(11,44,112,0.12);
|
||||
border-radius: 0rpx 0rpx 0rpx 0rpx;
|
||||
padding: 40rpx 28rpx 20rpx 28rpx
|
||||
.btn-wq{
|
||||
height: 90rpx;
|
||||
background: #256BFA;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
line-height: 90rpx
|
||||
}
|
||||
.btn-desbel{
|
||||
background: #6697FB;
|
||||
box-shadow: 0rpx -4rpx 24rpx 0rpx rgba(11,44,112,0.12);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
1029
packageB/jobFair/detailCom.vue
Normal file
1029
packageB/jobFair/detailCom.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,836 +0,0 @@
|
||||
<template>
|
||||
<view class="document">
|
||||
<view class="head-bar" :style="{'margin-top': barHeight + 5 + 'px'}">
|
||||
<view class="go-back" @click="goback"></view>
|
||||
<text>生涯档案</text>
|
||||
</view>
|
||||
<view style="display:none;" class="person-info">
|
||||
<view class="img-wrap">
|
||||
<image v-if="customInfo.AllHeadimgUrl" :src="customInfo.AllHeadimgUrl"></image>
|
||||
<image v-else src="https://51xuanxiao.oss-cn-hangzhou.aliyuncs.com/Resource/xcx_sygh/avatar.png" mode=""></image>
|
||||
</view>
|
||||
<view class="txt-wrap">
|
||||
<view class="top">
|
||||
<view class="name">{{user.RealName}}</view>
|
||||
<!-- <view class="grades">{{user.GradeName}}{{user.ClassName}}</view> -->
|
||||
</view>
|
||||
<view class="bottom">{{user.SchoolName}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view style="margin-top:50rpx;" class="section">
|
||||
<view class="head">
|
||||
<view class="left-txt">
|
||||
<view class="icon icon-1"></view>
|
||||
意向职业
|
||||
</view>
|
||||
<view class="right-txt">
|
||||
限5种
|
||||
</view>
|
||||
</view>
|
||||
<view class="content" v-if="intentionJobList != null && intentionJobList.length > 0">
|
||||
<view class="list">
|
||||
<view class="item" v-for="(item, index) in intentionJobList" :key="index">
|
||||
<text class="name">{{(index + 1) + '.' +item.Name}}</text>
|
||||
<view class="cancel-btn" v-on:click="cancleIntention(index,2,item.EnCodeId)">取消</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content" v-else>
|
||||
<view class="empty">
|
||||
<view class="icon"></view>
|
||||
<text>您还未添加意向职业</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="footer">
|
||||
<navigator url="/packageB/pages/job/index" class="btn">添加意向职业</navigator>
|
||||
</view>
|
||||
</view>
|
||||
<view class="section">
|
||||
<view class="head">
|
||||
<view class="left-txt">
|
||||
<view class="icon icon-4"></view>
|
||||
职业兴趣测评
|
||||
</view>
|
||||
</view>
|
||||
<view class="content" v-if="interestResult != null && interestResult !=''">
|
||||
<view class="text-wrap">
|
||||
<view class="row">
|
||||
<text class="label">兴趣代码:</text>
|
||||
<view class="value">
|
||||
<text v-for="(item, index) in interestCodeList" :key="index">
|
||||
{{item}} <text v-if="index < interestCodeList.length -1">、</text>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row">
|
||||
<text class="label">对应学类:</text>
|
||||
<view class="value"><text v-for="(item, index) in interestRecommendSpecialty" :key="index">
|
||||
{{item}} <text v-if="index < interestRecommendSpecialty.length -1">、</text>
|
||||
</text></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content" v-else>
|
||||
<view class="empty">
|
||||
<view class="icon"></view>
|
||||
<text>您还未测评</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="footer">
|
||||
<navigator v-if="interestResult != null && interestResult !=''"
|
||||
url="/packageB/pages/testReport/interestTestReport" class="btn">查看报告</navigator>
|
||||
<navigator v-if="user.GradeLevel == 2 && !(interestResult != null && interestResult !='')"
|
||||
url="/packageB/pages/pagesTest/interestTestTitle" class="btn">去测评</navigator>
|
||||
<navigator v-if="user.GradeLevel == 1 && !(interestResult != null && interestResult !='')"
|
||||
url="/packageB/pages/pagesTest/interestTestTitle" class="btn">去测评</navigator>
|
||||
</view>
|
||||
</view>
|
||||
<view class="section">
|
||||
<view class="head">
|
||||
<view class="left-txt">
|
||||
<view class="icon icon-6"></view>
|
||||
工作价值观测评
|
||||
</view>
|
||||
</view>
|
||||
<view class="content" v-if="workValueResult != null && workValueResult !=''">
|
||||
<view class="text-wrap">
|
||||
<view class="row">
|
||||
<text class="label">高分价值观: </text>
|
||||
<view class="long-value" v-if="workValueHight != null && workValueHight.length > 0">
|
||||
<text v-for="(item, index) in workValueHight" :key="index">
|
||||
{{item}} <text v-if="index < workValueHight.length -1">、</text>
|
||||
</text>
|
||||
</view>
|
||||
<view class="long-value" v-else>
|
||||
<text>无</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content" v-else>
|
||||
<view class="empty">
|
||||
<view class="icon"></view>
|
||||
<text>您还未测评</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="footer">
|
||||
<navigator class="btn" v-if="workValueResult != null && workValueResult !=''"
|
||||
url="/packageB/pages/testReport/workValuesTestReport">查看报告</navigator>
|
||||
<navigator class="btn" v-else url="/packageB/pages/pagesTest/workValuesTestTitle">去测评</navigator>
|
||||
</view>
|
||||
</view>
|
||||
<view class="section">
|
||||
<view class="head">
|
||||
<view class="left-txt">
|
||||
<view class="icon icon-8"></view>
|
||||
人格测评
|
||||
</view>
|
||||
</view>
|
||||
<view class="content" v-if="personResult != null && personResult !=''">
|
||||
<view class="text-wrap">
|
||||
<view class="row">
|
||||
<text class="label">内外向:</text>
|
||||
<view class="value" v-if="personGroupList1 != null && personGroupList1.length > 0">
|
||||
<text v-for="(item, index) in personGroupList1" :key="index">
|
||||
{{item}} <text v-if="index < personGroupList1.length -1">、</text>
|
||||
</text>
|
||||
</view>
|
||||
<view class="value" v-else>
|
||||
<text>无</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row">
|
||||
<text class="label">人际关系:</text>
|
||||
<view class="value" v-if="personGroupList2 != null && personGroupList2.length > 0">
|
||||
<text v-for="(item, index) in personGroupList2" :key="index">
|
||||
{{item}} <text v-if="index < personGroupList2.length -1">、</text>
|
||||
</text>
|
||||
</view>
|
||||
<view class="value" v-else>
|
||||
<text>无</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row">
|
||||
<text class="label">严谨性:</text>
|
||||
<view class="value" v-if="personGroupList3 != null && personGroupList3.length > 0">
|
||||
<text v-for="(item, index) in personGroupList3" :key="index">
|
||||
{{item}} <text v-if="index < personGroupList3.length -1">、</text>
|
||||
</text>
|
||||
</view>
|
||||
<view class="value" v-else>
|
||||
<text>无</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row">
|
||||
<text class="label">开放性:</text>
|
||||
<view class="value" v-if="personGroupList4 != null && personGroupList4.length > 0">
|
||||
<text v-for="(item, index) in personGroupList4" :key="index">
|
||||
{{item}} <text v-if="index < personGroupList4.length -1">、</text>
|
||||
</text>
|
||||
</view>
|
||||
<view class="value" v-else>
|
||||
<text>无</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content" v-else>
|
||||
<view class="empty">
|
||||
<view class="icon"></view>
|
||||
<text>您还未测评</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="footer">
|
||||
<navigator class="btn" v-if="personResult != null && personResult !=''"
|
||||
url="/packageB/pages/testReport/personalTestReport">查看报告</navigator>
|
||||
<navigator class="btn" v-else url="/packageB/pages/pagesTest/personalTestTitle">去测评</navigator>
|
||||
</view>
|
||||
</view>
|
||||
<view class="section" v-if="user.GradeLevel == 2">
|
||||
<view class="head">
|
||||
<view class="left-txt">
|
||||
<view class="icon icon-9"></view>
|
||||
个人选科报告
|
||||
</view>
|
||||
</view>
|
||||
<view class="content">
|
||||
<view class="report-wrap">
|
||||
<view class="block" v-for="(item, index) in groupDataList" :key="index">
|
||||
<view class="row">
|
||||
<view class="item">
|
||||
<text class="label" v-if="index==0">第一志愿:</text>
|
||||
<text class="label" v-if="index==1">第二志愿:</text>
|
||||
<text class="label" v-if="index==2">第三志愿:</text>
|
||||
<text class="value" v-text="item.GroupName != '' ? item.GroupName : '还未选择志愿'"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row" v-show="viewScores">
|
||||
<view class="item">
|
||||
<text class="label">选科组合成绩:</text>
|
||||
<text class="value">{{item.Score}}分</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row" v-show="viewScores">
|
||||
<view class="item">
|
||||
<text class="label">选科组合年级排名: </text>
|
||||
<text class="value">{{item.GroupRank}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row" v-show="viewScores">
|
||||
<view class="item">
|
||||
<text class="label">物理:</text>
|
||||
<text class="value">{{examSoreInfo!=null?examSoreInfo.PhysicsScore + '分':'暂无分数'}}</text>
|
||||
</view>
|
||||
<view class="item">
|
||||
<text class="label">化学:</text>
|
||||
<text class="value">{{examSoreInfo!=null?examSoreInfo.ChemistryScore + '分':'暂无分数'}}</text>
|
||||
</view>
|
||||
<view class="item">
|
||||
<text class="label">生物:</text>
|
||||
<text class="value">{{examSoreInfo!=null?examSoreInfo.BiologyScore + '分':'暂无分数'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row" v-show="viewScores">
|
||||
<view class="item">
|
||||
<text class="label">历史:</text>
|
||||
<text class="value">{{examSoreInfo!=null?examSoreInfo.HistoryScore + '分':'暂无分数'}}</text>
|
||||
</view>
|
||||
<view class="item">
|
||||
<text class="label">地理:</text>
|
||||
<text class="value">{{examSoreInfo!=null?examSoreInfo.GeographyScore + '分':'暂无分数'}}</text>
|
||||
</view>
|
||||
<view class="item">
|
||||
<text class="label">政治:</text>
|
||||
<text class="value">{{examSoreInfo!=null?examSoreInfo.PoliticsScore + '分':'暂无分数'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row" v-show="scoreMatch">
|
||||
<view class="item">
|
||||
<text class="label">选科组合成绩匹配度: </text>
|
||||
<text class="value" v-if="groupMatching==0">暂无数据</text>
|
||||
<text class="value" v-if="groupMatching==1">低</text>
|
||||
<text class="value" v-if="groupMatching==2">中</text>
|
||||
<text class="value" v-if="groupMatching==3">高</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row" v-show="subjectMatch">
|
||||
<view class="item">
|
||||
<text class="label">学科信心匹配度:</text>
|
||||
<text class="value" v-if="subjectMatching==0">暂无数据</text>
|
||||
<text class="value" v-if="subjectMatching==1">低</text>
|
||||
<text class="value" v-if="subjectMatching==2">中</text>
|
||||
<text class="value" v-if="subjectMatching==3">高</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row" v-show="specialtyUniversityMatch">
|
||||
<view class="item">
|
||||
<text class="label">意向专业、院校与选科组合匹配度: </text>
|
||||
<text class="value" v-if="specialtyMatching==0">暂无数据</text>
|
||||
<text class="value" v-if="specialtyMatching==1">低</text>
|
||||
<text class="value" v-if="specialtyMatching==2">中</text>
|
||||
<text class="value" v-if="specialtyMatching==3">高</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row">
|
||||
<view class="item">
|
||||
<text class="label">意向专业: </text>
|
||||
<text class="value"
|
||||
v-if="intentionSpecialtyList != null && intentionSpecialtyList.length > 0"> <text
|
||||
v-if="intentionSpecialtyList.length > 0"
|
||||
v-for="(item, index) in intentionSpecialtyList" :key="index">
|
||||
{{item.Name}} <text v-if="index < intentionSpecialtyList.length -1">、</text>
|
||||
</text></text>
|
||||
<text class="value" v-else>您还未添加意向信息</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row">
|
||||
<view class="item">
|
||||
<text class="label">意向院校:</text>
|
||||
<text class="value"
|
||||
v-if="intentionUniversityList != null && intentionUniversityList.length > 0">
|
||||
<text v-for="(item, index) in intentionUniversityList" :key="index">{{item.Name}} <text
|
||||
v-if="index < intentionUniversityList.length -1">、</text></text>
|
||||
</text>
|
||||
<text class="value" v-else>您还未添加意向信息</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row">
|
||||
<view class="item">
|
||||
<text class="label">系统推荐选科组合: </text>
|
||||
<text class="value">{{recommendGroups}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="row">
|
||||
<view class="item">
|
||||
<text class="label">学校建议选科: </text>
|
||||
<text class="value" v-if="suggestGroupName != null">{{suggestGroupName}}
|
||||
({{suggestReason}})</text>
|
||||
<text class="value" v-else>学校暂无建议</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from "@/apiB/user.js";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
refreshIfNeeded: false, //是否返回刷新
|
||||
barHeight: wx.getWindowInfo().statusBarHeight,
|
||||
user: uni.getStorageSync("userInfo").user,
|
||||
customInfo: uni.getStorageSync("customInfo"),
|
||||
intentionJobList: [], //意向职业
|
||||
intentionSpecialtyList: [], //意向专业
|
||||
intentionUniversityList: [], //意向院校
|
||||
|
||||
interestCodeList: [], //兴趣码
|
||||
interestRecommendSpecialty: [], //兴趣码
|
||||
interestResult: "", //兴趣测评结果
|
||||
customerGroup1: [], //学科效能
|
||||
customerGroup2: [], //学科效能
|
||||
customerResult: "", //学科效能
|
||||
workValueHight: [], //工作价值
|
||||
workValueResult: "", //工作价值
|
||||
multHight: "", //多元智能
|
||||
multResult: "", //多元智能
|
||||
personGroupList1: [], //人格
|
||||
personGroupList2: [], //人格
|
||||
personGroupList3: [], //人格
|
||||
personGroupList4: [], //人格
|
||||
personResult: "", //人格
|
||||
viewScores: false, //是否查看成绩
|
||||
groupDataList: [], //志愿
|
||||
examSoreInfo: {}, //科目成绩
|
||||
subjectMatching: 0, //学科信心匹配度 0无,1低 2中 3高
|
||||
groupMatching: 0, //选科组合匹配度 0无,1低 2中 3高
|
||||
specialtyMatching: 0, //意向专业院校匹配度 0无,1低 2中 3高
|
||||
recommendGroups: "", //推荐组合
|
||||
suggestGroupName: null, //学校建议组合
|
||||
suggestReason: null, //学校建议原因
|
||||
scoreMatch: false,
|
||||
subjectMatch: false,
|
||||
specialtyUniversityMatch: false,
|
||||
myStudyCourseList: [],
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
// let pages = getCurrentPages(); // 获取当前页面栈
|
||||
// let currentPage = pages[pages.length - 1]; // 当前页面
|
||||
// //修改后刷新
|
||||
// if (currentPage.data.refreshIfNeeded) {
|
||||
// currentPage.data.refreshIfNeeded = false;
|
||||
// }
|
||||
this.queryStudentProfile();
|
||||
this.user = uni.getStorageSync("userInfo").user;
|
||||
console.log("user====",this.user);
|
||||
this.customInfo = uni.getStorageSync('customInfo');
|
||||
},
|
||||
created() {
|
||||
// this.queryStudentProfile()
|
||||
},
|
||||
methods: {
|
||||
goback() {
|
||||
uni.navigateBack(-1);
|
||||
},
|
||||
// 获取个人档案
|
||||
queryStudentProfile() {
|
||||
uni.showLoading({
|
||||
title: "加载中"
|
||||
})
|
||||
api.queryStudentProfile().then((res) => {
|
||||
uni.hideLoading();
|
||||
if (res.Result == 1) {
|
||||
let data = res.Data;
|
||||
console.log("datas====",data);
|
||||
// 意向职业
|
||||
this.intentionJobList = data.IntentionJobList;
|
||||
// 意向专业
|
||||
this.intentionSpecialtyList = data.IntentionSpecialtyList;
|
||||
// 意向院校
|
||||
this.intentionUniversityList = data.IntentionUniversityList;
|
||||
// 兴趣测评
|
||||
this.interestCodeList = data.InterestCodeList;
|
||||
this.interestRecommendSpecialty = data.InterestRecommendSpecialty;
|
||||
this.interestResult = data.InterestResult;
|
||||
// 学科信心测评
|
||||
this.customerGroup1 = data.CustomerGroup1;
|
||||
this.customerGroup2 = data.CustomerGroup2;
|
||||
this.customerResult = data.CustomerResult;
|
||||
// 工作价值
|
||||
this.workValueHight = data.WorkValueHight;
|
||||
this.workValueResult = data.WorkValueResult;
|
||||
// 多元智能
|
||||
this.multHight = data.MultHight;
|
||||
this.multResult = data.MultResult;
|
||||
|
||||
// 人格测评
|
||||
this.personGroupList1 = data.PersonGroupList1;
|
||||
this.personGroupList2 = data.PersonGroupList2;
|
||||
this.personGroupList3 = data.PersonGroupList3;
|
||||
this.personGroupList4 = data.PersonGroupList4;
|
||||
this.personResult = data.PersonResult;
|
||||
|
||||
// 个人选科报告
|
||||
|
||||
this.viewScores = data.ViewScores;
|
||||
this.scoreMatch = data.ScoreMatch;
|
||||
this.subjectMatch = data.SubjectMatch;
|
||||
this.specialtyUniversityMatch = data.SpecialtyUniversityMatch;
|
||||
this.groupDataList = data.GroupDataList;
|
||||
this.examSoreInfo = data.ExamSoreInfo;
|
||||
this.subjectMatching = data.SubjectMatching;
|
||||
this.groupMatching = data.GroupMatching;
|
||||
this.specialtyMatching = data.SpecialtyMatching;
|
||||
if (data.RecommendGroups != null && data.RecommendGroups != '') {
|
||||
this.recommendGroups = data.RecommendGroups.split(",").join("、");
|
||||
} else {
|
||||
this.recommendGroups = "无"
|
||||
}
|
||||
if (data.SelectGroup != null) {
|
||||
this.suggestGroupName = data.SelectGroup.SuggestGroupName;
|
||||
this.suggestReason = data.SelectGroup.SuggestReason;
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
// 取消意向
|
||||
cancleIntention(index, type, id) {
|
||||
uni.showLoading({
|
||||
title: "取消中"
|
||||
})
|
||||
api.doIntention(type, id, 1).then((res) => {
|
||||
uni.hideLoading();
|
||||
if (res.Result == 1) {
|
||||
this.queryStudentProfile()
|
||||
// if(type == 2){
|
||||
// this.intentionJobList.splice(index, 1);
|
||||
// }else if(type == 3){
|
||||
// this.intentionUniversityList.splice(index, 1);
|
||||
// }else {
|
||||
// this.intentionSpecialtyList.splice(index, 1);
|
||||
// }
|
||||
uni.showToast({
|
||||
title: "取消成功",
|
||||
icon: "success"
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
$image-oss-url: "https://51xuanxiao.oss-cn-hangzhou.aliyuncs.com/Resource/xcx_sygh";
|
||||
|
||||
page {
|
||||
background: url('#{$image-oss-url}/17.png') no-repeat;
|
||||
background-size: contain;
|
||||
background-color: #EEF1F8;
|
||||
overflow-y:scroll;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.head-bar {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
|
||||
.go-back {
|
||||
position: absolute;
|
||||
left: 10rpx;
|
||||
top: 0;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAABUklEQVRoQ+3ZOwrCQBCA4UlyCVsrQauQdPYewcNYWXoHK1s9gYeYdIKlracYWYggkgiTnccuaB3D/+1sYEMKyPxXZN4Pf0DMBOu6XpZluQOANRGduq7bc+/nNoE+/gwAq3c0IrJ72H/grtDQ9UPxAPBAxDn3/uaAkfjQvUXES9IA6fiANZuARrwZQCveBKAZrw7QjlcFWMSrAaziVQCW8eIA63hRgEe8GMArXgTgGR8N8I6PAqQQPxmQSvxkQNM0VwDYfJ3dJ53nuef/7+vZx+l+9W8pxE+aQNu2CyK6ZwsI4VlvoQDI/iFOCcF+iD/3fgqTiAKkMIlogDdCBOCJEAN4IUQBHghxgDVCBWCJUANYIVQBFgh1gDbCBKCJMANoIUwBGghzwA/EExFn3HdkF8AYIpvPrO9VDu8TVVUdiKghomNWH7q5W2Xserct9Af0K/AChQ/cMY9OGScAAAAASUVORK5CYII=") center no-repeat;
|
||||
background-size: 38rpx 38rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.document {
|
||||
padding-bottom: 60rpx;
|
||||
|
||||
.person-info {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 664rpx;
|
||||
height: 174rpx;
|
||||
padding: 0 20rpx;
|
||||
margin: 65rpx auto 20rpx;
|
||||
border: 3px solid #FFFFFF;
|
||||
background: #EDF5FE;
|
||||
border-radius: 12px;
|
||||
|
||||
.img-wrap {
|
||||
overflow: hidden;
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 20rpx;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.txt-wrap {
|
||||
.top {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
margin-bottom: 10rpx;
|
||||
|
||||
.name {
|
||||
color: #000000;
|
||||
margin-right: 20rpx;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
|
||||
.grades {
|
||||
color: #666;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
color: #666;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.section {
|
||||
width: 670rpx;
|
||||
padding: 30rpx 20rpx 40rpx;
|
||||
background: #FFFFFF;
|
||||
margin: 0 auto 24rpx;
|
||||
border-radius: 12rpx;
|
||||
|
||||
.head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.left-txt {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 32rpx;
|
||||
color: #000;
|
||||
font-weight: 500;
|
||||
|
||||
.icon-1 {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 10rpx;
|
||||
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABqUlEQVR4AexXQU7DMBBcW+09B0AcywvIE8oP+AF9Qg+AuFGugFTxAvoEfhB+0PKC5gxIcK7UmpkKqjSEdB1ZJIdEHtVxdmcn663tWFFc0dBFB5duDjgN9i/cB+xOFdSiEtDpyEBEeqK8jJFIRM6AnU0lAITHayYjk9VKTsrgnAwFF34pAr3yphKwoXCSvt+b5zIg8MvGXtHxE6Ag9DVZCzi8cj0UzgCFc10ETEH8TTzC89JCtFYS2sKnB9tCPsZiYdPO4ibGnCZweMTA6A/8CMBjdWPRFvIxVrcr871z12cGxqCkMX7+r0FEhGyNKaDK24VSGlsqCcVWhYcZqOIXzKcV0GagERlIUdK1wb7emqM6Ybke+wDZEm5eeR9uLkR+fNe9xXqc+IAClkvp532wufAIxvXdi68RRciX8sUMDvmtlmMY9mveGeD8v92ZGQr3JguOYRpU58CsRG8BmP8pTjo8ov8CdtZpllzT9xaAIHxLHmCKoIm5ZeMtYMs7wE0roBEZqPT/DTD9pEiZgSf2asLELhbygOBc1bgloxu2FbHh+/FT8KHL2F8AAAD//4kh6/oAAAAGSURBVAMAtjRliSH3kwIAAAAASUVORK5CYII=") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.icon-2 {
|
||||
width: 27rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 10rpx;
|
||||
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAgCAYAAADjaQM7AAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAH4SURBVEiJ1dfBa9NgGMfx75sWUxglRdCRophTdxAlTHpz2DGvQ8GT8yjMqwevsp62y8Sz/QP0KszjYIGO7SBjAUFY8VDX0aJisSsTgyavB9vNicmbdkvR3zHv8+bD+7wvb4gAWNq0LdAWpKQEWCQS6Yrymp07o2vbySFH0fSM9nQUEIAmpSyNAgLQQFgjxEaXgTFDNzF0cygsHadIT2UpmncpmnNk0tnD57W2w2p9mY7XioWJxY1JGVVg6Cb3Llcw9HxozWp9mdetF0osso1xIICb1iPGxwonw66cm1VC/dyZeHIy7Or52VgQgKHnlQdH0cZ4q+qncHZ6OExPZcOGQtPxmsNhnt/l24/uQJiqPrKNbz6txIY6XpPd/a3hsWqjEnt11UZFWROJeX6X52/nlXsBcMm4pqxJzdw3y1EFB98/U2s76Kks42MTx8Z297d49a5Mx2tSNOfIZfLU2k7ou5TX1e/5BRbIpLN8ONg5didevzDP1MUHVBvPWN/7e0tjXcT9eH439BCs71XoeC0+ft0JnT8Qporq9P7bH8//Bvtzz14KgZsEFAS8P8R8P5h+POU6SUD99DDpJgktbkw+BG6kgXpSyFHkLRAlTQgcEHZPTzRiadO2pNTWAAukC3w5bURKYQtBTkD/lym1EATythDkThvrke5P22GeWTkOvPwAAAAASUVORK5CYII=") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.icon-3 {
|
||||
width: 31rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 10rpx;
|
||||
//background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB8AAAAgCAYAAADqgqNBAAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAMMSURBVEiJ7ZZPSJNhHMe/z97X+W7TfLNWQxPfylLDYAqSSqEdhLl5MDwUnewQiL4XDwXRwTp0CyyS6Fb3Dl0U6qQpvovAKRFOpHQSOHGo7zT1nfvz66CTbW66iXiI/W7P8/y+v8/7+/PwvAxHsE6nTeLA9TJCB4DhEAs/eFf/2ZNpHF2mAllpaeNIN2TQGe/Vnr/tEXhjBR/hJuTR1qZMY7GMwE57L4g9u3iqYrrafLMiuj++NLI4vz5jYcCrNw2DPccK73TaJJ64TzrGWazmBlHKLxcSff78/b04vjQiRij8Ld02HAqXlZY2AuszcCZLY3GrZso5Jaby3QiuqV8XBjQtuCkgwu703xoYPjI8VZkBYCO0Dn9gBWJuIYx8fpwu3TYkhR9WZveqC+4V1966srAGladr4mKk04Z90x6dZoEzVjSXtAuJYN+WF+4VF4oMpY/6GwZZgd78xL3igm/LGxenJO+ypbmkXTvoNsRlflCZo/ZL/YkZ9Yf28sZHQ3Tv8fe7vrKCqrNlYlUySco2MCC9aY7N3On9EjILxbVPq99Ovpjosnq35ifqLM0oMpWmkiVtA+t02iSOdEPpTHPURhYG4d9eVnOZoGrhzQvnjMV8naX5MFncbQjpwtVc/cPyXgNnkuzSfYuey02ZcayV5l+FwBkEI58nXiq4pqssrDlcBEDP5QpXxOt5c2vTIIR5PhLCfIALiLHTm4n5A8vwB5Yz0mxHAiCQyucEcz6EdNuN7lVXtNxNACYBqASSGDERDJMAAIKVGKkMzANABGAFMLxzlOAbEyfRFwD4gP71vq+SFQfJo7YmAOgas3d0K/a5mLMh2WnvBXaGVFYc1Om0ScDOTZEVx1DUt1uxz3WN2TsAQB61NcmKgxJZGb9qx2lZeBaehWfhWfj/B2e7v1DvCSQBAAOTCOQBgN0nUtxbg0kgqMRITeoLIPYs6pskjidC1MNkxTFRZCq1FujPnFC+gE/zwre14OEJJAq8SSsUzIsnBV8LrmqMmIUnwvNZdapv1j8lnRScQB4Cev4BQmp+U4L3kQsAAAAASUVORK5CYII=") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.icon-4 {
|
||||
width: 32rpx;
|
||||
height: 31rpx;
|
||||
margin-right: 10rpx;
|
||||
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAYAAACGVs+MAAADWElEQVR4AbRWO2wTQRB9ewln0yBDg5AoHKQ0FCRRGiQKYkGFgxRLoUTYBTWmIHEX3DlpYiihsBElkRwpcSqQI6FIaSISCppI2AUSoiEWTUIS3TKz5zvrfvadZUY3t7OzszNvZm93T8MgVMsnUC9UiJuKtxZXUSskB3EVHQAH12MNCpYl5qBJSJGHLmvgMVJGeaID0OPPADEJD5EuFlvyqPsoogFQGcp8oE8p5qIuRTQAZvaJQABAEjqeIAKFB9Av+27QbJQqhAfQP3sLQqQqhAOgtliPtbdCd9ss6i98PtSugSV5AfDEjYU5bC7kwft7s9CgdW0CIoHwRNtz5Avqi8SFivLFPjkRtZRdRyYADmoeLBKgiZpWg9BWwftbYAYDk+AqZJUv9qmjCT1+hK1CAxsF5VczPxjNOlgGDhVposQMNDQ4toYYKohWXgyNdLmqQYLWC0Ohuas3Ubk1j+TFyyH9iUn6BmQbQ6DJS9dQm36M7PVpMJCwLgmAeBXWOMguMRpXwXm8fXaM9V/fWAzDVQ3pUhWQ+/2suawzV274mi2N37fLXjz8hNbxka+dU0kx06UiVYDUp39TENhGAHGGzdQCGrefYmn8nsOKQeXH7igdZ15u7Si590uug2OSkQkgU27jQSlFfaoGvV1P+/zEzuolZWuBYGCViXllzVnnDj4ouc+rivRyBhyTDE0AJKgnXcpR6wsitfvWA6Iy8cgufe5gDQyU5vd6KLiKYds4AbCaQQh4loMzdIOwvvZycwfbv7+jJ7FP9u0y8gJgA4l33LiZQUx9fo39Pz/tIdYVDz/a/UAhwKc/gEAvUGVO7b5B9ceeWpLM3nul6zHFHDIM3/PGH4CQE+Ys/zevde7rGsYaK45q+Ft3tCPibkdyNP4AJIZ2PMMiQ/DNaPXs1h+A71+vPWcwQciQAMwfhuFXgG9c07cjAW8F9Av/IXgn5mjcUwUvgI5tqEaCzgvZ9x6BRedowUVeAKdnHiPXHO62YCCF2VKKjtUpJfNBwyOBLGkbnhA7DbwA+IyWxnOnmd1jcDmkS2N4WKLsO3qW+S5hUEE3q5RF6/zvzFKNFwCrZ1fKMIwMzKwoqOQym4HV9c1GPsxA0stTNJKjK36duE1/XAw0B/ZJA+7nHwAAAP//fvvjBQAAAAZJREFUAwCMpRtDiL0m1gAAAABJRU5ErkJggg==") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.icon-6 {
|
||||
width: 32rpx;
|
||||
height: 31rpx;
|
||||
margin-right: 10rpx;
|
||||
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAYAAACGVs+MAAACGklEQVR4AeyW0XHaQBCG/2VSgCuIzx04HZgOQgdxB9Fk8ox5zmTkDuIOkg6gA9yBDypIAR7W351sYEDCaCzkF+9o7w7dsv+/e8stAy/DVy/PH1DvWecJeyD5WFJQ/3IpeQkBsdB7SUgE3gs8434Q6CsD93q0IUV3m/O+NfRAwO8kG9rPOJMGE+3IiQnYjRXLayvi/wp3Na7mzXhCAgk8riP28vMfyb5rR1oQsBvJLir1vbPUtqysIOoMzm135uX5XLJvqpEjCRipjBOcxkqXhTIZca7aFlJtI/sRM0HAuWEdcDVedkcQ8FtAX6IJOD0TwjvILKhsQxUloTbk/T8h2CXwKUtmxobnFQJ+RxERrbi1A8D+lxWNK4wB4LME4MyKRTqaL1bEeyHsEbG/Co6pDhHA8fI6GeEQsOwQx0pr6sFTN7vSswBO+qFXBs4624bnrYNTEwEisdHmm6uSdQJnWj8A+JQCQ8MVJC/RseRUuyCpo6SOAJHYaBNR/vkQVaM/suBTgCk2JzONdrUbdQRIfYzJuorIDoEnszdpHQH+IaUiS5G3j6gtmzoC+EjAp40ckPw0EMh7vQwfBFIGcsX3ku99kBkELN12u01l37T7NwRukwEXDr/7BU1kYVb0qhdWxJSB7kNr45EjaGPevW0jAa7h4L9oMl1oGXYb2TqSWgKApwbzoE80mS5UPvffoban1BKAHh1RSXVqeQIAAP//TF3sLQAAAAZJREFUAwCBRGeYQHx5OgAAAABJRU5ErkJggg==") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.icon-7 {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 10rpx;
|
||||
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAMmSURBVFiFrZfPTxNBFMc/0xaxISGLhgMEY1UuxBgK6RGT9iBX9eTR9catBWrire3ZxtabN8pfIPEIMW30SkxJ5KZxjUm9GNiYSKmA42Ha7rbsrxa+SdPJzNv3/c6bmTdvBANCrqET4ikQB+pAQRSpDeqnAxGYOEOMCBtA0mG4NqwQXwEyQ4wwOQS6rzdJhTMKooxxKQLkGjqCHIJYUIeACZQ55bUoYw4lQK7zCCgNSOwkpCCKlAMLGCjcQSExEDxz2x9dATJLDshfGvF51BCsipfUewS0Z129YLiDwkSQsouItI9WMPKoBgkdpufhqgbHJjT24PMWHBpBPGhISkCq0yFklkNA8yVeSsNy3t1mtwLbhUBCRNFa+ogv+UQM9LcwHff2mtDhdhLepIJGoyvAG/3kjTp8ranQT9yEO0n1A7gWg5UqlBeg6ZsCAghI6L3kH8vwbrXXZqeg7J5sWCKW0qo/AEKeo/fTVnu3cp7cPradt32XUfsmDIwOKyCq9c5+22dGOwUr7FENFuOwiPWbdBMgXS6OKRt50wy2sRq2HDMTsxZ4FJh1FuIegeNgm6iLcWDMx6YtRL6gKp8T9xZgn3FUU8fRDTPAXeC6LWpHhosxECaJVCLcBTRNddw6WM45240CN4C5HIy0U8qJCb9qzvYWNCQl71Owu2m1Ezo8cBAxBsxmYC5v9X3xvIHtiAu5zjfPi2ilaiUagAMD9rdUIopqcO8h3LKNHxnwfkFFwQ2fgJZq+guIakqEXyrukH9Iea9/n4AQwqdsappQWuhNNE74XlEz9yMHOLWaQq6zEbgCmoip5ZieV5EBONiDVsU75Ha0UBHoCrhoQTKOOoJByffphh8gJMoYnJGCIR8XfwLa/QT2esmBWm9RmiUJ5HB+fLhjBpULnPAb+NH+74Uqz5y+Gaosn2yL6Nx+LcAADhxsBVucsCrKGK4PE5lBI0IayOBXNXUQBqb4iwAaXOGs3ykGkoJ4RcXS4oOBhLSfZoBJhBygo1KugaAiipy70wd7nLo9WiQGIR731/wyg8YIsf7+oQR0nWZJIkgjSQJ1/rFpD+mg+A9dEv37gzwmcAAAAABJRU5ErkJggg==") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.icon-5 {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 10rpx;
|
||||
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAKSSURBVFiF7ZdNSBRxGMZ/s7Pp6n44SplEwUBGeSjWPhErBmI7FQ2UFFi0EXTNoIsn7VLQxfZWEhh0KiIvnjqkh8AOsbtgFB1qIy1py7RWzY216fDfcdd1x51dZe3gA8uwzDvP87zvfz6eP/zHUNeSqw8wgBgQLNGMAnQAg2muSDEXx9SDLmPPSY/hrJSMNEEfoNm4VgN6gEmnSzJ2n/AY7XcbTI4lcFqxuLwO9JubCFyvI/wkwatHiWAingoCD4BLOeUKYlKnAK12m5N9bT78uofqWpmf4ylLt5YGTLjrZI5cUWi9XMO757OEnyZa3r/4bZ5WgYtAhyShNB6t5sA5H42HqwrR2jdgwiFLNAXcNAXcO5EIzyVSvbdbRm+562Sl+bSXvWe8KFts0xVvYBEMmmWn3A0oF+43UL+joiQaAAfi5ooh1rHscJB5zPQya0eASGlLsHJogB/EBNYU6wbWDawbsDQwPTHPzI/5VRGZS/wt2kBoLJokdHyU/s5vfHmdLEn4U3iOx9fi9LZ9BvEZXwKrN+EdYCiVNK6ODEwHRwam2eqv5FB7DbuOVSNvkCxFU38M3j6b4eXDX4y/SU4BQ0AofbRtACCKCB43AG0smuwai8ZVz0aZ/Wd9bG+t2pxT//XD8Oxwf+d3fWZi/iOi4xAwtYwGIKKSgYhRaoFajXRelCtEVGvrqTfO32vo7o6prnRNIQ4F6MrSZTLrj93spyK+ojFE6CwkaprvyaOHTia5Zv9i2JvKcjC7jeThH0Sk5gWoZMJJvuIg9kOLRv6mJhFNaYUIdDJ7g1wCqyXSyD9iswG9iAYWoCI6zzdCc9OSvfnIPd9ViqgV/FgvUdEjXimCLO7avKHKHmxVVncTW378A9QT5wUjCfL+AAAAAElFTkSuQmCC") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.icon-8 {
|
||||
width: 27rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 10rpx;
|
||||
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAgCAYAAADjaQM7AAADJUlEQVR4AeRW4VnbMBB98gRhgzAB9gRUHwOUTFAyAWECYILABEkngAX62UxgZ4J4AzKB1fdkK7ZjSGmpf3GfLtKdzvfuTifHET5KaT5Fml8hLVJyTn5tmPJmiV/5gvuTY+7+DOZBihVgtmTO+AYgBiDHYspugcgsIZuXze17oMfBUkYrB8AVPkYTVO4OMMw8j3FA74MpQhhG23uipPTMLO7odL7nyBAAGYAdapoCJmWGPcC3wZSRjxCBSsDNYeNT8gznZ/e4SNZ7lmxjS5uED6zJGixxH3AIluY8A9PNaE0AgiTBiRwNWWdb4ZK2c585PAnwya/4MwSDuaU+jMw/HKQwK6A0p6Og0BxdE2TpS6dM69JqY0rdlRZ9MDkBmBkacvc0nLDFeeDFPkL4gIx0K+5taTMFqnvAWdikgKiqfnIqyRzmVjZ9MJgf3Amj5IMZBYHroC/5gGaqoEaYAlDEJe3EO84ZAtmkZAM9NqJs4wMwXOKQbFJ3n2+QpGAmK5p07WIGIWdUH4wIBfYUnbdgOuD6oobt9kx0BjapG6RyLzR4JofBLM0yCATuVqApo3ZdL7PWufYEXAdQS+FXLW/jGUU6cjewMTs1nlFuhvnOhUoPqDspNOMoGG3MkpEeBkG9hoCSB616bOM5LPUKNDLXnb1dW8aOtrPk2ZgtXvz7TuVpz0Zn2THsLfXC1hsEaO35dmnBKsR4mybsqjvAsPXNlg3yStb8hHSz9IH4YIoV0oK64pW2aqIuEEhNZrqg/ZS59+6YcEeOmLVb+EDqV5uuAXXQPgYUmazOLOLtB+QAo1FVPUa+ASpGOBqKd5yxaVjGOquJV4324/gqAyLWfDEahnfsbphVpqXOrNBiJF4TaH8XCeZmgDtFZEbI0PnyhUQiIu/IJapqE5RjzcxsLNdDv18BzCZqz3KY/P/THJTR6W9813GvddGRP7Xsg+l/SNcALuF1OIGNTzjffAqh83AfTBs22UFfSJol/xsXgHmgn96xDMHwV6Qy86zpuHKsgLOsxAlsnMCeUe77+giYopNTRovwpSWnp3Qqx/xWpOOLRJlkOFKR3wAAAP//prmx5wAAAAZJREFUAwAwoC6lMoqQ5AAAAABJRU5ErkJggg==") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.icon-9 {
|
||||
width: 26rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 10rpx;
|
||||
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAgCAYAAAAMq2gFAAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAHESURBVEiJ3ZcxctpAFIa/X5MZ4845gcUNnBNk0nhUkgqTCt8gnAB0AuwbyI0hVXCnSRNuYN8gOoKrgBu9FEjMSsgWxIhk/Fc7b7Xvf//u27dPAgi+2RCjD/jsFwkiirsKlZGM9kxQhBh5mZJmYfQ99r9dVfC9A5AAcDCid2WDwUzGIO4pce3BxHwTY0HHtacpn3980cy1nd9ax/P47to2FFWRAMQ9JTIGu+lw/AZTs4LDC+mlBeXvt8XbS4Z/l3XBxPyqZMjn8nFVtuXYKutMjF2HLomJcW3oz2Aj65rC20uG/4hIjDDaBg9NEiVxV2FW566bIzLCfBj3FAFJcZpHg8fXEiWZc85vrQOgtKAqkfHhaUEbiOqICpXB4ErGHcByuToTp0OaLZ6Ijo4ZCk4wQqeCXAYTuylJ+Og2PYULu1zwfn6p9VYEE/MRPwEf41Pc0zwnji/UzgOJuwopIVv7q1JR65j7YGp5lBicCU5WITEE5svfXLda3DhqR8HU+mye35n7sO1WgjJVecQm7teB1GC3C7tStR5vSwJ/UVSVMkg9TgVfd1m38R7VwTzGLzYVz8CjdIgNIfFQ/WV7NUQkOMxvyx8J8rz3lpEgKQAAAABJRU5ErkJggg==") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.icon-10 {
|
||||
width: 27rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 10rpx;
|
||||
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAfCAYAAAAWRbZDAAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAL6SURBVEiJvZY/TBNxFMc/r9dKQ69QjG0RNDmQBBbiDUJqXBCcaRyMiWEyYXBSF4yJDAQTBwdxYlIXQsJmd8HEBHVgKGHRmEATA+Gf4QTqn5T25wAt0N5xUMDv+N6993nv/d798hPKlFEbMrScZioRQ0QuK+gQRUiJGppdXB2wixHXpKFQCJ/P0DRMUVxWgonCRAg5xWT/ZGpSlmUV272u1YKR96vd0iyUeitISgnT2SzJ1MpKsrE2PCdg4CcElMKMcNjUNF6gMIEQnt12RWEpSIqQVEpNe4Tk80cXrI6Y3/J6vYZSOQPAA6bevpJ0m5IUqrFRle6xNE28mke8Z3ziL/YHdQ893TXEb1SlAlcmG/K5FKQKHyksEZJZMgNeJxDA+mbO8VwAWIaF5QwKSe0178u5PSZTw2cUzmxyrIlgQCt8k3j3k/6hReJdVQw+PF+wD4+uMjz6g8EHtcRvVO8Uv63ZxZUGu5ouRcNrgFmA7QUdVQId6alrc8V2lVM39faPSSVYAobXLrhMpFECE9l3DJ6Tg7nrULCRxBrXbn9jeHT1WDDXMU583iQxvg7A8OgP6iK+smGunW2kczQ3VvDq2UWux3QWljOnB+vuqub1s4u0tVby8kk9PfGasmGOY+y8qgO7/1Jefb0RmhsqaGutPDlYMKCVgPJysrvpv66+bWcb6SwLSxnW07l99vqIj7qoj410li+zf20TtjRWFG6jra2tlCvs/tN5pmZ+2yabHGvi7uPvfHWAdcZ0hp7U2/psYT3xs7S1/imxBwMawYDGvTvn+Dpb6ge4csDi2MI6YzqdMd0xyM1/JNhIYo2pmV+sp7OHStLS6KevN1IebGrmFxOfNw8FAlhY2iof5nTAx5Xj6k98OnxnxWprraQuWnph28L6XyweaYzFclp/W1hfb4TrZWxbAXbVPtYWVhf1EY+Wd/8dpNO9G/1+C0DU9lNdLtWG3wMdwYDnWC8sO80vZ1Kw845UWNJ7yzDHP6TfiGCeKGmvFJZCDfwDa27tlQaAF3UAAAAASUVORK5CYII=") no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.right-txt {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
.report-wrap {
|
||||
padding: 40rpx 0 0;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 35rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.item {
|
||||
.label {
|
||||
color: #999999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #333;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.course-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
padding: 40rpx 0 15rpx;
|
||||
|
||||
.item {
|
||||
width: 320rpx;
|
||||
background: #F8F9FB;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.img-wrap {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
width: 320rpx;
|
||||
height: 184rpx;
|
||||
|
||||
image {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
padding: 10rpx 20rpx 0;
|
||||
height: 76rpx;
|
||||
color: #333333;
|
||||
font-size: 28rpx;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
/*! autoprefixer: ignore next */
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.count {
|
||||
margin-top: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
padding: 0 20rpx 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.text-wrap {
|
||||
padding: 40rpx 0 15rpx;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
margin-bottom: 25rpx;
|
||||
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.value {
|
||||
width: 500rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
|
||||
&.w450 {
|
||||
width: 450rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.long-value {
|
||||
width: 450rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
/*! autoprefixer: ignore next */
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
padding: 40rpx 0 15rpx;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 25rpx;
|
||||
|
||||
.name {
|
||||
color: #1677ff;
|
||||
font-size: 28rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
width: 92rpx;
|
||||
height: 48rpx;
|
||||
line-height: 48rpx;
|
||||
text-align: center;
|
||||
background: #FCF6EC;
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
border: 2rpx solid #FAECD8;
|
||||
font-size: 26rpx;
|
||||
color: #E6A23C;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40rpx 0 25rpx;
|
||||
|
||||
.icon {
|
||||
width: 128rpx;
|
||||
height: 128rpx;
|
||||
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAATlBMVEUAAABLac1KaMtNbM5Lac1IaMxGZMVPY89JZstNW9ZKaMxJZs1LaMtLaM1Jac1KaM1KaMtKatBKZ8xKaMxKaMpHZMhLaNFKac5LaM1MZ84Bwi/qAAAAGnRSTlMAM4AZmR8IEHAFeFBAJzhgSBNoWGAMLIqVOe7t0vgAAAVXSURBVHja7ZmJrqMgFIYFyiKLUpf2zvu/6Hix5UhprVAaMxO/m5umafQ/nFWwOjg4ODg4ODg4+M8h1b6wvtoXinm1Ky221Z4YjHd1AZUYY7GbBURhh9S7lALqMKD2MIGZ9i5Pq51o8ITYYfWBBfv2wu6rfYBR1OiJBhH2KhWxi/8XksDoQeAFsm3IUxc4S2XhXkCVwE+QUbq7tTMksGjKqXNQj2kb9iRUFvflXKAFXkVq9iQQrFh/A/mubyiZV8hNs3CLoLHXSnnfqwyIRz82Lb7RRwsuu3yhXqyIWnmLQ1N9AX0P8opDmb6ZoIs/TLIOOxR/E6Y5EB93wJY/1Reo8tScUnO5XIwxZKwrjxFzRbLPpoh9pg/lXBODAszZ28BvxrIPOt3vCmgF9KFbR4OeQL0JdjY3v9z0w2OEDRKrjuQjE/SnmYiCEKDgdgStQAILPqjGZS/h0unD8tcw9dKCoVe6MTxn1i8rwiX1Tf+C3nBhPm2A1lL2QUVASjO0AQZ9OxrWGTAXADqvH6HtFpB4WNPsDmzB/xu41HBliGJ5DpDzdWYt+S6RBcwFgQfDuuNZDtBv628Mf6ZQvioc1l2OAwR7lwDG6YUGTfwu3D+Q0janOyHoJybFAANXo9CbInEq+gwY0RrkMUJn74LhIZ4mOQLWOyCBWUbh4IiCQwxSIkA3t4AoCyjEwCFSH1WUjwBFidBZMRzLMtUDwk+BC0rFTwSoPHDIRpivAYaSGf0gYVFKb4X4rCUoGeLXTJdjrU/OwZwUgDpYPJcQGGtJOQhFmMbFp52F+by5BuARX+TkIGThcB8HXKQ+KjdyMT1QBrU3wOsnnFQwhWeGTw1wtzASpySAM7iMAcrdQmOc1gKIwAUN6Oa7SbJdf3aYavNzAJLQkXJq7QPWuB2RzKkCKEPvyoRjIi5vDptDxzL7gIF7pY0gJrzDjM9cgpKhk7wG929HwRXEN9IRJcO5Fn75CdBlwsr79KhRKtrLJ761aZfb2sH3YpooL66wIUrSJ8El1iVBcgysPJ3AAJ2+EaGBOSqtE+j+ejqdflwmCbjbVlT46C7c14Q66OVpwjlAIN65RpLE4NIu3JujrTtTK35OMz/uQI1mHNj14VaCwzg4o3WUuJ48rfEJTaok7EPdDBBFsxZ3eQKu4g9UdFulQR8aF3Lf144n/qjueloge4RqqGhaJdI9HLkPMMh5vPLZ7wDu//iNocnYjsP4aBFbZIHgUSVY1cmbOKjrxVkdgxpMA8F7KMrus6GHM0I9SXfYpXsQd/UnPCvsoYckQgX2iE7djmmRnpTB4wG4s8hDFgUsWeZ7KfyS6xPxaemRPpEfHZVyK/ErfsDtsrXRQelSX5V8OQhcf6ZG27WwcIDUy4fqj1+WMdpY1QlwhhgGpRtDyZvDcgK7kEJQEb6Lqs9RWzSkhgECDzWl4MKfdIIN3ogLBfWKWdAvbEH8VrIex5HVkbOgdRWEd9jR8ncVXF4fXAvn7usNRJXXhx0TDIoQjgb8zRencGThaBvCgoIdcMKJeD60xYDolbJa9UOHAYGqrwImAAXl0aA3mGDlC3VIz0zI1lMMajv8QKdMAfcmTFBGtVKDEKIbhr7Z/lZuPUNbOEf7EsxWu8J7cHEm9S/sKe6n9fW3GEubrMjYyPl5gmzkPMH5yFhsTyP5ZuFJFjTzmWxZTsxmkzQ/k+KcuTODvRUvpE3df2QFq9flOQFo/j8ox/B6RZ+UhEbruFG/NuAce4/mfcKXmA0h+FgdiBbD601JmOWElThAEu5bhimwsBHRtNXHjQj4fismQSsuCwyj8ffPf8AwOjg4OPjX+AveIUqXZPVRsgAAAABJRU5ErkJggg==") no-repeat;
|
||||
background-size: 100%;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
text {
|
||||
font-size: 24rpx;
|
||||
color: #A4B3E5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-top: 10rpx;
|
||||
|
||||
.btn {
|
||||
width: 400rpx;
|
||||
height: 80rpx;
|
||||
text-align: center;
|
||||
line-height: 80rpx;
|
||||
background: #1677ff;
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
border-radius: 60rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
497
packageB/priority/helpFilter.vue
Normal file
497
packageB/priority/helpFilter.vue
Normal file
@@ -0,0 +1,497 @@
|
||||
<template>
|
||||
<view class="help-filter-page">
|
||||
<view class="header">
|
||||
<view class="back-btn" @click="goBack">
|
||||
<uni-icons type="arrowleft" size="24" color="#fff" />
|
||||
</view>
|
||||
<view class="title">筛选和帮扶</view>
|
||||
</view>
|
||||
|
||||
<!-- 筛选条件区域 -->
|
||||
<view class="filter-section">
|
||||
<view class="filter-item">
|
||||
<view class="filter-label">人员姓名:</view>
|
||||
<input class="filter-input" v-model="filters.personName" placeholder="请输入人员姓名" />
|
||||
</view>
|
||||
|
||||
<view class="filter-item">
|
||||
<view class="filter-label">身份证号:</view>
|
||||
<input class="filter-input" v-model="filters.idCard" placeholder="请输入身份证号" />
|
||||
</view>
|
||||
|
||||
<view class="filter-item">
|
||||
<view class="filter-label">帮扶类型:</view>
|
||||
<picker class="filter-picker" mode="selector" range="{{helpTypes}}" bindchange="onHelpTypeChange">
|
||||
<view class="picker-text">{{filters.helpType || '请选择帮扶类型'}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="filter-item">
|
||||
<view class="filter-label">帮扶人员:</view>
|
||||
<input class="filter-input" v-model="filters.helperName" placeholder="请输入帮扶人员姓名" />
|
||||
</view>
|
||||
|
||||
<view class="filter-item">
|
||||
<view class="filter-label">所属区域:</view>
|
||||
<picker class="filter-picker" mode="selector" range="{{regions}}" bindchange="onRegionChange">
|
||||
<view class="picker-text">{{filters.region || '请选择所属区域'}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="date-range">
|
||||
<view class="filter-label">帮扶时间:</view>
|
||||
<view class="date-inputs">
|
||||
<input class="date-input" v-model="filters.startDate" type="date" placeholder="开始日期" />
|
||||
<view class="date-separator">至</view>
|
||||
<input class="date-input" v-model="filters.endDate" type="date" placeholder="结束日期" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="filter-buttons">
|
||||
<button class="query-btn" type="primary" @click="queryData">查询</button>
|
||||
<button class="reset-btn" @click="resetFilters">重置</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 帮扶记录列表 -->
|
||||
<view class="list-section">
|
||||
<view class="list-header">
|
||||
<view class="list-title">帮扶记录列表</view>
|
||||
<view class="list-count">共{{helpRecords.length}}条记录</view>
|
||||
</view>
|
||||
|
||||
<view class="records-list">
|
||||
<view class="record-item" v-for="record in helpRecords" :key="record.id">
|
||||
<view class="record-header">
|
||||
<view class="person-name">{{record.personName}}</view>
|
||||
<view class="job-tag" @click="showJobRecommend(record)">{{record.jobTag}}</view>
|
||||
</view>
|
||||
|
||||
<view class="record-info">
|
||||
<view class="info-row">
|
||||
<uni-icons type="call" size="14" color="#999" />
|
||||
<span class="info-label">联系电话:</span>
|
||||
<span class="info-value">{{record.phone}}</span>
|
||||
</view>
|
||||
|
||||
<view class="info-row">
|
||||
<uni-icons type="card" size="14" color="#999" />
|
||||
<span class="info-label">身份证号:</span>
|
||||
<span class="info-value">{{record.idCard}}</span>
|
||||
</view>
|
||||
|
||||
<view class="info-row">
|
||||
<uni-icons type="location" size="14" color="#999" />
|
||||
<span class="info-label">所属区域:</span>
|
||||
<span class="info-value">{{record.region}}</span>
|
||||
</view>
|
||||
|
||||
<view class="info-row">
|
||||
<uni-icons type="person" size="14" color="#999" />
|
||||
<span class="info-label">帮扶人员:</span>
|
||||
<span class="info-value">{{record.helperName}}</span>
|
||||
</view>
|
||||
|
||||
<view class="info-row">
|
||||
<uni-icons type="briefcase" size="14" color="#999" />
|
||||
<span class="info-label">帮扶单位:</span>
|
||||
<span class="info-value">{{record.helperUnit}}</span>
|
||||
</view>
|
||||
|
||||
<view class="info-row">
|
||||
<uni-icons type="calendar" size="14" color="#999" />
|
||||
<span class="info-label">帮扶日期:</span>
|
||||
<span class="info-value">{{record.helpDate}}</span>
|
||||
</view>
|
||||
|
||||
<view class="info-row">
|
||||
<uni-icons type="time" size="14" color="#999" />
|
||||
<span class="info-label">下次联系:</span>
|
||||
<span class="info-value">{{record.nextContactDate}}</span>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="record-actions">
|
||||
<button class="detail-btn" @click="showDetail(record)">详情</button>
|
||||
<button class="follow-btn" @click="followUp(record)">跟进</button>
|
||||
<button class="recommend-btn" @click="showJobRecommend(record)">智能推荐</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { useRouter } from 'uni-app'
|
||||
|
||||
export default {
|
||||
name: 'HelpFilter',
|
||||
setup() {
|
||||
const router = useRouter()
|
||||
|
||||
// 筛选条件
|
||||
const filters = reactive({
|
||||
personName: '',
|
||||
idCard: '',
|
||||
helpType: '',
|
||||
helperName: '',
|
||||
region: '',
|
||||
startDate: '',
|
||||
endDate: ''
|
||||
})
|
||||
|
||||
// 帮扶类型选项
|
||||
const helpTypes = ref(['就业帮扶', '技能培训', '创业支持', '政策咨询'])
|
||||
|
||||
// 区域选项
|
||||
const regions = ref(['喀什地区/疏勒县', '喀什地区/疏附县', '喀什地区/伽师县', '喀什地区/岳普湖县'])
|
||||
|
||||
// 帮扶记录数据
|
||||
const helpRecords = ref([
|
||||
{
|
||||
id: 1,
|
||||
personName: '王小明',
|
||||
jobTag: '招聘岗位推荐',
|
||||
phone: '13912345678',
|
||||
idCard: '371302198801112024',
|
||||
region: '喀什地区/疏勒县',
|
||||
helperName: '新兴社区管理员',
|
||||
helperUnit: '新兴社区',
|
||||
helpDate: '2023-11-05',
|
||||
nextContactDate: '2023-11-06'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
personName: '赵小美',
|
||||
jobTag: '招聘岗位推荐',
|
||||
phone: '15912345678',
|
||||
idCard: '371302198801112024',
|
||||
region: '喀什地区/疏勒县',
|
||||
helperName: '新兴社区管理员',
|
||||
helperUnit: '新兴社区',
|
||||
helpDate: '2023-11-05',
|
||||
nextContactDate: '2023-11-06'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
personName: '赵小美',
|
||||
jobTag: '招聘岗位推荐',
|
||||
phone: '15912345678',
|
||||
idCard: '371302198801112024',
|
||||
region: '喀什地区/疏勒县',
|
||||
helperName: '新兴社区管理员',
|
||||
helperUnit: '新兴社区',
|
||||
helpDate: '2023-11-05',
|
||||
nextContactDate: '2023-11-06'
|
||||
}
|
||||
])
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
router.back()
|
||||
}
|
||||
|
||||
// 重置筛选条件
|
||||
const resetFilters = () => {
|
||||
Object.keys(filters).forEach(key => {
|
||||
filters[key] = ''
|
||||
})
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
const queryData = () => {
|
||||
// 这里是模拟查询,实际项目中应该调用API
|
||||
console.log('查询条件:', filters)
|
||||
// 实际开发中这里应该调用接口获取数据
|
||||
// fetchHelpRecords(filters)
|
||||
}
|
||||
|
||||
// 显示详情
|
||||
const showDetail = (record) => {
|
||||
console.log('查看详情:', record)
|
||||
// 跳转到详情页面
|
||||
// router.push({ path: '/detail', query: { id: record.id } })
|
||||
}
|
||||
|
||||
// 跟进
|
||||
const followUp = (record) => {
|
||||
console.log('跟进记录:', record)
|
||||
// 跳转到跟进页面
|
||||
router.push({ path: '/packageB/priority/helpFollow', query: { personId: record.id, personName: record.personName } })
|
||||
}
|
||||
|
||||
// 智能推荐
|
||||
const showJobRecommend = (record) => {
|
||||
console.log('智能推荐:', record)
|
||||
// 跳转到推荐页面
|
||||
// router.push({ path: '/recommend', query: { id: record.id } })
|
||||
}
|
||||
|
||||
// 帮扶类型选择变化
|
||||
const onHelpTypeChange = (e) => {
|
||||
filters.helpType = helpTypes.value[e.detail.value]
|
||||
}
|
||||
|
||||
// 区域选择变化
|
||||
const onRegionChange = (e) => {
|
||||
filters.region = regions.value[e.detail.value]
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 组件挂载时的初始化逻辑
|
||||
})
|
||||
|
||||
return {
|
||||
filters,
|
||||
helpTypes,
|
||||
regions,
|
||||
helpRecords,
|
||||
goBack,
|
||||
resetFilters,
|
||||
queryData,
|
||||
showDetail,
|
||||
followUp,
|
||||
showJobRecommend,
|
||||
onHelpTypeChange,
|
||||
onRegionChange
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.help-filter-page {
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: #1989fa;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 30rpx;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
padding: 10rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: #fff;
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
margin-right: 60rpx;
|
||||
}
|
||||
|
||||
.filter-section {
|
||||
background-color: #fff;
|
||||
margin-top: 100rpx;
|
||||
padding: 30rpx;
|
||||
border-radius: 10rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.filter-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
width: 200rpx;
|
||||
}
|
||||
|
||||
.filter-input {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.filter-picker {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.picker-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.date-range {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.date-inputs {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.date-input {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.date-separator {
|
||||
margin: 0 20rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.filter-buttons {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.query-btn {
|
||||
flex: 1;
|
||||
background-color: #1989fa;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
flex: 1;
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
font-size: 32rpx;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
}
|
||||
|
||||
.list-section {
|
||||
background-color: #fff;
|
||||
padding: 30rpx;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.list-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.list-count {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.record-item {
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 10rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.record-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.person-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.job-tag {
|
||||
font-size: 24rpx;
|
||||
color: #ff6600;
|
||||
padding: 5rpx 15rpx;
|
||||
border: 1rpx solid #ff6600;
|
||||
border-radius: 15rpx;
|
||||
}
|
||||
|
||||
.record-info {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
color: #666;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
color: #333;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.record-actions {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.detail-btn {
|
||||
flex: 1;
|
||||
background-color: #e8f3ff;
|
||||
color: #1989fa;
|
||||
font-size: 28rpx;
|
||||
border: none;
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
}
|
||||
|
||||
.follow-btn {
|
||||
flex: 1;
|
||||
background-color: #e6f7ff;
|
||||
color: #1890ff;
|
||||
font-size: 28rpx;
|
||||
border: none;
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
}
|
||||
|
||||
.recommend-btn {
|
||||
flex: 1;
|
||||
background-color: #f6ffed;
|
||||
color: #52c41a;
|
||||
font-size: 28rpx;
|
||||
border: none;
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
}
|
||||
</style>
|
||||
442
packageB/priority/helpFollow.vue
Normal file
442
packageB/priority/helpFollow.vue
Normal file
@@ -0,0 +1,442 @@
|
||||
<template>
|
||||
<view class="help-follow-page">
|
||||
<view class="header">
|
||||
<view class="back-btn" @click="goBack">
|
||||
<uni-icons type="arrowleft" size="24" color="#fff" />
|
||||
</view>
|
||||
<view class="title">跟进</view>
|
||||
</view>
|
||||
|
||||
<!-- 人员信息卡片 -->
|
||||
<view class="person-info-card">
|
||||
<view class="info-item">
|
||||
<uni-icons type="person" size="20" color="#1989fa" />
|
||||
<span class="info-label">人员姓名</span>
|
||||
<span class="info-value">{{personInfo.personName}}</span>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<uni-icons type="briefcase" size="20" color="#1989fa" />
|
||||
<span class="info-label">帮扶类型</span>
|
||||
<span class="info-value">{{personInfo.helpType}}</span>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 新增跟进记录 -->
|
||||
<view class="follow-form-section">
|
||||
<view class="section-title">新增跟进记录</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label required">跟进日期:</view>
|
||||
<input class="form-input date-input" v-model="followData.followDate" type="date" placeholder="请选择跟进日期" />
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label required">跟进方式:</view>
|
||||
<picker class="form-picker" mode="selector" range="{{followMethods}}" @change="onFollowMethodChange">
|
||||
<view class="picker-text">{{followData.followMethod || '请选择跟进方式'}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label required">跟进内容:</view>
|
||||
<textarea class="form-textarea" v-model="followData.followContent" placeholder="请输入跟进内容" rows="4"></textarea>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label required">跟进结果:</view>
|
||||
<textarea class="form-textarea" v-model="followData.followResult" placeholder="请输入跟进结果" rows="3"></textarea>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">下一步计划:</view>
|
||||
<textarea class="form-textarea" v-model="followData.nextPlan" placeholder="请输入下一步计划" rows="3"></textarea>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">下次联系:</view>
|
||||
<input class="form-input date-input" v-model="followData.nextContactDate" type="date" placeholder="请选择下次联系日期" />
|
||||
</view>
|
||||
|
||||
<view class="form-buttons">
|
||||
<button class="save-btn" type="primary" @click="saveFollowRecord">保存跟进</button>
|
||||
<button class="reset-btn" @click="resetForm">重置</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 跟进历史记录 -->
|
||||
<view class="history-section">
|
||||
<view class="section-header">
|
||||
<view class="section-title">跟进历史记录</view>
|
||||
<view class="record-count">共{{historyRecords.length}}条记录</view>
|
||||
</view>
|
||||
|
||||
<view class="history-list">
|
||||
<view class="history-item" v-for="record in historyRecords" :key="record.id">
|
||||
<view class="history-header">
|
||||
<uni-icons type="time" size="16" color="#1989fa" />
|
||||
<span class="history-date">{{record.date}}</span>
|
||||
</view>
|
||||
<view class="history-content">
|
||||
<view class="history-row">
|
||||
<span class="history-label">跟进方式:</span>
|
||||
<span class="history-value">{{record.method}}</span>
|
||||
</view>
|
||||
<view class="history-row">
|
||||
<span class="history-label">跟进人:</span>
|
||||
<span class="history-value">{{record.follower}}</span>
|
||||
</view>
|
||||
<view class="history-row">
|
||||
<span class="history-label">跟进内容:</span>
|
||||
<span class="history-value">{{record.content}}</span>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'uni-app'
|
||||
|
||||
export default {
|
||||
name: 'HelpFollow',
|
||||
setup() {
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
// 人员信息
|
||||
const personInfo = reactive({
|
||||
personName: '王小美',
|
||||
helpType: '招聘岗位推荐'
|
||||
})
|
||||
|
||||
// 跟进方式选项
|
||||
const followMethods = ref(['电话', '微信', '邮件', '上门拜访', '视频会议', '其他'])
|
||||
|
||||
// 跟进表单数据
|
||||
const followData = reactive({
|
||||
followDate: '',
|
||||
followMethod: '',
|
||||
followContent: '',
|
||||
followResult: '',
|
||||
nextPlan: '',
|
||||
nextContactDate: ''
|
||||
})
|
||||
|
||||
// 历史记录数据
|
||||
const historyRecords = ref([
|
||||
{
|
||||
id: 1,
|
||||
date: '2025-11-05',
|
||||
method: '电话',
|
||||
follower: '新兴社区管理员',
|
||||
content: '内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容。'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
date: '2025-11-05',
|
||||
method: '电话',
|
||||
follower: '新兴社区管理员',
|
||||
content: '内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容。'
|
||||
}
|
||||
])
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
router.back()
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
Object.keys(followData).forEach(key => {
|
||||
followData[key] = ''
|
||||
})
|
||||
}
|
||||
|
||||
// 保存跟进记录
|
||||
const saveFollowRecord = () => {
|
||||
// 表单验证
|
||||
if (!followData.followDate) {
|
||||
uni.showToast({ title: '请选择跟进日期', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!followData.followMethod) {
|
||||
uni.showToast({ title: '请选择跟进方式', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!followData.followContent) {
|
||||
uni.showToast({ title: '请输入跟进内容', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!followData.followResult) {
|
||||
uni.showToast({ title: '请输入跟进结果', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 这里是模拟保存,实际项目中应该调用API
|
||||
console.log('保存跟进记录:', followData)
|
||||
|
||||
// 保存成功后添加到历史记录列表
|
||||
const newRecord = {
|
||||
id: historyRecords.value.length + 1,
|
||||
date: followData.followDate,
|
||||
method: followData.followMethod,
|
||||
follower: '当前登录用户', // 实际应该从登录信息中获取
|
||||
content: followData.followContent
|
||||
}
|
||||
historyRecords.value.unshift(newRecord)
|
||||
|
||||
// 清空表单
|
||||
resetForm()
|
||||
|
||||
uni.showToast({ title: '保存成功', icon: 'success' })
|
||||
}
|
||||
|
||||
// 跟进方式选择变化
|
||||
const onFollowMethodChange = (e) => {
|
||||
followData.followMethod = followMethods.value[e.detail.value]
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 组件挂载时的初始化逻辑
|
||||
// 可以从路由参数中获取人员ID等信息
|
||||
console.log('路由参数:', route.query)
|
||||
|
||||
// 实际项目中应该根据ID加载人员信息和历史记录
|
||||
// loadPersonInfo(route.query.personId)
|
||||
// loadHistoryRecords(route.query.personId)
|
||||
})
|
||||
|
||||
return {
|
||||
personInfo,
|
||||
followMethods,
|
||||
followData,
|
||||
historyRecords,
|
||||
goBack,
|
||||
resetForm,
|
||||
saveFollowRecord,
|
||||
onFollowMethodChange
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.help-follow-page {
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: #1989fa;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 30rpx;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
padding: 10rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: #fff;
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
margin-right: 60rpx;
|
||||
}
|
||||
|
||||
.person-info-card {
|
||||
background-color: #fff;
|
||||
margin-top: 100rpx;
|
||||
padding: 30rpx;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
border-radius: 10rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.follow-form-section {
|
||||
background-color: #fff;
|
||||
padding: 30rpx;
|
||||
border-radius: 10rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.history-section {
|
||||
background-color: #fff;
|
||||
padding: 30rpx;
|
||||
border-radius: 10rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.record-count {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.required::before {
|
||||
content: '*';
|
||||
color: #ff4d4f;
|
||||
margin-right: 5rpx;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.date-input {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.form-picker {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20rpx;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.picker-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
width: 100%;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 28rpx;
|
||||
min-height: 150rpx;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.form-buttons {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
flex: 1;
|
||||
background-color: #1989fa;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
flex: 1;
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
font-size: 32rpx;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
}
|
||||
|
||||
.history-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.history-item {
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 10rpx;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.history-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15rpx;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.history-date {
|
||||
font-size: 28rpx;
|
||||
color: #1989fa;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.history-content {
|
||||
padding-left: 30rpx;
|
||||
}
|
||||
|
||||
.history-row {
|
||||
margin-bottom: 10rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.history-label {
|
||||
color: #666;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.history-value {
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
@@ -24,7 +24,7 @@
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="btns" @click="jumps('')">
|
||||
<view class="btns" @click="jumps('/packageB/train/mockExam/examList')">
|
||||
<image src="/static/images/train/mnks-k.png" mode=""></image>
|
||||
<view>
|
||||
<text>模拟考试</text>
|
||||
|
||||
@@ -1,8 +1,517 @@
|
||||
<template>
|
||||
<div class="app-box">
|
||||
<div class="con-box">
|
||||
<template #headContent>
|
||||
<view class="collection-search">
|
||||
<view class="search-content">
|
||||
<view class="header-input button-click">
|
||||
<uni-icons class="iconsearch" color="#6A6A6A" type="search" size="22"></uni-icons>
|
||||
<input
|
||||
class="input"
|
||||
v-model="searchKeyword"
|
||||
@confirm="searchVideo"
|
||||
placeholder="输入考试名称"
|
||||
placeholder-class="inputplace"
|
||||
/>
|
||||
<uni-icons
|
||||
v-if="searchKeyword"
|
||||
class="clear-icon"
|
||||
type="clear"
|
||||
size="24"
|
||||
color="#999"
|
||||
@click="clearSearch"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<scroll-view scroll-y class="main-scroll" @scrolltolower="handleScrollToLower">
|
||||
<div class="cards" v-for="(item,index) in dataList">
|
||||
<div class="cardHead">
|
||||
<div class="cardHeadLeft">
|
||||
<div class="cardTitle">{{item.name}}</div>
|
||||
<div class="titleType success" v-if="item.score">已完成</div>
|
||||
<div class="titleType info" v-else-if="dates<item.startDate">未开始</div>
|
||||
<div class="titleType primary" v-else-if="(dates>item.startDate||dates==item.startDate)&&dates<item.dueDate">
|
||||
进行中
|
||||
</div>
|
||||
<div class="titleType info" v-else-if="dates>item.dueDate">已过期</div>
|
||||
</div>
|
||||
<div class="rightBtn" v-if="(dates>item.startDate||dates==item.startDate)&&dates<item.dueDate&&item.isContinue!=1">开始考试</div>
|
||||
<div class="rightBtn" v-if="(dates>item.startDate||dates==item.startDate)&&dates<item.dueDate&&item.isContinue==1">继续考试</div>
|
||||
</div>
|
||||
<div class="heng"></div>
|
||||
<div class="cardCon">
|
||||
<div class="conten">考试时长:{{item.timeLimit}}分钟</div>
|
||||
<div class="conten">题目数量:{{item.totalQuestions}}题</div>
|
||||
<div class="conten">分类:
|
||||
<span v-for="(val, key) in classification">
|
||||
<template v-if="item.category==val.dictValue">{{ val.dictLabel }}</template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="conten">成绩:
|
||||
<span v-if="item.gradeUser" >{{ item.gradeUser.score }}分</span>
|
||||
<span v-else>--</span>
|
||||
</div>
|
||||
<div class="conten">开始时间:{{item.startDate}}</div>
|
||||
<div class="conten">截止时间:{{item.dueDate}}</div>
|
||||
</div>
|
||||
<div class="flooter">
|
||||
<div v-if="item.gradeUser" @click="jumps('/packageB/train/mockExam/viewGrades')">查看成绩</div>
|
||||
<div @click="handleDetail(item)">详情</div>
|
||||
<div @click="collects(item,1)" v-if="item.isCollect==0">
|
||||
<image :src="urls+'wsc.png'" mode="" style="width: 32rpx;height: 30rpx;"></image>
|
||||
收藏
|
||||
</div>
|
||||
<div v-else @click="collects(item,0)">
|
||||
<image :src="urls+'video-sc.png'" mode="" style="width: 32rpx;height: 30rpx;"></image>
|
||||
取消
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</scroll-view>
|
||||
</div>
|
||||
<div class="cards2" v-if="dialogVisible">
|
||||
<div class="cardCon">
|
||||
<div class="cardHead" style="margin-bottom: 20rpx;">
|
||||
<div>{{examInfo.name}}</div>
|
||||
<div style="font-size: 40rpx;" @click="clones()">×</div>
|
||||
</div>
|
||||
<div class="status-tags">
|
||||
<div class="titleType success" v-if="examInfo.score">已完成</div>
|
||||
<div class="titleType info" v-else-if="dates<examInfo.startDate">未开始</div>
|
||||
<div class="titleType primary" v-else-if="(dates>examInfo.startDate||dates==examInfo.startDate)&&dates<examInfo.dueDate">
|
||||
进行中
|
||||
</div>
|
||||
<div class="titleType info" v-else-if="dates>examInfo.dueDate">已过期</div>
|
||||
|
||||
<div class="titleType success" v-if="examInfo.difficulty=='easy'">初级</div>
|
||||
<div class="titleType tertiary" v-if="examInfo.difficulty=='medium'">中级</div>
|
||||
<div class="titleType primary2" v-if="examInfo.difficulty=='hard'">高级</div>
|
||||
</div>
|
||||
<div class="detailTitle">考试简介</div>
|
||||
<div class="detailCon">{{ examInfo.description }}</div>
|
||||
<div class="exam-info">
|
||||
<div class="info-item">
|
||||
<div class="info-value">{{ examInfo.timeLimit }}</div>
|
||||
<div class="info-label">考试时长</div>
|
||||
<div class="info-label">(分钟)</div>
|
||||
</div>
|
||||
<div class="info-divider"></div>
|
||||
<div class="info-item">
|
||||
<div class="info-value">{{ examInfo.totalQuestions }}</div>
|
||||
<div class="info-label">题目总数</div>
|
||||
</div>
|
||||
<div class="info-divider"></div>
|
||||
<div class="info-item">
|
||||
<div class="info-value">{{ examInfo.passScore }}</div>
|
||||
<div class="info-label">及格分数</div>
|
||||
</div>
|
||||
<div class="info-divider"></div>
|
||||
<div class="info-item">
|
||||
<div class="info-value">{{ examInfo.totalScore }}</div>
|
||||
<div class="info-label">总分</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detailTitle">考试要求</div>
|
||||
<div class="detailCon">考试过程中请勿刷新页面或关闭浏览器</div>
|
||||
<div class="detailCon">请在规定时间内完成所有题目</div>
|
||||
<div class="detailCon">考试开始后不可暂停,请确保网络连接稳定</div>
|
||||
<div class="detailCon">考试结束后可查看成绩和答案解析</div>
|
||||
|
||||
<div style="display: flex;justify-content: center;margin-top: 30rpx;">
|
||||
<div class="rightBtn" v-if="(dates>examInfo.startDate||dates==examInfo.startDate)&&dates<examInfo.dueDate&&examInfo.isContinue!=1">开始考试</div>
|
||||
<div class="rightBtn" v-if="(dates>examInfo.startDate||dates==examInfo.startDate)&&dates<examInfo.dueDate&&examInfo.isContinue==1">继续考试</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { inject, ref, reactive } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
const { $api, navTo, navBack,urls } = inject('globalFunction');
|
||||
import config from "@/config.js"
|
||||
const userInfo = ref({});
|
||||
const Authorization = ref('');
|
||||
const searchKeyword = ref('');
|
||||
const dataList=ref([])
|
||||
const pageSize=ref(10)
|
||||
const pageNum=ref(1)
|
||||
const totalNum=ref(0)
|
||||
const dates=ref('')
|
||||
const classification=ref([])
|
||||
const levalLabels=ref([])
|
||||
const examInfo = ref({})
|
||||
const baseUrl = config.imgBaseUrl
|
||||
const dialogVisible = ref(false);
|
||||
const handleScrollToLower = () => {
|
||||
|
||||
};
|
||||
onLoad(() => {
|
||||
getDictionary()
|
||||
const date = new Date();
|
||||
let year = date.getFullYear();
|
||||
let month = date.getMonth() + 1; // 月份从0开始,需要加1
|
||||
let day = date.getDate();
|
||||
month=month>9?month:'0'+month
|
||||
day=day>9?day:'0'+day
|
||||
dates.value=year+'-'+month+'-'+day
|
||||
Authorization.value=uni.getStorageSync('Padmin-Token')||''
|
||||
getHeart();
|
||||
});
|
||||
function getHeart() {
|
||||
const raw =Authorization.value;
|
||||
const token = typeof raw === "string" ? raw.trim() : "";
|
||||
const headers = token ? { 'Authorization': raw.startsWith("Bearer ") ? raw : `Bearer ${token}` }: {}
|
||||
$api.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers).then((resData) => {
|
||||
if (resData.code == 200) {
|
||||
getUserInfo();
|
||||
} else {
|
||||
navTo('/packageB/login')
|
||||
}
|
||||
});
|
||||
};
|
||||
function getUserInfo(){
|
||||
let header={
|
||||
'Authorization':Authorization.value
|
||||
}
|
||||
$api.myRequest('/system/user/login/user/info', {},'get',10100,header).then((resData) => {
|
||||
userInfo.value = resData.info || {};
|
||||
getDataList('refresh');
|
||||
});
|
||||
};
|
||||
function getDictionary(){
|
||||
$api.myRequest('/system/public/dict/data/type/question_classification', {},'get',9100).then((resData) => {
|
||||
classification.value=resData.data
|
||||
});
|
||||
$api.myRequest('/system/public/dict/data/type/question_level', {},'get',9100).then((resData) => {
|
||||
levalLabels.value=resData.data
|
||||
});
|
||||
}
|
||||
// 搜索视频
|
||||
function searchVideo() {
|
||||
getDataList('refresh');
|
||||
}
|
||||
|
||||
// 清除搜索内容
|
||||
function clearSearch() {
|
||||
searchKeyword.value = '';
|
||||
getDataList('refresh');
|
||||
}
|
||||
// 获取考试列表
|
||||
function getDataList(type = 'add') {
|
||||
let maxPage=Math.ceil(totalNum.value/pageSize.value)
|
||||
let params={}
|
||||
if (type === 'refresh') {
|
||||
pageNum.value = 1;
|
||||
params={
|
||||
name:searchKeyword.value,
|
||||
pageSize:pageSize.value,
|
||||
pageNum:pageNum.value,
|
||||
userId:userInfo.value.userId
|
||||
}
|
||||
$api.myRequest('/train/public/trainExamDash/getExamPublishTable', params).then((resData) => {
|
||||
if(resData.code==200){
|
||||
dataList.value=resData.rows
|
||||
totalNum.value=resData.total
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
if (type === 'add' && pageNum.value < maxPage) {
|
||||
pageNum.value += 1;
|
||||
params={
|
||||
name:searchKeyword.value,
|
||||
pageSize:pageSize.value,
|
||||
pageNum:pageNum.value,
|
||||
userId:userInfo.value.userId
|
||||
}
|
||||
$api.myRequest('/train/public/trainExamDash/getExamPublishTable', params).then((resData) => {
|
||||
if(resData.code==200){
|
||||
dataList.value=dataList.value.concat(resData.rows)
|
||||
totalNum.value=resData.total
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
function collects(row,i){
|
||||
$api.myRequest('/train/public/examUser/addOrUpdateExamUser', {
|
||||
userId:userInfo.value.userId,
|
||||
examPaperId:row.examPaperId,
|
||||
collect:i,
|
||||
}).then((resData) => {
|
||||
if(resData.code==200){
|
||||
if(i==1){
|
||||
$api.msg('收藏成功',2000)
|
||||
}else{
|
||||
$api.msg('已取消收藏',2000)
|
||||
}
|
||||
getDataList('refresh');
|
||||
}
|
||||
});
|
||||
}
|
||||
function handleDetail(row){
|
||||
$api.myRequest('/train/public/trainExamDash/getExamPublishModel', {
|
||||
userId:userInfo.value.userId,
|
||||
examPaperId:row.examPaperId,
|
||||
}).then((resData) => {
|
||||
if(resData&&resData.code==200){
|
||||
examInfo.value=resData.data
|
||||
dialogVisible.value=true;
|
||||
}
|
||||
});
|
||||
}
|
||||
function jumps(url){
|
||||
navTo(url);
|
||||
}
|
||||
function clones(){
|
||||
dialogVisible.value=false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style lang="stylus" scoped>
|
||||
.app-box{
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
.con-box{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top:0;
|
||||
z-index: 10;
|
||||
padding: 20rpx 28rpx;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
.collection-search{
|
||||
padding: 10rpx 20rpx;
|
||||
.search-content{
|
||||
position: relative
|
||||
display: flex
|
||||
align-items: center
|
||||
padding: 14rpx 0
|
||||
.header-input{
|
||||
padding: 0
|
||||
width: calc(100%);
|
||||
position: relative
|
||||
.iconsearch{
|
||||
position: absolute
|
||||
left: 30rpx;
|
||||
top: 50%
|
||||
transform: translate(0, -50%)
|
||||
z-index: 1
|
||||
}
|
||||
.input{
|
||||
padding: 0 80rpx 0 80rpx
|
||||
height: 80rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 75rpx 75rpx 75rpx 75rpx;
|
||||
border: 2rpx solid #ECECEC
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.clear-icon{
|
||||
position: absolute
|
||||
right: 30rpx;
|
||||
top: 50%
|
||||
transform: translate(0, -50%)
|
||||
z-index: 1
|
||||
cursor: pointer
|
||||
}
|
||||
.inputplace{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #B5B5B5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.main-scroll {
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
.cards{
|
||||
width: 100%;
|
||||
height: 280rpx;
|
||||
background: linear-gradient(0deg, #E3EFFF 0%, #FBFDFF 100%);
|
||||
// box-shadow: 0px 0px 6px 0px rgba(0,71,200,0.32);
|
||||
border-radius: 12rpx;
|
||||
border: 2px solid #EDF5FF;
|
||||
margin-bottom: 30rpx;
|
||||
padding: 30rpx 40rpx 0;
|
||||
box-sizing: border-box
|
||||
.cardHead{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.cardHeadLeft{
|
||||
display: flex;
|
||||
align-items: center
|
||||
width: 75%;
|
||||
.cardTitle{
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #0069CB;
|
||||
max-width: 75%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.titleType{
|
||||
border-radius: 4px;
|
||||
font-size: 22rpx;
|
||||
color: #157EFF;
|
||||
width: 100rpx;
|
||||
height: 38rpx;
|
||||
text-align: center;
|
||||
line-height: 38rpx;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
.heng{
|
||||
width: 120rpx;
|
||||
height: 4rpx;
|
||||
background: linear-gradient(88deg, #015EEA 0%, #00C0FA 100%);
|
||||
margin: 10rpx 0 20rpx;
|
||||
}
|
||||
.cardCon{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.conten{
|
||||
width: 50%;
|
||||
font-size: 22rpx;
|
||||
color: #666666;
|
||||
display: flex;
|
||||
align-items: center
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.status-tags{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.flooter{
|
||||
border-top: 1px solid #ccc;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
view{
|
||||
font-size: 28rpx;
|
||||
margin-left: 30rpx;
|
||||
color: #2175F3;
|
||||
padding-top: 14rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.cards2{
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
z-index: 10000;
|
||||
padding: 100rpx 50rpx;
|
||||
box-sizing: border-box;
|
||||
.cardCon{
|
||||
height: 70%;
|
||||
background-color: #fff;
|
||||
padding: 20rpx;
|
||||
box-sizing: border-box;
|
||||
.cardHead{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
.titleType{
|
||||
display: inline-block
|
||||
border-radius: 4px;
|
||||
font-size: 22rpx;
|
||||
color: #157EFF;
|
||||
width: 100rpx;
|
||||
height: 38rpx;
|
||||
text-align: center;
|
||||
line-height: 38rpx;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
.primary{
|
||||
border: 1px solid #157EFF!important;
|
||||
color: #157EFF!important
|
||||
}
|
||||
.success{
|
||||
border: 1px solid #05A636!important;
|
||||
color: #05A636!important
|
||||
}
|
||||
.info{
|
||||
border: 1px solid #898989!important;
|
||||
color: #898989!important
|
||||
}
|
||||
.tertiary{
|
||||
border: 1px solid #E6A340!important;
|
||||
color: #E6A340!important
|
||||
}
|
||||
.primary2{
|
||||
border: 1px solid #F56C6C!important;
|
||||
color: #F56C6C!important
|
||||
}
|
||||
.rightBtn{
|
||||
width: 140rpx;
|
||||
height: 44rpx;
|
||||
line-height: 44rpx;
|
||||
background: linear-gradient(90deg, #00C0FA 0%, #1271FF 100%);
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.detailTitle{
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
margin: 30rpx 0;
|
||||
}
|
||||
.detailCon{
|
||||
font-size: 28rpx;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
.exam-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 35rpx;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-family: 'D-DIN-Medium';
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #409EFF;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.info-divider {
|
||||
width: 2px;
|
||||
background-color: #C3E1FF;
|
||||
}
|
||||
</style>
|
||||
605
packageB/train/mockExam/startExam.vue
Normal file
605
packageB/train/mockExam/startExam.vue
Normal file
@@ -0,0 +1,605 @@
|
||||
<template>
|
||||
<div class="app-box">
|
||||
<image src="../../../static/images/train/bj.jpg" class="bjImg" mode=""></image>
|
||||
<div class="con-box">
|
||||
<div class="header">
|
||||
<div>正确率:{{accuracyRate}}%</div>
|
||||
<div>用时:{{formattedTime}}</div>
|
||||
<div class="headBtn" v-if="isRunning" @click="pause">暂停</div>
|
||||
<div class="headBtn" v-if="!isRunning" @click="start">继续</div>
|
||||
</div>
|
||||
<div class="problemCard">
|
||||
<div v-for="(item,index) in problemData" :key="index">
|
||||
<template v-if="questionIndex==(index+1)">
|
||||
<div class="problemTitle">
|
||||
<span class="titleType" v-if="item.type=='single'">单选题</span>
|
||||
<span class="titleType" v-if="item.type=='multiple'">多选题</span>
|
||||
<span class="titleType" v-if="item.type=='judge'">判断题</span>
|
||||
<span>{{item.content}}</span>
|
||||
</div>
|
||||
<div class="options" v-if="item.type=='single'">
|
||||
<div class="opt" @click="selected(i)" :class="radio!==''&&i==radio?'active':''" v-for="(val,i) in parseOptions(item.trainChooses)">
|
||||
<div class="optLab">{{indexToLetter(i)}}</div>
|
||||
<span>{{val}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options" v-if="item.type=='multiple'">
|
||||
<div class="opt" @click="selected2(i)" :class="judgment(i)?'active':''" v-for="(val,i) in parseOptions(item.trainChooses)">
|
||||
<div class="optLab">{{indexToLetter(i)}}</div>
|
||||
<span>{{val}}</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="options" v-if="item.type=='judge'">
|
||||
<div class="opt" @click="selected3('正确')" :class="radio2=='正确'?'active':''">
|
||||
<span>正确</span>
|
||||
</div>
|
||||
<div class="opt" @click="selected3('错误')" :class="radio2=='错误'?'active':''">
|
||||
<span>错误</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="analysis" v-if="analysis">
|
||||
<div class="analysisHead correct" v-if="judgWhether=='正确'">
|
||||
<div>回答正确!</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="analysisHead errors" v-if="judgWhether=='错误'">
|
||||
<div>回答错误!</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="analysisCon">
|
||||
<div class="parse1">正确答案:</div>
|
||||
<div class="parse2" v-if="item.type=='single'" style="color: #30A0FF;font-weight: bold;">{{String.fromCharCode(65 + Number(item.answer))}}.</div>
|
||||
<div class="parse2" v-if="item.type=='multiple'" style="color: #30A0FF;font-weight: bold;">
|
||||
<span v-for="(val,i) in parseOptions(item.answer)">{{indexToLetter(val-1)}}.</span>
|
||||
</div>
|
||||
<div class="parse2" v-if="item.type=='judge'" style="color: #30A0FF;font-weight: bold;">{{item.answer}}</div>
|
||||
</div>
|
||||
<div class="analysisCon">
|
||||
<div class="parse1">答案解析:</div>
|
||||
<div class="parse2">{{item.answerDesc}}</div>
|
||||
</div>
|
||||
<div class="analysisCon">
|
||||
<div class="parse1">知识点:</div>
|
||||
<div>
|
||||
<el-tag style="margin-right: 10px;">{{item.knowledgePoint}}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="problemBtns">
|
||||
<div v-if="analysis&&judgWhether!=''&&questionIndex!=problemData.length" @click="questionIndex+=1">下一题</div>
|
||||
<div v-else :class="((radio===''&&radio2===''&&checkList.length==0&&isRunning)||analysis)?'events':''" @click="submit()">提交答案</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="footerLeft">
|
||||
<div class="zuo" :class="questionIndex==1?'events':''" @click="questionIndex-=1"></div>
|
||||
<div class="you" :class="questionIndex==problemData.length?'events':''" @click="questionIndex+=1"></div>
|
||||
<div @click="collect(1)" style="text-align: center;font-size: 24rpx;" v-if="(problemData[questionIndex - 1]?.isCollect || 0)!=1">
|
||||
<image :src="urls+'wsc.png'" mode="" style="width: 34rpx;height: 32rpx;"></image>
|
||||
<div>收藏</div>
|
||||
</div>
|
||||
<div @click="collect(0)" style="text-align: center;font-size: 24rpx;" v-if="(problemData[questionIndex - 1]?.isCollect || 0)==1">
|
||||
<image :src="urls+'video-sc.png'" mode="" style="width: 34rpx;height: 32rpx;"></image>
|
||||
<div>取消</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footerBtn" @click="exit()">完成练习</div>
|
||||
<div class="footerLeft">
|
||||
<div>
|
||||
<div class="icons" style="background-color: #1CADF5;">√</div>
|
||||
<div class="texts" style="color: #1CADF5;">{{correctIndex}}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="icons" style="background-color: #FF6668;">×</div>
|
||||
<div class="texts" style="color: #FF6668;">{{errorsIndex}}</div>
|
||||
</div>
|
||||
<div @click="dialogVisible=true">
|
||||
<div><span style="color: #1CADF5;">{{questionIndex}}</span>/{{problemData.length}}</div>
|
||||
<div>题号</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cards" v-if="dialogVisible">
|
||||
<div class="cardCon">
|
||||
<div class="cardHead">
|
||||
<div>题号</div>
|
||||
<div style="font-size: 40rpx;" @click="clones()">×</div>
|
||||
</div>
|
||||
<div class="questionNums">
|
||||
<div class="questions" :class="item.whether=='正确'?'questionCorrect':item.whether=='错误'?'questionError':questionIndex==(index+1)?'questionsActive':''" @click="switchs(index)" v-for="(item,index) in problemList" :key="index">{{index+1}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted,onBeforeUnmount,computed } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
const { $api,urls , navTo,navBack , vacanciesTo, formatTotal, config } = inject('globalFunction');
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
const userInfo = ref({});
|
||||
const Authorization = ref('');
|
||||
const radio = ref('');
|
||||
const radio2 = ref('');
|
||||
const checkList = ref([]);
|
||||
const questionIndex = ref(1);
|
||||
const correctIndex = ref(0);
|
||||
const errorsIndex = ref(0);
|
||||
const accuracyRate = ref(0);
|
||||
const elapsedTime = ref(0);
|
||||
const analysis = ref(false);
|
||||
const judgWhether = ref('');
|
||||
const isRunning = ref(false);
|
||||
const dialogVisible = ref(false);
|
||||
const problemData = ref([]);
|
||||
const problemList = ref([]);
|
||||
let timer = null;
|
||||
const formattedTime = computed(() => {
|
||||
const minutes = Math.floor(elapsedTime.value / 60)
|
||||
const seconds = elapsedTime.value % 60
|
||||
return `${padTime(minutes)}:${padTime(seconds)}`
|
||||
});
|
||||
watch(questionIndex, (newVal, oldVal) => {
|
||||
radio.value=""
|
||||
radio2.value=""
|
||||
checkList.value=[]
|
||||
analysis.value=false
|
||||
judgWhether.value=""
|
||||
});
|
||||
|
||||
// watch(problemData, (newVal, oldVal) => {
|
||||
// problemList.value=[];
|
||||
// newVal.forEach((item,i)=>{
|
||||
// problemList.value.push({index:i+1,whether:""})
|
||||
// })
|
||||
// });
|
||||
|
||||
onLoad((options) => {
|
||||
Authorization.value=uni.getStorageSync('Padmin-Token')||''
|
||||
getHeart();
|
||||
});
|
||||
onShow(()=>{
|
||||
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer); // 清除定时器
|
||||
timer = null; // 防止内存泄漏,确保下次不会再误用已清除的定时器
|
||||
}
|
||||
});
|
||||
function getHeart() {
|
||||
const raw =Authorization.value;
|
||||
const token = typeof raw === "string" ? raw.trim() : "";
|
||||
const headers = token ? { 'Authorization': raw.startsWith("Bearer ") ? raw : `Bearer ${token}` }: {}
|
||||
$api.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers).then((resData) => {
|
||||
if (resData.code == 200) {
|
||||
getUserInfo();
|
||||
} else {
|
||||
navTo('/packageB/login')
|
||||
}
|
||||
});
|
||||
};
|
||||
function getUserInfo(){
|
||||
let header={
|
||||
'Authorization':Authorization.value
|
||||
}
|
||||
$api.myRequest('/system/user/login/user/info', {},'get',10100,header).then((resData) => {
|
||||
userInfo.value = resData.info || {};
|
||||
// userId.value=resData.info.userId
|
||||
queryData()
|
||||
});
|
||||
};
|
||||
function queryData(){
|
||||
problemData.value=[]
|
||||
let header={
|
||||
'Authorization':Authorization.value,
|
||||
'Content-Type':"application/x-www-form-urlencoded"
|
||||
}
|
||||
$api.myRequest('/train/public/trainPractice/getQuestions', {
|
||||
userId: userInfo.value.userId
|
||||
},'post',9100,header).then((resData) => {
|
||||
resData.forEach((item,i)=>{
|
||||
problemData.value.push(item)
|
||||
problemList.value.push({index:i+1,whether:""})
|
||||
})
|
||||
start()
|
||||
accuracyRates()
|
||||
});
|
||||
}
|
||||
function collect(is){
|
||||
let header={
|
||||
'Authorization':Authorization.value,
|
||||
'Content-Type':"application/x-www-form-urlencoded"
|
||||
}
|
||||
$api.myRequest('/train/public/questionUser/addOrUpdateCollect', {
|
||||
userId: userInfo.value.userId,
|
||||
questionId:problemData.value[questionIndex.value-1].questionId,
|
||||
collect:is
|
||||
},'post',9100,header).then((resData) => {
|
||||
problemData.value[questionIndex.value-1].isCollect=is
|
||||
});
|
||||
};
|
||||
//正确率
|
||||
function accuracyRates(){
|
||||
let header={
|
||||
'Authorization':Authorization.value,
|
||||
'Content-Type':"application/x-www-form-urlencoded"
|
||||
}
|
||||
$api.myRequest('/train/public/trainPractice/getCount', {
|
||||
userId: userInfo.value.userId,
|
||||
},'post',9100,header).then((resData) => {
|
||||
accuracyRate.value=resData.truePresent
|
||||
});
|
||||
};
|
||||
//提交答案
|
||||
function submit(){
|
||||
let indexs=questionIndex.value-1
|
||||
let parm={
|
||||
questionId:problemData.value[indexs].questionId,
|
||||
userId:userInfo.value.userId,
|
||||
answer:problemData.value[indexs].answer
|
||||
}
|
||||
if(problemData.value[indexs].type=='single'){
|
||||
parm.submitAnswer=radio.value
|
||||
}else if(problemData.value[indexs].type=='multiple'){
|
||||
parm.submitAnswer=checkList.value.join(',')
|
||||
}else if(problemData.value[indexs].type=='judge'){
|
||||
parm.submitAnswer=radio2.value
|
||||
}
|
||||
let header={
|
||||
'Authorization':Authorization.value,
|
||||
'Content-Type':"application/json"
|
||||
}
|
||||
$api.myRequest('/train/public/trainPractice/submitAnswer', parm,'post',9100,header).then((resData) => {
|
||||
if(resData&&resData.code==200){
|
||||
analysis.value=true
|
||||
judgWhether.value=resData.msg
|
||||
problemList.value[indexs].whether=resData.msg
|
||||
if(resData.msg=='正确'){
|
||||
correctIndex.value++
|
||||
}else if(resData.msg=='错误'){
|
||||
errorsIndex.value++
|
||||
}
|
||||
accuracyRates()
|
||||
}
|
||||
});
|
||||
};
|
||||
function selected(i){
|
||||
radio.value=i
|
||||
};
|
||||
//多选
|
||||
function selected2(i){
|
||||
let arr=checkList.value.join(",")
|
||||
if(arr.indexOf(i) !== -1){
|
||||
const index = checkList.value.indexOf(i);
|
||||
if (index !== -1) {
|
||||
checkList.value.splice(index, 1);
|
||||
}
|
||||
}else{
|
||||
checkList.value.push(i)
|
||||
}
|
||||
};
|
||||
function judgment(i){
|
||||
let arr=checkList.value.join(",")
|
||||
if(arr.indexOf(i) !== -1){
|
||||
return true
|
||||
}else{
|
||||
return false
|
||||
}
|
||||
};
|
||||
function selected3(i){
|
||||
radio2.value=i
|
||||
};
|
||||
// 解析选项
|
||||
function parseOptions(options) {
|
||||
if (!options) return [];
|
||||
// 假设options是字符串格式,以分号分隔
|
||||
if (typeof options === 'string') {
|
||||
return options.split(',').filter(opt => opt.trim());
|
||||
}
|
||||
// 如果是数组,直接返回
|
||||
if (Array.isArray(options)) {
|
||||
return options;
|
||||
}
|
||||
return [];
|
||||
};
|
||||
function indexToLetter(index) {
|
||||
// 将索引转换为对应的字母
|
||||
return String.fromCharCode(65 + index);
|
||||
};
|
||||
function padTime(time) {
|
||||
return time < 10 ? `0${time}` : time
|
||||
};
|
||||
function start() {
|
||||
if (isRunning.value) return
|
||||
isRunning.value = true
|
||||
timer = setInterval(() => {
|
||||
elapsedTime.value++
|
||||
}, 1000)
|
||||
};
|
||||
function pause() {
|
||||
if (!isRunning.value) return
|
||||
clearInterval(timer)
|
||||
isRunning.value = false
|
||||
};
|
||||
function clones(){
|
||||
dialogVisible.value=false
|
||||
};
|
||||
function switchs(i){
|
||||
questionIndex.value=(i+1)
|
||||
dialogVisible.value=false
|
||||
};
|
||||
function exit(){
|
||||
navBack()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.app-box{
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
.bjImg{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.con-box{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top:0;
|
||||
z-index: 10;
|
||||
padding: 20rpx 28rpx;
|
||||
box-sizing: border-box;
|
||||
.header{
|
||||
height: 100rpx;
|
||||
padding: 0 10rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: linear-gradient(0deg, #4285EC 0%, #0BBAFB 100%);
|
||||
color: #fff;
|
||||
font-size: 26rpx;
|
||||
border-radius: 10rpx
|
||||
.headBtn{
|
||||
background: #499FFF;
|
||||
border-radius: 4px;
|
||||
width: 100rpx;
|
||||
text-align: center;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
}
|
||||
}
|
||||
.problemCard{
|
||||
margin-top: 30rpx;
|
||||
.problemTitle{
|
||||
font-size: 30rpx;
|
||||
.titleType{
|
||||
display: inline-block;
|
||||
background-color: #499FFF;
|
||||
border-radius: 10rpx 10rpx 10rpx 0;
|
||||
padding: 8rpx 12rpx;
|
||||
color: #fff;
|
||||
font-size: 26rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
}
|
||||
.options{
|
||||
margin-top: 30rpx;
|
||||
.opt{
|
||||
height: 60rpx;
|
||||
/* background-color: #F8F9FA; */
|
||||
border-radius: 5px;
|
||||
margin-bottom: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 30rpx;
|
||||
box-sizing: border-box;
|
||||
color: #808080;
|
||||
font-size: 30rpx;
|
||||
.optLab{
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
text-align: center;
|
||||
line-height: 40rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #8C8C8C;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
font-size: 32rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
}
|
||||
.active{
|
||||
background: linear-gradient(90deg, #25A9F5 0%, #B1DBFF 100%);
|
||||
color: #fff!important;
|
||||
font-weight: bold;
|
||||
}
|
||||
.active>view{
|
||||
background-color: #fff!important;
|
||||
color: #25A9F5!important;
|
||||
}
|
||||
}
|
||||
.analysis{
|
||||
margin-top: 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 15rpx;
|
||||
border: 1px solid #10A8FF;
|
||||
padding: 20rpx;
|
||||
box-sizing: border-box;
|
||||
.analysisHead{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 32rpx;
|
||||
font-family: Microsoft YaHei;
|
||||
font-weight: bold;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
.correct{
|
||||
color: #67C23A;
|
||||
}
|
||||
.errors{
|
||||
color: #F06A6A;
|
||||
}
|
||||
.analysisCon{
|
||||
margin-top: 30rpx;
|
||||
.parse1{
|
||||
font-size: 30rpx;
|
||||
font-family: Microsoft YaHei;
|
||||
font-weight: bold;
|
||||
}
|
||||
.parse2{
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.problemBtns{
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
view{
|
||||
width: 140rpx
|
||||
height: 50rpx
|
||||
text-align: center
|
||||
line-height: 50rpx
|
||||
background-color: #10A8FF
|
||||
color: #fff
|
||||
font-size: 28rpx
|
||||
border-radius: 5rpx
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
width: 100%;
|
||||
height: 120rpx;
|
||||
border-top: 1px solid #ddd
|
||||
position: fixed
|
||||
bottom: 0
|
||||
left: 0
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: space-between
|
||||
.footerLeft{
|
||||
display: flex
|
||||
align-items: center
|
||||
font-size: 30rpx;
|
||||
text-align: center
|
||||
.zuo{
|
||||
width: 26rpx;
|
||||
height: 26rpx;
|
||||
border-top: 2px solid #666
|
||||
border-left: 2px solid #666
|
||||
transform: rotate(-45deg); /* 鼠标悬停时旋转360度 */
|
||||
margin-left: 60rpx;
|
||||
}
|
||||
.you{
|
||||
width: 26rpx;
|
||||
height: 26rpx;
|
||||
border-right: 2px solid #666
|
||||
border-bottom: 2px solid #666
|
||||
transform: rotate(-45deg); /* 鼠标悬停时旋转360度 */
|
||||
// margin-left: 30rpx;
|
||||
margin-right: 50rpx;
|
||||
}
|
||||
.icons{
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
line-height: 30rpx;
|
||||
border-radius: 50%
|
||||
}
|
||||
.texts{
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
.footerLeft>view{
|
||||
margin-right: 40rpx;
|
||||
}
|
||||
.footerBtn{
|
||||
width: 140rpx
|
||||
height: 50rpx
|
||||
text-align: center
|
||||
line-height: 50rpx
|
||||
background-color: #67C23A
|
||||
color: #fff
|
||||
font-size: 28rpx
|
||||
border-radius: 5rpx
|
||||
}
|
||||
}
|
||||
}
|
||||
.cards{
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
z-index: 1000;
|
||||
padding: 100rpx 50rpx;
|
||||
box-sizing: border-box;
|
||||
.cardCon{
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
padding: 20rpx;
|
||||
box-sizing: border-box;
|
||||
.cardHead{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
.questionNums{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.questions{
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
text-align: center;
|
||||
line-height: 60rpx;
|
||||
border-radius: 8rpx;
|
||||
border: 2px solid #E0E0E0;
|
||||
font-size: 28rpx;
|
||||
margin-right: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.questionsActive{
|
||||
background-color: #F0F9FF;
|
||||
border: 2px solid #409EFF;
|
||||
}
|
||||
.questionCorrect{
|
||||
background-color: #F0F9FF;
|
||||
border: 2px solid #64BC38;
|
||||
color: #6BC441;
|
||||
}
|
||||
.questionError{
|
||||
background-color: #FFF1F0;
|
||||
border: 2px solid #F56C6C;
|
||||
color: #F36B6B;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.events{
|
||||
pointer-events: none; /* 这会禁用所有指针事件 */
|
||||
opacity: 0.5; /* 可选:改变透明度以视觉上表示不可点击 */
|
||||
cursor: not-allowed; /* 可选:改变鼠标光标样式 */
|
||||
}
|
||||
</style>
|
||||
65
packageB/train/mockExam/viewGrades.vue
Normal file
65
packageB/train/mockExam/viewGrades.vue
Normal file
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<div class="app-box">
|
||||
<div class="con-box">
|
||||
<div class="tabCon">
|
||||
<div class="tabLeft">
|
||||
<div><span>考试名称:</span>456546456</div>
|
||||
<div><span>考试时间:</span>456546456</div>
|
||||
<div><span>考试成绩:</span>456546456</div>
|
||||
</div>
|
||||
<div class="tabRight">查看</div>
|
||||
<div class="tabLeft"></div>
|
||||
<div class="tabRight">查看</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.app-box{
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
.con-box{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top:0;
|
||||
z-index: 10;
|
||||
padding: 20rpx 28rpx;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
.tabCon{
|
||||
border-top: 1px solid #ccc;
|
||||
border-left: 1px solid #ccc;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.tabLeft{
|
||||
width: 80%;
|
||||
height: 140rpx;
|
||||
border-bottom: 1px solid #ccc;
|
||||
border-right: 1px solid #ccc;
|
||||
box-sizing: border-box;
|
||||
view{
|
||||
line-height: 45rpx
|
||||
}
|
||||
}
|
||||
.tabRight{
|
||||
width: 20%;
|
||||
height: 140rpx;
|
||||
border-bottom: 1px solid #ccc;
|
||||
border-right: 1px solid #ccc;
|
||||
box-sizing: border-box;
|
||||
font-size: 30rpx;
|
||||
text-align: center;
|
||||
line-height: 140rpx;
|
||||
color: #2175F3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -3,9 +3,10 @@
|
||||
<image src="../../../static/images/train/bj.jpg" class="bjImg" mode=""></image>
|
||||
<div class="con-box">
|
||||
<div class="header">
|
||||
<div>正确率:0%</div>
|
||||
<div>用时:00:00</div>
|
||||
<div class="headBtn">暂停</div>
|
||||
<div>正确率:{{accuracyRate}}%</div>
|
||||
<div>用时:{{formattedTime}}</div>
|
||||
<div class="headBtn" v-if="isRunning" @click="pause">暂停</div>
|
||||
<div class="headBtn" v-if="!isRunning" @click="start">继续</div>
|
||||
</div>
|
||||
<div class="problemCard">
|
||||
<div v-for="(item,index) in problemData" :key="index">
|
||||
@@ -37,15 +38,15 @@
|
||||
<span>错误</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="analysis">
|
||||
<div class="analysisHead correct">
|
||||
<div class="analysis" v-if="analysis">
|
||||
<div class="analysisHead correct" v-if="judgWhether=='正确'">
|
||||
<div>回答正确!</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<!-- <div class="analysisHead errors" v-if="judgWhether=='错误'">
|
||||
<div class="analysisHead errors" v-if="judgWhether=='错误'">
|
||||
<div>回答错误!</div>
|
||||
<div></div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="analysisCon">
|
||||
<div class="parse1">正确答案:</div>
|
||||
<div class="parse2" v-if="item.type=='single'" style="color: #30A0FF;font-weight: bold;">{{String.fromCharCode(65 + Number(item.answer))}}.</div>
|
||||
@@ -66,39 +67,64 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="problemBtns">
|
||||
<div class="events">提交答案</div>
|
||||
<div>下一题</div>
|
||||
<div v-if="analysis&&judgWhether!=''&&questionIndex!=problemData.length" @click="questionIndex+=1">下一题</div>
|
||||
<div v-else :class="((radio===''&&radio2===''&&checkList.length==0&&isRunning)||analysis)?'events':''" @click="submit()">提交答案</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="footerLeft">
|
||||
<div class="zuo events"></div>
|
||||
<div class="you"></div>
|
||||
<div style="text-align: center;font-size: 24rpx;">
|
||||
<div>⭐</div>
|
||||
<div class="zuo" :class="questionIndex==1?'events':''" @click="questionIndex-=1"></div>
|
||||
<div class="you" :class="questionIndex==problemData.length?'events':''" @click="questionIndex+=1"></div>
|
||||
<div @click="collect(1)" style="text-align: center;font-size: 24rpx;" v-if="(problemData[questionIndex - 1]?.isCollect || 0)!=1">
|
||||
<image :src="urls+'wsc.png'" mode="" style="width: 34rpx;height: 32rpx;"></image>
|
||||
<div>收藏</div>
|
||||
|
||||
</div>
|
||||
<div @click="collect(0)" style="text-align: center;font-size: 24rpx;" v-if="(problemData[questionIndex - 1]?.isCollect || 0)==1">
|
||||
<image :src="urls+'video-sc.png'" mode="" style="width: 34rpx;height: 32rpx;"></image>
|
||||
<div>取消</div>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
<div class="footer">
|
||||
|
||||
<div class="footerBtn" @click="exit()">完成练习</div>
|
||||
<div class="footerLeft">
|
||||
<div>
|
||||
<div class="icons" style="background-color: #1CADF5;">√</div>
|
||||
<div class="texts" style="color: #1CADF5;">{{correctIndex}}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="icons" style="background-color: #FF6668;">×</div>
|
||||
<div class="texts" style="color: #FF6668;">{{errorsIndex}}</div>
|
||||
</div>
|
||||
<div @click="dialogVisible=true">
|
||||
<div><span style="color: #1CADF5;">{{questionIndex}}</span>/{{problemData.length}}</div>
|
||||
<div>题号</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cards" v-if="dialogVisible">
|
||||
<div class="cardCon">
|
||||
<div class="cardHead">
|
||||
<div>题号</div>
|
||||
<div style="font-size: 40rpx;" @click="clones()">×</div>
|
||||
</div>
|
||||
<div class="questionNums">
|
||||
<div class="questions" :class="item.whether=='正确'?'questionCorrect':item.whether=='错误'?'questionError':questionIndex==(index+1)?'questionsActive':''" @click="switchs(index)" v-for="(item,index) in problemList" :key="index">{{index+1}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import { reactive, inject, watch, ref, onMounted,onBeforeUnmount,computed } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
const { $api, navTo, vacanciesTo, formatTotal, config } = inject('globalFunction');
|
||||
const { $api,urls , navTo,navBack , vacanciesTo, formatTotal, config } = inject('globalFunction');
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
|
||||
const userInfo = ref({});
|
||||
const Authorization = ref('');
|
||||
const radio = ref('');
|
||||
const radio2 = ref('');
|
||||
const checkList = ref([]);
|
||||
@@ -106,29 +132,144 @@ const questionIndex = ref(1);
|
||||
const correctIndex = ref(0);
|
||||
const errorsIndex = ref(0);
|
||||
const accuracyRate = ref(0);
|
||||
const problemData = reactive([
|
||||
{
|
||||
type:'single',
|
||||
content:"君不见黄河之水天上来,下一句是?",
|
||||
fraction:5,
|
||||
trainChooses:"奔流到海不复回,朝如青丝暮成雪,人生得意须尽欢,莫使金樽空对月",
|
||||
},{
|
||||
type:'multiple',
|
||||
content:"以下哪些是欧姆定律的适用条件?",
|
||||
fraction:8,
|
||||
trainChooses:"线性电阻,恒定温度,金属导体,半导体材料",
|
||||
|
||||
},{
|
||||
type:'judge',
|
||||
content:"功率越大的电器,其电阻值越小",
|
||||
fraction:2,
|
||||
trainChooses:[
|
||||
"正确",
|
||||
"错误",
|
||||
]
|
||||
}
|
||||
]);
|
||||
const elapsedTime = ref(0);
|
||||
const analysis = ref(false);
|
||||
const judgWhether = ref('');
|
||||
const isRunning = ref(false);
|
||||
const dialogVisible = ref(false);
|
||||
const problemData = ref([]);
|
||||
const problemList = ref([]);
|
||||
let timer = null;
|
||||
const formattedTime = computed(() => {
|
||||
const minutes = Math.floor(elapsedTime.value / 60)
|
||||
const seconds = elapsedTime.value % 60
|
||||
return `${padTime(minutes)}:${padTime(seconds)}`
|
||||
});
|
||||
watch(questionIndex, (newVal, oldVal) => {
|
||||
radio.value=""
|
||||
radio2.value=""
|
||||
checkList.value=[]
|
||||
analysis.value=false
|
||||
judgWhether.value=""
|
||||
});
|
||||
|
||||
// watch(problemData, (newVal, oldVal) => {
|
||||
// problemList.value=[];
|
||||
// newVal.forEach((item,i)=>{
|
||||
// problemList.value.push({index:i+1,whether:""})
|
||||
// })
|
||||
// });
|
||||
|
||||
onLoad((options) => {
|
||||
Authorization.value=uni.getStorageSync('Padmin-Token')||''
|
||||
getHeart();
|
||||
});
|
||||
onShow(()=>{
|
||||
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer); // 清除定时器
|
||||
timer = null; // 防止内存泄漏,确保下次不会再误用已清除的定时器
|
||||
}
|
||||
});
|
||||
function getHeart() {
|
||||
const raw =Authorization.value;
|
||||
const token = typeof raw === "string" ? raw.trim() : "";
|
||||
const headers = token ? { 'Authorization': raw.startsWith("Bearer ") ? raw : `Bearer ${token}` }: {}
|
||||
$api.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers).then((resData) => {
|
||||
if (resData.code == 200) {
|
||||
getUserInfo();
|
||||
} else {
|
||||
navTo('/packageB/login')
|
||||
}
|
||||
});
|
||||
};
|
||||
function getUserInfo(){
|
||||
let header={
|
||||
'Authorization':Authorization.value
|
||||
}
|
||||
$api.myRequest('/system/user/login/user/info', {},'get',10100,header).then((resData) => {
|
||||
userInfo.value = resData.info || {};
|
||||
// userId.value=resData.info.userId
|
||||
queryData()
|
||||
});
|
||||
};
|
||||
function queryData(){
|
||||
problemData.value=[]
|
||||
let header={
|
||||
'Authorization':Authorization.value,
|
||||
'Content-Type':"application/x-www-form-urlencoded"
|
||||
}
|
||||
$api.myRequest('/train/public/trainPractice/getQuestions', {
|
||||
userId: userInfo.value.userId
|
||||
},'post',9100,header).then((resData) => {
|
||||
resData.forEach((item,i)=>{
|
||||
problemData.value.push(item)
|
||||
problemList.value.push({index:i+1,whether:""})
|
||||
})
|
||||
start()
|
||||
accuracyRates()
|
||||
});
|
||||
}
|
||||
function collect(is){
|
||||
let header={
|
||||
'Authorization':Authorization.value,
|
||||
'Content-Type':"application/x-www-form-urlencoded"
|
||||
}
|
||||
$api.myRequest('/train/public/questionUser/addOrUpdateCollect', {
|
||||
userId: userInfo.value.userId,
|
||||
questionId:problemData.value[questionIndex.value-1].questionId,
|
||||
collect:is
|
||||
},'post',9100,header).then((resData) => {
|
||||
problemData.value[questionIndex.value-1].isCollect=is
|
||||
});
|
||||
};
|
||||
//正确率
|
||||
function accuracyRates(){
|
||||
let header={
|
||||
'Authorization':Authorization.value,
|
||||
'Content-Type':"application/x-www-form-urlencoded"
|
||||
}
|
||||
$api.myRequest('/train/public/trainPractice/getCount', {
|
||||
userId: userInfo.value.userId,
|
||||
},'post',9100,header).then((resData) => {
|
||||
accuracyRate.value=resData.truePresent
|
||||
});
|
||||
};
|
||||
//提交答案
|
||||
function submit(){
|
||||
let indexs=questionIndex.value-1
|
||||
let parm={
|
||||
questionId:problemData.value[indexs].questionId,
|
||||
userId:userInfo.value.userId,
|
||||
answer:problemData.value[indexs].answer
|
||||
}
|
||||
if(problemData.value[indexs].type=='single'){
|
||||
parm.submitAnswer=radio.value
|
||||
}else if(problemData.value[indexs].type=='multiple'){
|
||||
parm.submitAnswer=checkList.value.join(',')
|
||||
}else if(problemData.value[indexs].type=='judge'){
|
||||
parm.submitAnswer=radio2.value
|
||||
}
|
||||
let header={
|
||||
'Authorization':Authorization.value,
|
||||
'Content-Type':"application/json"
|
||||
}
|
||||
$api.myRequest('/train/public/trainPractice/submitAnswer', parm,'post',9100,header).then((resData) => {
|
||||
if(resData&&resData.code==200){
|
||||
analysis.value=true
|
||||
judgWhether.value=resData.msg
|
||||
problemList.value[indexs].whether=resData.msg
|
||||
if(resData.msg=='正确'){
|
||||
correctIndex.value++
|
||||
}else if(resData.msg=='错误'){
|
||||
errorsIndex.value++
|
||||
}
|
||||
accuracyRates()
|
||||
}
|
||||
});
|
||||
};
|
||||
function selected(i){
|
||||
radio.value=i
|
||||
};
|
||||
@@ -172,6 +313,31 @@ function indexToLetter(index) {
|
||||
// 将索引转换为对应的字母
|
||||
return String.fromCharCode(65 + index);
|
||||
};
|
||||
function padTime(time) {
|
||||
return time < 10 ? `0${time}` : time
|
||||
};
|
||||
function start() {
|
||||
if (isRunning.value) return
|
||||
isRunning.value = true
|
||||
timer = setInterval(() => {
|
||||
elapsedTime.value++
|
||||
}, 1000)
|
||||
};
|
||||
function pause() {
|
||||
if (!isRunning.value) return
|
||||
clearInterval(timer)
|
||||
isRunning.value = false
|
||||
};
|
||||
function clones(){
|
||||
dialogVisible.value=false
|
||||
};
|
||||
function switchs(i){
|
||||
questionIndex.value=(i+1)
|
||||
dialogVisible.value=false
|
||||
};
|
||||
function exit(){
|
||||
navBack()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@@ -331,25 +497,103 @@ function indexToLetter(index) {
|
||||
display: flex
|
||||
align-items: center
|
||||
font-size: 30rpx;
|
||||
text-align: center
|
||||
.zuo{
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
width: 26rpx;
|
||||
height: 26rpx;
|
||||
border-top: 2px solid #666
|
||||
border-left: 2px solid #666
|
||||
transform: rotate(-45deg); /* 鼠标悬停时旋转360度 */
|
||||
margin-left: 50rpx;
|
||||
margin-left: 60rpx;
|
||||
}
|
||||
.you{
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
width: 26rpx;
|
||||
height: 26rpx;
|
||||
border-right: 2px solid #666
|
||||
border-bottom: 2px solid #666
|
||||
transform: rotate(-45deg); /* 鼠标悬停时旋转360度 */
|
||||
margin-left: 30rpx;
|
||||
// margin-left: 30rpx;
|
||||
margin-right: 50rpx;
|
||||
}
|
||||
.icons{
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
line-height: 30rpx;
|
||||
border-radius: 50%
|
||||
}
|
||||
.texts{
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
.footerLeft>view{
|
||||
margin-right: 40rpx;
|
||||
}
|
||||
.footerBtn{
|
||||
width: 140rpx
|
||||
height: 50rpx
|
||||
text-align: center
|
||||
line-height: 50rpx
|
||||
background-color: #67C23A
|
||||
color: #fff
|
||||
font-size: 28rpx
|
||||
border-radius: 5rpx
|
||||
}
|
||||
}
|
||||
}
|
||||
.cards{
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
z-index: 1000;
|
||||
padding: 100rpx 50rpx;
|
||||
box-sizing: border-box;
|
||||
.cardCon{
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
padding: 20rpx;
|
||||
box-sizing: border-box;
|
||||
.cardHead{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
.questionNums{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.questions{
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
text-align: center;
|
||||
line-height: 60rpx;
|
||||
border-radius: 8rpx;
|
||||
border: 2px solid #E0E0E0;
|
||||
font-size: 28rpx;
|
||||
margin-right: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.questionsActive{
|
||||
background-color: #F0F9FF;
|
||||
border: 2px solid #409EFF;
|
||||
}
|
||||
.questionCorrect{
|
||||
background-color: #F0F9FF;
|
||||
border: 2px solid #64BC38;
|
||||
color: #6BC441;
|
||||
}
|
||||
.questionError{
|
||||
background-color: #FFF1F0;
|
||||
border: 2px solid #F56C6C;
|
||||
color: #F36B6B;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,316 +1,492 @@
|
||||
<template>
|
||||
<AppLayout :title="title" :show-bg-image="false" @onScrollBottom="getDataList('add')">
|
||||
<!-- <template #headerleft>
|
||||
<AppLayout :title="title" :show-bg-image="false">
|
||||
<!-- <template #headerleft>
|
||||
<view class="btnback">
|
||||
<image src="@/static/icon/back.png" @click="navBack"></image>
|
||||
</view>
|
||||
</template> -->
|
||||
<template #headContent>
|
||||
<view class="collection-search">
|
||||
<view class="search-content">
|
||||
<view class="header-input button-click">
|
||||
<uni-icons class="iconsearch" color="#6A6A6A" type="search" size="22"></uni-icons>
|
||||
<input
|
||||
class="input"
|
||||
v-model="searchKeyword"
|
||||
@confirm="searchVideo"
|
||||
placeholder="输入视频名称"
|
||||
placeholder-class="inputplace"
|
||||
/>
|
||||
<uni-icons
|
||||
v-if="searchKeyword"
|
||||
class="clear-icon"
|
||||
type="clear"
|
||||
size="24"
|
||||
color="#999"
|
||||
@click="clearSearch"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view class="main-list">
|
||||
<view class="list-title">
|
||||
<text>视频列表</text>
|
||||
<view class="title-line"></view>
|
||||
<view class="video-box">
|
||||
<view class="video-detail-container">
|
||||
<!-- 视频播放组件 -->
|
||||
<view class="video-wrapper">
|
||||
<video id="myVideo" :src="videoInfo.currentUrl" :poster="trainVideoImgUrl+ videoInfo.cover" @seeked="onSeeked"
|
||||
enable-danmu controls style="width: 100%;" @pause="onPause" @timeupdate="onTimeupdate" @ended="onEnded"></video>
|
||||
</view>
|
||||
</view>
|
||||
<view class="video-grid" v-if="pageState.list.length">
|
||||
<view
|
||||
v-for="video in pageState.list"
|
||||
:key="video.id || video.videoId"
|
||||
class="video-item"
|
||||
:style="getItemBackgroundStyle('video-bg.png')"
|
||||
@click="playVideo(video)"
|
||||
>
|
||||
<view class="video-cover">
|
||||
<image
|
||||
:src="video.coverImage || video.videoCover || '/static/icon/video.png'"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
</view>
|
||||
<view class="video-info">
|
||||
{{ video.title || video.videoName || '未命名视频' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<empty v-else pdTop="200"></empty>
|
||||
</view>
|
||||
<view class="video-info" :style="getItemBackgroundStyle('video-bj2.png')">
|
||||
<view class="video-title">
|
||||
<text>视频详情</text>
|
||||
<view class="title-line"></view>
|
||||
</view>
|
||||
<view class="info-detail">
|
||||
<view class="info-left">
|
||||
<view class="info-item">
|
||||
<image class="icon-img" :src="baseUrl+'/train/zs.png'" mode=""></image>
|
||||
<view class="info-label">
|
||||
分类:
|
||||
</view>
|
||||
<view class="info-value" :data-content="getCategoryLabelByValue(videoInfo.category)">
|
||||
{{getCategoryLabelByValue(videoInfo.category)}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-right">
|
||||
<view class="info-item">
|
||||
<image class="icon-img" :src="baseUrl+'/train/zs.png'" mode=""></image>
|
||||
<view class="info-label">
|
||||
等级:
|
||||
</view>
|
||||
<view class="info-value">
|
||||
{{getLevelLabelByValue(videoInfo.level)}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<image class="icon-img" :src="baseUrl+'/train/zs.png'" mode=""></image>
|
||||
<view class="info-label">
|
||||
讲师:
|
||||
</view>
|
||||
<view class="info-value">
|
||||
{{videoInfo.teacherName}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-detail">
|
||||
<view class="info-left">
|
||||
<view class="info-item">
|
||||
<image class="icon-img" :src="baseUrl+'/train/zs.png'" mode=""></image>
|
||||
<view class="info-label">
|
||||
时长:
|
||||
</view>
|
||||
<view class="info-value">
|
||||
{{videoInfo.hour}}分钟
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-right">
|
||||
<view class="info-item">
|
||||
<image class="icon-img" :src="baseUrl+'/train/zs.png'" mode=""></image>
|
||||
<view class="info-label">
|
||||
发布时间:
|
||||
</view>
|
||||
<view class="info-value">
|
||||
{{videoInfo.uploadTime}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="video-intro" :style="videoIntroBackgroundStyle('video-bj.png')">
|
||||
<view class="intro-title">
|
||||
<image class="intro-img1" :src="baseUrl+'/train/video-kc.png'" mode=""></image>
|
||||
<view class="title1">
|
||||
课程
|
||||
</view>
|
||||
<view class="title2">
|
||||
简介
|
||||
</view>
|
||||
<image class="intro-img2" :src="baseUrl+'/train/video-sc.png'" mode=""></image>
|
||||
</view>
|
||||
<view class="intro-content">
|
||||
{{videoInfo.introduce}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="video-title">
|
||||
<text>学习进度</text>
|
||||
<view class="title-line"></view>
|
||||
</view>
|
||||
<view class="progress-box">
|
||||
<progress :percent="videoInfo.percentage" activeColor="#30A0FF" backgroundColor="#B0DBFF" stroke-width="6" border-radius="10" />
|
||||
<view class="progress-info">
|
||||
<view class="progress-left">
|
||||
已观看
|
||||
</view>
|
||||
<view class="progress-right">
|
||||
{{videoInfo.percentage}}%
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="video-title" v-if="videoInfo.trainClassList && videoInfo.trainClassList.length>0">
|
||||
<text>课程章节</text>
|
||||
<view class="title-line"></view>
|
||||
</view>
|
||||
<view class="chapter-box" v-if="videoInfo.trainClassList && videoInfo.trainClassList.length>0">
|
||||
<view class="chapter-item" :class="{ active: currentChapter === index}" @click="chapterChange(item,index)" v-for="(item ,index) in videoInfo.trainClassList" :key="index">
|
||||
<view class="chapter-left">
|
||||
<view class="chapter-number">
|
||||
{{ index + 1 }}
|
||||
</view>
|
||||
<view class="chapter-info">
|
||||
{{item.className}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="chapter-icon" v-if="currentChapter === index">
|
||||
<uni-icons type="videocam" size="24"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject, ref, reactive } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { inject, reactive,ref, onMounted, onUnmounted, nextTick } from 'vue';
|
||||
import { onLoad,onHide,onUnload } from '@dcloudio/uni-app';
|
||||
const { $api, navTo, navBack } = inject('globalFunction');
|
||||
import config from "@/config.js"
|
||||
|
||||
// state
|
||||
const title = ref('');
|
||||
const searchKeyword = ref('');
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
list: [],
|
||||
total: 0,
|
||||
maxPage: 1,
|
||||
pageSize: 12,
|
||||
search: {},
|
||||
});
|
||||
const baseUrl = 'http://10.110.145.145/images/train/';
|
||||
const videoId=ref('')
|
||||
const userId=ref('')
|
||||
const videoInfo=ref({})
|
||||
const trainVideoImgUrl=config.trainVideoImgUrl
|
||||
const categories=ref([])
|
||||
const levalLabels=ref([])
|
||||
const latestTime = ref(0)
|
||||
const totalTime=ref(0)
|
||||
const baseUrl = config.imgBaseUrl
|
||||
const pageEnterTime = ref(0)
|
||||
const currentChapter = ref(0)
|
||||
const getItemBackgroundStyle = (imageName) => ({
|
||||
backgroundImage: `url(${baseUrl + imageName})`,
|
||||
backgroundSize: 'cover', // 覆盖整个容器
|
||||
backgroundImage: `url(${baseUrl}/train/${imageName})`,
|
||||
backgroundSize: '100% 100%', // 覆盖整个容器
|
||||
backgroundPosition: 'center', // 居中
|
||||
backgroundRepeat: 'no-repeat'
|
||||
});
|
||||
// 模拟视频数据
|
||||
const mockVideoData = [
|
||||
{
|
||||
id: '1',
|
||||
title: '职业技能培训基础课程',
|
||||
coverImage: '/static/icon/server1.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: '面试技巧分享',
|
||||
coverImage: '/static/icon/server2.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: '简历制作指南',
|
||||
coverImage: '/static/icon/server3.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: '职场沟通技巧',
|
||||
coverImage: '/static/icon/server4.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
title: '职业规划讲座',
|
||||
coverImage: '/static/icon/flame.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
title: '行业趋势分析',
|
||||
coverImage: '/static/icon/flame2.png',
|
||||
videoUrl: ''
|
||||
}
|
||||
];
|
||||
const videoIntroBackgroundStyle = (imageName) => ({
|
||||
backgroundImage: `url(${baseUrl}/train/${imageName})`,
|
||||
backgroundSize: '100% 100%', // 覆盖整个容器
|
||||
backgroundPosition: 'center', // 居中
|
||||
backgroundRepeat: 'no-repeat'
|
||||
});
|
||||
const params = reactive({
|
||||
videoId: '',
|
||||
userId: ''
|
||||
})
|
||||
onLoad((options) => {
|
||||
getHeart()
|
||||
pageEnterTime.value = Date.now() // 记录毫秒时间戳
|
||||
videoId.value=options.id
|
||||
getDictionary()
|
||||
});
|
||||
onHide(() => {
|
||||
updateVideoInfo() // 用缓存值,不要调 getCurrentTime
|
||||
reportPageDuration()
|
||||
})
|
||||
onUnload(() => {
|
||||
updateVideoInfo()
|
||||
reportPageDuration()
|
||||
})
|
||||
function getData() {
|
||||
params.videoId=videoId.value
|
||||
params.userId=userId.value
|
||||
$api.myRequest('/train/public/trainVideo/updateWatchCount',{videoId:videoId.value}).then((resData) => {
|
||||
console.log("视频更新次数成功")
|
||||
});
|
||||
let header={
|
||||
'Authorization':uni.getStorageSync('Padmin-Token'),
|
||||
'Content-Type': "application/x-www-form-urlencoded"
|
||||
}
|
||||
$api.myRequest('/train/public/trainVideo/model', params,'post',9100,header).then((resData) => {
|
||||
videoInfo.value=resData
|
||||
videoInfo.value.currentUrl=trainVideoImgUrl+videoInfo.value.trainClassList[0].url
|
||||
videoInfo.value.percentage=((videoInfo.value.process/(videoInfo.value.hour*60))*100).toFixed(2)
|
||||
videoInfo.value.uploadTime=videoInfo.value.uploadTime.split(' ')[0]
|
||||
});
|
||||
}
|
||||
function getHeart() {
|
||||
const raw = uni.getStorageSync("Padmin-Token");
|
||||
const token = typeof raw === "string" ? raw.trim() : "";
|
||||
const headers = token ? { Authorization: raw.startsWith("Bearer ") ? raw : `Bearer ${token}` }: {}
|
||||
$api.myRequest("/dashboard/auth/heart", {}, "POST", 10100, headers).then((resData) => {
|
||||
if (resData.code == 200) {
|
||||
getUserInfo();
|
||||
} else {
|
||||
navTo('/packageB/login')
|
||||
}
|
||||
});
|
||||
}
|
||||
function getUserInfo(){
|
||||
let header={
|
||||
'Authorization':uni.getStorageSync('Padmin-Token')
|
||||
}
|
||||
$api.myRequest('/system/user/login/user/info', {},'get',10100,header).then((resData) => {
|
||||
userId.value=resData.info.userId
|
||||
getData()
|
||||
});
|
||||
}
|
||||
function getDictionary(){
|
||||
$api.myRequest('/system/public/dict/data/type/question_classification', {},'get',9100).then((resData) => {
|
||||
categories.value=resData.data
|
||||
});
|
||||
$api.myRequest('/system/public/dict/data/type/train_level', {},'get',9100).then((resData) => {
|
||||
levalLabels.value=resData.data
|
||||
});
|
||||
}
|
||||
function getCategoryLabelByValue(value) {
|
||||
if (!Array.isArray(categories.value)) {
|
||||
console.warn('categories 不是数组:', categories.value)
|
||||
return ''
|
||||
}
|
||||
const item = categories.value.find(item => item.dictValue === String(value))
|
||||
return item ? item.dictLabel : '暂无分类'
|
||||
}
|
||||
function getLevelLabelByValue(value) {
|
||||
if (!Array.isArray(levalLabels.value)) {
|
||||
console.warn('levalLabels 不是数组:', levalLabels.value)
|
||||
return ''
|
||||
}
|
||||
const item = levalLabels.value.find(item => item.dictValue === String(value))
|
||||
return item ? item.dictLabel : '暂无等级'
|
||||
}
|
||||
function onPause(e){
|
||||
updateVideoInfo()
|
||||
}
|
||||
function onEnded(e){
|
||||
updateVideoInfo()
|
||||
}
|
||||
function onTimeupdate(e){
|
||||
latestTime.value = e.detail.currentTime
|
||||
}
|
||||
function onSeeked(){
|
||||
updateVideoInfo()
|
||||
}
|
||||
// 更新播放时长
|
||||
function updateVideoInfo(){
|
||||
totalTime.value=0
|
||||
if(currentChapter.value>0){
|
||||
videoInfo.value.trainClassList.forEach((item,index)=>{
|
||||
if(index<currentChapter.value){
|
||||
totalTime.value+=Number(item.hour)
|
||||
}
|
||||
})
|
||||
}
|
||||
totalTime.value+=Number(latestTime.value)
|
||||
let paramsData={
|
||||
userId:userId.value,
|
||||
videoId:videoId.value,
|
||||
collect:'',
|
||||
process:Math.floor(Number(totalTime.value))
|
||||
}
|
||||
let header={
|
||||
'Authorization':uni.getStorageSync('Padmin-Token'),
|
||||
'Content-Type': "application/x-www-form-urlencoded"
|
||||
}
|
||||
if(videoInfo.value.isCollect===null && videoInfo.value.process ===null){
|
||||
$api.myRequest('/train/public/videoUser/add', paramsData,'post',9100,header).then((resData) => {
|
||||
console.log("视频播放时长更新成功")
|
||||
});
|
||||
}else{
|
||||
$api.myRequest('/train/public/videoUser/update', paramsData,'post',9100,header).then((resData) => {
|
||||
console.log("视频播放时长更新成功")
|
||||
});
|
||||
}
|
||||
}
|
||||
// 计算并上报停留时长
|
||||
function reportPageDuration() {
|
||||
const duration = Date.now() - pageEnterTime.value // 毫秒
|
||||
const durationSeconds = Math.floor(duration / 1000) // 转为秒
|
||||
if (durationSeconds > 0) {
|
||||
let paramsData={
|
||||
type:'video',
|
||||
hour:durationSeconds,
|
||||
videoId:videoId.value,
|
||||
userId:userId.value,
|
||||
title:videoInfo.value.videoTitle
|
||||
}
|
||||
let header={
|
||||
'Authorization':uni.getStorageSync('Padmin-Token'),
|
||||
'Content-Type': "application/x-www-form-urlencoded"
|
||||
}
|
||||
$api.myRequest('/train/public/userHour/add', paramsData,'post',9100,header).then((resData) => {
|
||||
console.log("学习时长更新成功")
|
||||
});
|
||||
}
|
||||
}
|
||||
function chapterChange(video,index){
|
||||
currentChapter.value=index
|
||||
videoInfo.value.currentUrl=trainVideoImgUrl+video.url
|
||||
}
|
||||
onUnmounted(() => {
|
||||
|
||||
onLoad(() => {
|
||||
getDataList('refresh');
|
||||
});
|
||||
|
||||
// 搜索视频
|
||||
function searchVideo() {
|
||||
getDataList('refresh');
|
||||
}
|
||||
|
||||
// 清除搜索内容
|
||||
function clearSearch() {
|
||||
searchKeyword.value = '';
|
||||
getDataList('refresh');
|
||||
}
|
||||
|
||||
// 获取视频列表
|
||||
function getDataList(type = 'add') {
|
||||
if (type === 'refresh') {
|
||||
pageState.page = 1;
|
||||
pageState.maxPage = 1;
|
||||
}
|
||||
if (type === 'add' && pageState.page < pageState.maxPage) {
|
||||
pageState.page += 1;
|
||||
}
|
||||
|
||||
// 模拟API请求延迟
|
||||
setTimeout(() => {
|
||||
// 在实际项目中,这里应该调用真实的API接口
|
||||
// 目前使用模拟数据
|
||||
let filteredList = [...mockVideoData];
|
||||
|
||||
// 如果有搜索关键词,进行过滤
|
||||
if (searchKeyword.value.trim()) {
|
||||
filteredList = filteredList.filter(video =>
|
||||
video.title.toLowerCase().includes(searchKeyword.value.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
const start = 0;
|
||||
const end = pageState.pageSize;
|
||||
const pageData = filteredList.slice(start, end);
|
||||
|
||||
if (type === 'add') {
|
||||
pageState.list = [...pageState.list, ...pageData];
|
||||
} else {
|
||||
pageState.list = pageData;
|
||||
}
|
||||
|
||||
pageState.total = filteredList.length;
|
||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// 播放视频
|
||||
function playVideo(video) {
|
||||
// 在实际项目中,这里应该导航到视频播放页面
|
||||
// 或者调用视频播放组件
|
||||
console.log('播放视频:', video.title);
|
||||
// 示例:navTo(`/pages/videoPlayer/videoPlayer?id=${video.id}`);
|
||||
$api.msg(`准备播放: ${video.title}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.btnback{
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
.video-box{
|
||||
padding: 10rpx 20rpx;
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
image {
|
||||
height: 100%;
|
||||
.video-detail-container{
|
||||
width: 100%;
|
||||
}
|
||||
.collection-search{
|
||||
padding: 10rpx 20rpx;
|
||||
.search-content{
|
||||
position: relative
|
||||
display: flex
|
||||
align-items: center
|
||||
padding: 14rpx 0
|
||||
.header-input{
|
||||
padding: 0
|
||||
width: calc(100%);
|
||||
position: relative
|
||||
.iconsearch{
|
||||
position: absolute
|
||||
left: 30rpx;
|
||||
top: 50%
|
||||
transform: translate(0, -50%)
|
||||
z-index: 1
|
||||
}
|
||||
.input{
|
||||
padding: 0 80rpx 0 80rpx
|
||||
height: 80rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 75rpx 75rpx 75rpx 75rpx;
|
||||
border: 2rpx solid #ECECEC
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.clear-icon{
|
||||
position: absolute
|
||||
right: 30rpx;
|
||||
top: 50%
|
||||
transform: translate(0, -50%)
|
||||
z-index: 1
|
||||
cursor: pointer
|
||||
}
|
||||
.inputplace{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #B5B5B5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.main-list{
|
||||
background-color: #ffffff;
|
||||
padding: 20rpx 20rpx 28rpx 20rpx;
|
||||
margin:10rpx 30rpx ;
|
||||
box-shadow: 0px 3px 20px 0px rgba(0,105,234,0.1);
|
||||
border-radius: 12px;
|
||||
}
|
||||
.list-title{
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
|
||||
.video-wrapper{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
background-color: #000000;
|
||||
height: auto;
|
||||
}
|
||||
.video-info{
|
||||
width:100%;
|
||||
margin-top:30rpx;
|
||||
padding: 20rpx 30rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.video-title{
|
||||
font-size: 32rpx;
|
||||
color: #404040;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
.title-line{
|
||||
position: absolute;
|
||||
bottom: -10rpx;
|
||||
left: 36rpx;
|
||||
width: 70rpx;
|
||||
width: 60rpx;
|
||||
height: 8rpx;
|
||||
background: linear-gradient(90deg, #FFAD58 0%, #FF7A5B 100%);
|
||||
border-radius: 2px;
|
||||
}
|
||||
.video-grid{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20rpx;
|
||||
}
|
||||
.video-item{
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.2s;
|
||||
padding: 20rpx
|
||||
}
|
||||
.video-item:active{
|
||||
transform: scale(0.98);
|
||||
}
|
||||
.video-cover{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-top: 56.25%; /* 16:9 比例 */
|
||||
background: #f0f0f0;
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
.video-cover image{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.info-detail{
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
.video-info{
|
||||
padding: 16rpx 16rpx 0 16rpx;
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
.info-left{
|
||||
width: 35%;
|
||||
}
|
||||
.info-right{
|
||||
width: 65%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.info-item{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.icon-img{
|
||||
width: 24rpx;
|
||||
height: 28rpx;
|
||||
margin-right: 4rpx;
|
||||
}
|
||||
.info-label{
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #0068C8;
|
||||
min-width: 86rpx;
|
||||
}
|
||||
.info-value{
|
||||
font-size: 28rpx;
|
||||
color: #404040;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
.video-title{
|
||||
.video-intro{
|
||||
padding: 20rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
.intro-title{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.intro-img1{
|
||||
width: 36rpx;
|
||||
height: 30rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
.intro-img2{
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
.title1{
|
||||
font-size: 26rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
}
|
||||
.title2{
|
||||
color: #077DF5;
|
||||
font-size: 26rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
.intro-content{
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.progress-box{
|
||||
background: linear-gradient(0deg, #DFEDFF 0%, #F8FCFF 100%);
|
||||
box-shadow: 0px 0px 10px 0px rgba(0,48,107,0.1);
|
||||
border-radius: 16rpx;
|
||||
padding: 40rpx 30rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
.progress-info{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
.chapter-box{
|
||||
background: linear-gradient(0deg, #DFEDFF 0%, #F8FCFF 100%);
|
||||
box-shadow: 0px 0px 10px 0px rgba(0,48,107,0.1);
|
||||
border-radius: 16rpx;
|
||||
padding: 40rpx 30rpx;
|
||||
}
|
||||
.chapter-item{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16rpx 24rpx;
|
||||
border-radius: 12rpx;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
margin-bottom: 16rpx;
|
||||
border: 2rpx solid #F0F0F0;
|
||||
background: #F9F9F9;
|
||||
}
|
||||
.chapter-item.active {
|
||||
background-color: #e6f7ff;
|
||||
color: #409EFF;
|
||||
}
|
||||
.chapter-left{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.chapter-number{
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
background: #cccccc;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
margin-right: 16rpx;
|
||||
color: #fff;
|
||||
}
|
||||
.chapter-item.active .chapter-number {
|
||||
background: #409EFF;
|
||||
color: #fff;
|
||||
}
|
||||
.chapter-info {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 40rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: #303133;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -34,9 +34,9 @@
|
||||
<text>视频列表</text>
|
||||
<view class="title-line"></view>
|
||||
</view>
|
||||
<view class="video-grid" v-if="pageState.list.length">
|
||||
<view class="video-grid" v-if="dataList.length>0">
|
||||
<view
|
||||
v-for="video in pageState.list"
|
||||
v-for="video in dataList"
|
||||
:key="video.id || video.videoId"
|
||||
class="video-item"
|
||||
:style="getItemBackgroundStyle('video-bg.png')"
|
||||
@@ -44,12 +44,12 @@
|
||||
>
|
||||
<view class="video-cover">
|
||||
<image
|
||||
:src="video.coverImage || video.videoCover || '/static/icon/video.png'"
|
||||
:src="trainVideoImgUrl+ video.cover"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
</view>
|
||||
<view class="video-info">
|
||||
{{ video.title || video.videoName || '未命名视频' }}
|
||||
{{ video.videoTitle || '未命名视频' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -62,64 +62,23 @@
|
||||
import { inject, ref, reactive } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
const { $api, navTo, navBack } = inject('globalFunction');
|
||||
import config from "@/config.js"
|
||||
|
||||
// state
|
||||
const title = ref('');
|
||||
const searchKeyword = ref('');
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
list: [],
|
||||
total: 0,
|
||||
maxPage: 1,
|
||||
pageSize: 12,
|
||||
search: {},
|
||||
});
|
||||
const baseUrl = 'http://10.110.145.145/images/train/';
|
||||
const dataList=ref([])
|
||||
const pageSize=ref(10)
|
||||
const pageNum=ref(1)
|
||||
const totalNum=ref(0)
|
||||
const baseUrl = config.imgBaseUrl
|
||||
const getItemBackgroundStyle = (imageName) => ({
|
||||
backgroundImage: `url(${baseUrl + imageName})`,
|
||||
backgroundImage: `url(${baseUrl}/train/${imageName})`,
|
||||
backgroundSize: 'cover', // 覆盖整个容器
|
||||
backgroundPosition: 'center', // 居中
|
||||
backgroundRepeat: 'no-repeat'
|
||||
});
|
||||
// 模拟视频数据
|
||||
const mockVideoData = [
|
||||
{
|
||||
id: '1',
|
||||
title: '职业技能培训基础课程',
|
||||
coverImage: '/static/icon/server1.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: '面试技巧分享',
|
||||
coverImage: '/static/icon/server2.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: '简历制作指南',
|
||||
coverImage: '/static/icon/server3.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: '职场沟通技巧',
|
||||
coverImage: '/static/icon/server4.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
title: '职业规划讲座',
|
||||
coverImage: '/static/icon/flame.png',
|
||||
videoUrl: ''
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
title: '行业趋势分析',
|
||||
coverImage: '/static/icon/flame2.png',
|
||||
videoUrl: ''
|
||||
}
|
||||
];
|
||||
const trainVideoImgUrl=config.trainVideoImgUrl
|
||||
|
||||
onLoad(() => {
|
||||
getDataList('refresh');
|
||||
@@ -138,49 +97,46 @@ function clearSearch() {
|
||||
|
||||
// 获取视频列表
|
||||
function getDataList(type = 'add') {
|
||||
let maxPage=Math.ceil(totalNum.value/pageSize.value)
|
||||
let params={}
|
||||
if (type === 'refresh') {
|
||||
pageState.page = 1;
|
||||
pageState.maxPage = 1;
|
||||
pageNum.value = 1;
|
||||
params={
|
||||
category:'',
|
||||
hour:'',
|
||||
level:'',
|
||||
searchValue:searchKeyword.value,
|
||||
orderStr:'',
|
||||
pageSize:pageSize.value,
|
||||
pageNum:pageNum.value
|
||||
}
|
||||
$api.myRequest('/train/public/trainVideo/trainVideoList', params).then((resData) => {
|
||||
dataList.value=resData.rows
|
||||
totalNum.value=resData.total
|
||||
});
|
||||
}
|
||||
if (type === 'add' && pageState.page < pageState.maxPage) {
|
||||
pageState.page += 1;
|
||||
}
|
||||
|
||||
// 模拟API请求延迟
|
||||
setTimeout(() => {
|
||||
// 在实际项目中,这里应该调用真实的API接口
|
||||
// 目前使用模拟数据
|
||||
let filteredList = [...mockVideoData];
|
||||
|
||||
// 如果有搜索关键词,进行过滤
|
||||
if (searchKeyword.value.trim()) {
|
||||
filteredList = filteredList.filter(video =>
|
||||
video.title.toLowerCase().includes(searchKeyword.value.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
const start = 0;
|
||||
const end = pageState.pageSize;
|
||||
const pageData = filteredList.slice(start, end);
|
||||
|
||||
if (type === 'add') {
|
||||
pageState.list = [...pageState.list, ...pageData];
|
||||
} else {
|
||||
pageState.list = pageData;
|
||||
}
|
||||
|
||||
pageState.total = filteredList.length;
|
||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||
}, 300);
|
||||
if (type === 'add' && pageNum.value < maxPage) {
|
||||
pageNum.value += 1;
|
||||
params={
|
||||
category:'',
|
||||
hour:'',
|
||||
level:'',
|
||||
searchValue:searchKeyword.value,
|
||||
orderStr:'',
|
||||
pageSize:pageSize.value,
|
||||
pageNum:pageNum.value
|
||||
}
|
||||
$api.myRequest('/train/public/trainVideo/trainVideoList', params).then((resData) => {
|
||||
dataList.value=dataList.value.concat(resData.rows)
|
||||
totalNum.value=resData.total
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 播放视频
|
||||
function playVideo(video) {
|
||||
// 在实际项目中,这里应该导航到视频播放页面
|
||||
// 或者调用视频播放组件
|
||||
console.log('播放视频:', video.title);
|
||||
// 示例:navTo(`/pages/videoPlayer/videoPlayer?id=${video.id}`);
|
||||
$api.msg(`准备播放: ${video.title}`);
|
||||
navTo(`/packageB/train/video/videoDetail?id=${video.videoId}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -189,13 +145,6 @@ function playVideo(video) {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
image {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
@@ -263,7 +212,7 @@ image {
|
||||
width: 70rpx;
|
||||
height: 8rpx;
|
||||
background: linear-gradient(90deg, #FFAD58 0%, #FF7A5B 100%);
|
||||
border-radius: 2px;
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
.video-grid{
|
||||
display: grid;
|
||||
|
||||
@@ -126,14 +126,14 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from "@/apiB/job.js"
|
||||
import api1 from "@/apiB/user.js"
|
||||
import api from "@/apiCa/job.js"
|
||||
import api1 from "@/apiCa/user.js"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
showLogin: false,
|
||||
isVisitor: false, //游客
|
||||
user: uni.getStorageSync("userInfo").user,
|
||||
user: uni.getStorageSync("CAuserInfo").user,
|
||||
id: 0,
|
||||
jobDetailData: {
|
||||
Name: "",
|
||||
@@ -10,11 +10,12 @@
|
||||
<text class="icon icon-search"></text>
|
||||
<input type="search" v-model="kw" placeholder="请输入职业名称" @input="inputKeywrok"/>
|
||||
<view class="list-wrap" v-show="kw != ''">
|
||||
<navigator class="link" :url="'/packageB/pages/job/details?id='+item.Id" v-for="(item, index) in jobDataList" :key="index">{{item.Name}}</navigator>
|
||||
<navigator class="link" :url="'/packageCa/job/details?id='+item.Id" v-for="(item, index) in jobDataList" :key="index">{{item.Name}}</navigator>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="u-menu-wrap" :style="{height: winHeight - barHeight - loginHeight + 'px'}">
|
||||
<!-- :style="{height: winHeight - barHeight - loginHeight + 'px'}" -->
|
||||
<view class="u-menu-wrap" >
|
||||
<scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop" :scroll-into-view="itemId">
|
||||
<view v-for="(item,index) in jobList" :key="index" class="u-tab-item"
|
||||
:class="[current == index ? 'u-tab-item-active' : '']" @tap.stop="swichMenu(index)">
|
||||
@@ -29,7 +30,7 @@
|
||||
</view>
|
||||
<view class="item-container">
|
||||
<view class="thumb-box" v-for="(item1, index1) in item.SubList" :key="index1" >
|
||||
<navigator class="item-menu-name" :url="`/packageB/pages/job/midList?code=${item1.Code}&name=${item1.Name}`" >{{item1.Name}}</navigator>
|
||||
<navigator class="item-menu-name" :url="`/packageCa/job/midList?code=${item1.Code}&name=${item1.Name}`" >{{item1.Name}}</navigator>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -51,13 +52,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from "@/apiB/job.js"
|
||||
import jobList from "@/dataB/jobList.json";
|
||||
import api from "@/apiCa/job.js"
|
||||
import jobList from "@/packageCa/job/jobList.json";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
kw: "", //搜索关键
|
||||
user: uni.getStorageSync("userInfo").user,
|
||||
user: uni.getStorageSync("CAuserInfo").user,
|
||||
isVisitor: false, //游客
|
||||
barHeight: wx.getWindowInfo().statusBarHeight,
|
||||
winHeight: wx.getWindowInfo().windowHeight,
|
||||
@@ -247,7 +248,7 @@
|
||||
})
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: "/packageB/pages/job/smallList?name=" + this.kw.trim()
|
||||
url: "/packageCa/job/smallList?name=" + this.kw.trim()
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -275,9 +276,10 @@
|
||||
.jobIndex {
|
||||
position: relative;
|
||||
padding-top: 0;
|
||||
height: 100vh;
|
||||
.u-menu-wrap {
|
||||
display: flex;
|
||||
// height: calc(100vh - 100rpx);
|
||||
height: calc(100vh - 100rpx);
|
||||
overflow: auto;
|
||||
padding-top: 100rpx;
|
||||
.u-tab-view {
|
||||
@@ -301,7 +303,7 @@
|
||||
.u-tab-item-active {
|
||||
position: relative;
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
background: #1677ff;
|
||||
border-radius:5px;
|
||||
@@ -442,6 +444,7 @@
|
||||
overflow: auto;
|
||||
box-shadow: 0 0 4rpx 2rpx #f2f2f2;
|
||||
border-radius: 8rpx;
|
||||
z-index: 90;
|
||||
.link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -38,13 +38,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from "@/apiB/job.js"
|
||||
import api from "@/apiCa/job.js"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
showLogin: false,
|
||||
isVisitor: false, //游客
|
||||
user: uni.getStorageSync("userInfo").user,
|
||||
user: uni.getStorageSync("CAuserInfo").user,
|
||||
name: "",
|
||||
code: "",
|
||||
jobList: [],
|
||||
@@ -80,7 +80,7 @@
|
||||
//this.showLogin = true;
|
||||
}else {
|
||||
uni.navigateTo({
|
||||
url: `/packageB/pages/job/smallList?code=${item.Code}&name=${item.Name}`
|
||||
url: `/packageCa/job/smallList?code=${item.Code}&name=${item.Name}`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -35,13 +35,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from "@/apiB/job.js"
|
||||
import api from "@/apiCa/job.js"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
showLogin: false,
|
||||
isVisitor: false, //游客
|
||||
user: uni.getStorageSync("userInfo").user,
|
||||
user: uni.getStorageSync("CAuserInfo").user,
|
||||
name: "",
|
||||
code: "",
|
||||
jobList: [],
|
||||
@@ -75,7 +75,7 @@
|
||||
//this.showLogin = true;
|
||||
}else {
|
||||
uni.navigateTo({
|
||||
url: `/packageB/pages/job/details?id=${item.Id}&name=${item.Name}`
|
||||
url: `/packageCa/job/details?id=${item.Id}&name=${item.Name}`
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -56,7 +56,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from "@/apiB/testManage.js"
|
||||
import api from "@/apiCa/testManage.js"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -329,11 +329,11 @@
|
||||
setTimeout(() => {
|
||||
if (this.testType == -27) {
|
||||
uni.redirectTo({
|
||||
url: `/packageB/pages/testReport/multipleAbilityTestReport?id=${res.Data.TestId}`
|
||||
url: `/packageCa/testReport/multipleAbilityTestReport?id=${res.Data.TestId}`
|
||||
})
|
||||
} else if (this.testType == -28) {
|
||||
uni.redirectTo({
|
||||
url: `/packageB/pages/testReport/generalCareerTestReport?id=${res.Data.TestId}`
|
||||
url: `/packageCa/testReport/generalCareerTestReport?id=${res.Data.TestId}`
|
||||
})
|
||||
}
|
||||
}, 1000)
|
||||
@@ -64,7 +64,7 @@
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import api from "@/apiB/testManage.js"
|
||||
import api from "@/apiCa/testManage.js"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -333,7 +333,7 @@
|
||||
beforePage.data.refreshIfNeeded = true;
|
||||
setTimeout(()=>{
|
||||
uni.redirectTo({
|
||||
url: `/packageB/pages/testReport/interestTestReport`
|
||||
url: `/packageCa/testReport/interestTestReport`
|
||||
})
|
||||
},1000)
|
||||
} else {
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
|
||||
<script>
|
||||
import api from "@/apiB/testManage.js"
|
||||
import api from "@/apiCa/testManage.js"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -263,7 +263,7 @@
|
||||
beforePage.data.refreshIfNeeded = true;
|
||||
setTimeout(()=>{
|
||||
uni.redirectTo({
|
||||
url: `/packageB/pages/testReport/personalTestReport?year=${res.Data.Year}`
|
||||
url: `/packageCa/testReport/personalTestReport?year=${res.Data.Year}`
|
||||
})
|
||||
},1000)
|
||||
|
||||
@@ -375,7 +375,7 @@
|
||||
width: 630rpx;
|
||||
height: 96rpx;
|
||||
padding-left: 40rpx;
|
||||
background: #EDF6FF;
|
||||
background: #f5f5f5;
|
||||
margin-bottom: 24rpx;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
font-size: 28rpx;
|
||||
@@ -76,7 +76,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from "@/apiB/testManage.js"
|
||||
import api from "@/apiCa/testManage.js"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -231,7 +231,7 @@
|
||||
uni.showLoading({
|
||||
title: "加载中"
|
||||
})
|
||||
let eduLevel = uni.getStorageSync("userInfo").user.GradeLevel;
|
||||
let eduLevel = uni.getStorageSync("CAuserInfo").user.GradeLevel;
|
||||
new Promise((resolve,reject)=>{
|
||||
return api.getTestTypeTagLIst().then((res)=>{
|
||||
resolve(res)
|
||||
@@ -423,21 +423,21 @@
|
||||
case 11: {
|
||||
// 高中兴趣测评
|
||||
uni.navigateTo({
|
||||
url: "/packageB/pages/pagesTest/interestTestTitle"
|
||||
url: "/packageCa/pagesTest/interestTestTitle"
|
||||
})
|
||||
break;
|
||||
}
|
||||
case 15: {
|
||||
// 人格测评
|
||||
uni.navigateTo({
|
||||
url: "/packageB/pages/pagesTest/personalTestTitle"
|
||||
url: "/packageCa/pagesTest/personalTestTitle"
|
||||
})
|
||||
break;
|
||||
}
|
||||
case 17: {
|
||||
// 工作价值观测评
|
||||
uni.navigateTo({
|
||||
url: "/packageB/pages/pagesTest/workValuesTestTitle"
|
||||
url: "/packageCa/pagesTest/workValuesTestTitle"
|
||||
})
|
||||
break;
|
||||
}
|
||||
@@ -445,14 +445,14 @@
|
||||
case -27: {
|
||||
// 多元能力
|
||||
uni.navigateTo({
|
||||
url: "/packageB/pages/pagesTest/customTestTitle?testType=-27"
|
||||
url: "/packageCa/pagesTest/customTestTitle?testType=-27"
|
||||
})
|
||||
break;
|
||||
}
|
||||
case -28: {
|
||||
// 通用职业
|
||||
uni.navigateTo({
|
||||
url: "/packageB/pages/pagesTest/customTestTitle?testType=-28"
|
||||
url: "/packageCa/pagesTest/customTestTitle?testType=-28"
|
||||
})
|
||||
break;
|
||||
}
|
||||
@@ -478,35 +478,35 @@
|
||||
case 11: {
|
||||
// 兴趣测评
|
||||
uni.navigateTo({
|
||||
url: `/packageB/pages/testReport/interestTestReport`
|
||||
url: `/packageCa/testReport/interestTestReport`
|
||||
})
|
||||
break;
|
||||
}
|
||||
case 15: {
|
||||
// 人格测评
|
||||
uni.navigateTo({
|
||||
url: `/packageB/pages/testReport/personalTestReport`
|
||||
url: `/packageCa/testReport/personalTestReport`
|
||||
})
|
||||
break;
|
||||
}
|
||||
case 17: {
|
||||
// 工作价值观测评
|
||||
uni.navigateTo({
|
||||
url: `/packageB/pages/testReport/workValuesTestReport`
|
||||
url: `/packageCa/testReport/workValuesTestReport`
|
||||
})
|
||||
break;
|
||||
}
|
||||
case -27: {
|
||||
// 多元能力
|
||||
uni.navigateTo({
|
||||
url: `/packageB/pages/testReport/multipleAbilityTestReport?id=${item.RecordId}`
|
||||
url: `/packageCa/testReport/multipleAbilityTestReport?id=${item.RecordId}`
|
||||
})
|
||||
break;
|
||||
}
|
||||
case -28: {
|
||||
// 通用职业
|
||||
uni.navigateTo({
|
||||
url: `/packageB/pages/testReport/generalCareerTestReport?id=${item.RecordId}`
|
||||
url: `/packageCa/testReport/generalCareerTestReport?id=${item.RecordId}`
|
||||
})
|
||||
break;
|
||||
}
|
||||
@@ -47,7 +47,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from "@/apiB/testManage.js"
|
||||
import api from "@/apiCa/testManage.js"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -231,7 +231,7 @@
|
||||
beforePage.data.refreshIfNeeded = true;
|
||||
setTimeout(()=>{
|
||||
uni.redirectTo({
|
||||
url: `/packageB/pages/testReport/workValuesTestReport?year=${res.Data.Year}`
|
||||
url: `/packageCa/testReport/workValuesTestReport?year=${res.Data.Year}`
|
||||
})
|
||||
},1000)
|
||||
} else {
|
||||
@@ -3,7 +3,7 @@
|
||||
<view class="yanshi-wrap">
|
||||
<view class="head-bar" :style="{'margin-top': barHeight + 5 + 'px'}">
|
||||
<view class="go-back" @click="goback"></view>
|
||||
<text>AI智慧就业服务</text>
|
||||
<text>素质测评</text>
|
||||
</view>
|
||||
<view class="section">
|
||||
<view class="head-title">测评中心</view>
|
||||
@@ -23,59 +23,46 @@
|
||||
<text class="icon icon-103"></text>
|
||||
<text class="title">职业库</text>
|
||||
</view>
|
||||
<!-- <view class="item" @click="navDetail(4)">
|
||||
<text class="icon icon-104"></text>
|
||||
<text class="title">个人档案</text>
|
||||
</view> -->
|
||||
</view>
|
||||
<view class="head-title">规划中心</view>
|
||||
<view class="head-title">职业生涯规划</view>
|
||||
<view class="nav-block">
|
||||
<view class="item" @click="navDetail(6)">
|
||||
<text class="icon icon-105"></text>
|
||||
<text class="title">生涯罗盘</text>
|
||||
</view>
|
||||
<view class="item" @click="navDetail(2)">
|
||||
<view class="item" @click="navDetail(5)">
|
||||
<text class="icon icon-106"></text>
|
||||
<text class="title">职业生涯路径</text>
|
||||
</view>
|
||||
<view class="item" @click="navDetail(7)">
|
||||
<text class="icon icon-107"></text>
|
||||
<text class="title">学业规划</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="head-title">档案中心</view>
|
||||
<view class="nav-block">
|
||||
</view>
|
||||
<view class="item" @click="navDetail(4)">
|
||||
<text class="icon icon-108"></text>
|
||||
<text class="title">生涯档案</text>
|
||||
</view>
|
||||
<!-- <view class="item" @click="navDetail(5)">
|
||||
<text class="icon icon-11"></text>
|
||||
<text class="title">测试完善个人信息</text>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api1 from "@/apiB/weChartUser.js"
|
||||
import api3 from "@/apiB/tenpayOrder.js"
|
||||
import api4 from "@/apiB/user.js"
|
||||
import api from "@/apiCa/user.js"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
barHeight: wx.getWindowInfo().statusBarHeight,
|
||||
user: null,//用户信息
|
||||
userId: 0,
|
||||
name: ""
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let user = uni.getStorageSync("userInfo").user;
|
||||
if(user == undefined){
|
||||
this.queryWechartToken();
|
||||
}
|
||||
this.getUserInfor();
|
||||
onLoad(e) {
|
||||
this.userId = e.userId;
|
||||
this.name = e.name;
|
||||
this.queryWechartToken();
|
||||
},
|
||||
methods: {
|
||||
// 返回
|
||||
@@ -83,10 +70,10 @@
|
||||
uni.navigateBack(-1);
|
||||
},
|
||||
async getUserInfor(){
|
||||
const res = await api4.getUserBasisInfo();
|
||||
const res = await api.getUserBasisInfo();
|
||||
if (res.Result == 1) {
|
||||
const data = res.Data.data;
|
||||
if(!data.SpecialtyName){
|
||||
if(data === null){
|
||||
uni.showToast({
|
||||
title: "请先完善个人信息",
|
||||
duration:2000,
|
||||
@@ -94,7 +81,7 @@
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: "/packageB/pages/userCenter/fillInInformation"
|
||||
url: "/packageCa/userCenter/fillInInformation"
|
||||
})
|
||||
}, 2000);
|
||||
}
|
||||
@@ -111,102 +98,83 @@
|
||||
case 1:
|
||||
case 2: {
|
||||
uni.navigateTo({
|
||||
url: "/packageB/pages/pagesTest/testList"
|
||||
url: "/packageCa/pagesTest/testList"
|
||||
})
|
||||
break;
|
||||
}
|
||||
case 3 : {
|
||||
uni.navigateTo({
|
||||
url: "/packageB/pages/job/index"
|
||||
url: "/packageCa/job/index"
|
||||
})
|
||||
break;
|
||||
}
|
||||
case 4 : {
|
||||
uni.navigateTo({
|
||||
url: "/packageB/pages/userCenter/personDocument"
|
||||
url: "/packageCa/userCenter/personDocument"
|
||||
})
|
||||
break;
|
||||
}
|
||||
case 5 : {
|
||||
uni.navigateTo({
|
||||
url: "/packageB/pages/userCenter/fillInInformation"
|
||||
url: "/packageCa/userCenter/professionPath"
|
||||
})
|
||||
break;
|
||||
}
|
||||
case 6 : {
|
||||
uni.navigateTo({
|
||||
url: "/packageB/pages/userCenter/careerCompass"
|
||||
url: "/packageCa/userCenter/careerCompass"
|
||||
})
|
||||
break;
|
||||
}
|
||||
case 7 : {
|
||||
uni.navigateTo({
|
||||
url: "/packageB/pages/userCenter/smartTarget"
|
||||
url: "/packageCa/userCenter/smartTarget"
|
||||
})
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 登录获取openid
|
||||
loginMpWeixin() {
|
||||
return new Promise((resolve,reject)=>{
|
||||
let openid = uni.getStorageSync('userInfo').openid;
|
||||
if (!openid) {
|
||||
uni.login({
|
||||
provider: 'weixin',
|
||||
success: (res)=> {
|
||||
console.log("res.code======="+res.code);
|
||||
api3.getOpenId(res.code).then((res2) => {
|
||||
console.log("88888888");
|
||||
// uni.setStorageSync('userInfo', data.Data);
|
||||
const userInfo = res2.Data
|
||||
this.user = userInfo.user;
|
||||
resolve(userInfo)
|
||||
})
|
||||
},
|
||||
fail(err) {}
|
||||
})
|
||||
}else {
|
||||
const userInfo = uni.getStorageSync("userInfo");
|
||||
this.user = userInfo.user;
|
||||
resolve(userInfo)
|
||||
}
|
||||
})
|
||||
},
|
||||
// 获取绑定账户
|
||||
async getAccessTokenAndUser() {
|
||||
const userInfo = await this.loginMpWeixin();
|
||||
return new Promise((resolve,reject)=>{
|
||||
api1.getAccessTokenAndUser(userInfo.openid).then((res)=>{
|
||||
if(res.Result == 1){
|
||||
this.user = res.Data.User;
|
||||
userInfo.token = res.Data.Token;
|
||||
userInfo.user = res.Data.User;
|
||||
userInfo.year = res.Data.Year;
|
||||
userInfo.expirationDate = res.Data.ExpirationDate;
|
||||
userInfo.vipName = res.Data.VipName;
|
||||
if(res.Data.User != null){
|
||||
resolve(userInfo)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
// 登录获取用户信息
|
||||
async queryKaShiToken() {
|
||||
const res = await api.queryKaShiToken(this.userId,this.name)
|
||||
if(res.Result == 1){
|
||||
return res.Data;
|
||||
}else {
|
||||
return null
|
||||
}
|
||||
},
|
||||
// 获取token
|
||||
async queryWechartToken() {
|
||||
uni.showLoading({
|
||||
title: "加载中"
|
||||
})
|
||||
const data = await this.getAccessTokenAndUser();
|
||||
api1.queryWechartToken(data.user.Id,data.user.SchoolId,data.user.UserType).then((res)=>{
|
||||
const data = await this.queryKaShiToken();
|
||||
if(data.userInfo != null){
|
||||
const res = await api.queryWechartToken(data.userInfo.Id,2268,1)
|
||||
uni.hideLoading();
|
||||
if(res.Result == 1){
|
||||
data.userToken = res.Data.token;
|
||||
uni.setStorageSync('userInfo',data);
|
||||
let params = {
|
||||
token:data.token,
|
||||
user:data.userInfo,
|
||||
userToken: res.Data.token
|
||||
};
|
||||
uni.setStorageSync('CAuserInfo',params);
|
||||
this.getUserInfor();
|
||||
}
|
||||
})
|
||||
},
|
||||
}else {
|
||||
uni.showToast({
|
||||
title: "获取用户信息失败",
|
||||
icon: "none"
|
||||
})
|
||||
setTimeout(()=>{
|
||||
uni.reLaunch({
|
||||
url: "/pages/index/index"
|
||||
})
|
||||
},1500)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -30,7 +30,7 @@
|
||||
{{optionStr2}}
|
||||
<view class="iocn"></view>
|
||||
</view>
|
||||
<view class="title">群体维度</view>
|
||||
<!-- <view class="title">群体维度</view>
|
||||
<view class="options">
|
||||
<view class="item" :class="[schoolLevel == 1?'on':'', gradeShow?'':'disable']" v-on:click="selectSchoolLevel(1)" >班级</view>
|
||||
<view class="item" :class="[schoolLevel == 2?'on':'', gradeShow?'':'disable']" v-on:click="selectSchoolLevel(2)">年级</view>
|
||||
@@ -40,7 +40,7 @@
|
||||
<view class="options">
|
||||
<view class="item" v-on:click="selectSex(1)" :class="sexType == 1?'on':''">男</view>
|
||||
<view class="item" v-on:click="selectSex(2)" :class="sexType == 2?'on':''">女</view>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
<view class="content" v-else>
|
||||
<view class="title">我的报告</view>
|
||||
@@ -54,7 +54,7 @@
|
||||
{{optionStr2}}
|
||||
<view class="iocn"></view>
|
||||
</view>
|
||||
<view class="title">群体维度</view>
|
||||
<!-- <view class="title">群体维度</view>
|
||||
<view class="options">
|
||||
<view v-for="(item, index) in departList" :key="index">
|
||||
<view class="item" v-on:click="selectSchoolLevel(item)" :class="schoolLevel == item.DepartId?'on':''">
|
||||
@@ -66,7 +66,7 @@
|
||||
<view class="options">
|
||||
<view class="item" v-on:click="selectSex(1)" :class="sexType == 1?'on':''">男</view>
|
||||
<view class="item" v-on:click="selectSex(2)" :class="sexType == 2?'on':''">女</view>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
<view class="btn-wrap">
|
||||
<view class="btn" v-on:click="confirmCompute">
|
||||
@@ -107,7 +107,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from "@/apiB/testManage.js";
|
||||
import api from "@/apiCa/testManage.js";
|
||||
export default {
|
||||
props: {
|
||||
testType: {
|
||||
@@ -121,11 +121,7 @@
|
||||
recordId: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -134,12 +130,12 @@
|
||||
showTime: false, //显示时间选择
|
||||
treeList: [], //时间列表
|
||||
childrenList: [],//时间子级
|
||||
selYTItem1: null,//临时选中的学年1
|
||||
selRepItem1: null,//临时选中的报告1
|
||||
selYTItem2: null,//临时选中的学年2
|
||||
selRepItem2: null,//临时选中的报告2
|
||||
checkedRepItem1: null,//确认选中报告1
|
||||
checkedRepItem2: null,//确认选中报告2
|
||||
selYTItem1: {},//临时选中的学年1
|
||||
selRepItem1: {},//临时选中的报告1
|
||||
selYTItem2: {},//临时选中的学年2
|
||||
selRepItem2: {},//临时选中的报告2
|
||||
checkedRepItem1: {},//确认选中报告1
|
||||
checkedRepItem2: {},//确认选中报告2
|
||||
timeType: 1,//时间类型,是报告时间1,还是对比时间2
|
||||
optionStr1: "",//我的报告展示字段
|
||||
optionStr2: "",//我的报告展示字段
|
||||
@@ -240,12 +236,15 @@
|
||||
changeYearTrem(ITEM,INDEX){
|
||||
if(INDEX == 1){
|
||||
this.selYTItem1 = ITEM;
|
||||
this.selRepItem1 = null;
|
||||
this.selRepItem1 = {};
|
||||
}else {
|
||||
this.selYTItem2 = ITEM;
|
||||
this.selRepItem2 = null;
|
||||
this.selRepItem2 = {};
|
||||
}
|
||||
this.childrenList = ITEM.children;
|
||||
console.log(this.selYTItem2);
|
||||
console.log(this.selRepItem2);
|
||||
console.log(this.childrenList);
|
||||
},
|
||||
// 显示团队对比弹窗
|
||||
showContrastLayer(){
|
||||
@@ -5,7 +5,7 @@
|
||||
<text>我的报告</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<contrastBox :value="isShowEchart" @updateValue="handleChildValueChange" :testType="testType" :userId="userId" :recordId="recordId" @compareParameters="opCompareParameters"></contrastBox>
|
||||
<contrastBox @updateValue="handleChildValueChange" :testType="testType" :userId="userId" :recordId="recordId" @compareParameters="opCompareParameters"></contrastBox>
|
||||
<view class="section-block">
|
||||
<testHead :reportTitle="'通用(职业)能力测评报告'" :testTime="testDate" :isIntroduce="false" :isVideo="false" :videoUrl="videoUrl" :introduceUrl="introduceUrl" ></testHead>
|
||||
<view class="s-line"></view>
|
||||
@@ -39,7 +39,7 @@
|
||||
<view class="code-value">
|
||||
<text class="scort" v-text="lowStr==''?'无':lowStr"></text>
|
||||
</view>
|
||||
<view v-show="isShowEchart" class="chat-wrap">
|
||||
<view class="chat-wrap">
|
||||
<view class="row-item"><l-echart ref="chartRef" class="charts-box"></l-echart>
|
||||
</view>
|
||||
</view>
|
||||
@@ -71,11 +71,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import testHead from "@/packageB/pages/testReport/components/testHead.vue"
|
||||
import contrastBox from "@/packageB/pages/testReport/components/contrastBox.vue"
|
||||
import api from "@/apiB/testManage.js";
|
||||
import testHead from "@/packageCa/testReport/components/testHead.vue"
|
||||
import contrastBox from "@/packageCa/testReport/components/contrastBox.vue"
|
||||
import api from "@/apiCa/testManage.js";
|
||||
import theme from '@/uni_modules/lime-echart/static/walden.json';
|
||||
const echarts = require('../../../uni_modules/lime-echart/static/echarts.min.js');
|
||||
const echarts = require('../../uni_modules/lime-echart/static/echarts.min.js');
|
||||
// import * as echarts from '@/uni_modules/lime-echart/static/echarts.min';
|
||||
// // 注册主题
|
||||
// echarts.registerTheme('theme', theme);
|
||||
@@ -155,7 +155,6 @@
|
||||
recordId: 0,
|
||||
labelName1: "",//表值1
|
||||
labelName2: "",//表值2
|
||||
isShowEchart:true,//是否显示图表
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
@@ -172,10 +171,6 @@
|
||||
this.getTestRecord(this.currentYear, this.currentTerm,this.recordId);
|
||||
},
|
||||
methods: {
|
||||
handleChildValueChange(newValue) {
|
||||
console.log("66666====");
|
||||
this.isShowEchart = newValue
|
||||
},
|
||||
changeMore(INDEX) {
|
||||
this.list[INDEX].showMore = !this.list[INDEX].showMore
|
||||
this.$forceUpdate();
|
||||
@@ -5,9 +5,9 @@
|
||||
<text>我的报告</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<contrastBox :value="isShowEchart" @updateValue="handleChildValueChange" :testType="testType" :userId="userId" :recordId="recordId" @compareParameters="opCompareParameters"></contrastBox>
|
||||
<contrastBox :testType="testType" :userId="userId" :recordId="recordId" @compareParameters="opCompareParameters"></contrastBox>
|
||||
<view class="section-block">
|
||||
<testHead :value="isShowEchart" @updateValue="handleChildValueChange" :reportTitle="'职业兴趣测评报告'" :testTime="testDate" :isIntroduce="false" :isVideo="true" :videoUrl="videoUrl" :introduceUrl="introduceUrl" ></testHead>
|
||||
<testHead :reportTitle="'职业兴趣测评报告'" :testTime="testDate" :isIntroduce="false" :isVideo="true" :videoUrl="videoUrl" :introduceUrl="introduceUrl" ></testHead>
|
||||
<view class="s-line"></view>
|
||||
<view class="title">
|
||||
<view class="name">兴趣代码</view>
|
||||
@@ -38,7 +38,7 @@
|
||||
<view class="title">
|
||||
<view class="name">兴趣分数</view>
|
||||
</view>
|
||||
<view v-show="isShowEchart" class="chat-wrap">
|
||||
<view class="chat-wrap">
|
||||
<view class="row-item"><l-echart ref="chartRef" class="charts-box"></l-echart>
|
||||
</view>
|
||||
|
||||
@@ -241,11 +241,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import testHead from "@/packageB/pages/testReport/components/testHead.vue"
|
||||
import contrastBox from "@/packageB/pages/testReport/components/contrastBox.vue"
|
||||
import api from "@/apiB/testManage.js";
|
||||
import testHead from "@/packageCa/testReport/components/testHead.vue"
|
||||
import contrastBox from "@/packageCa/testReport/components/contrastBox.vue"
|
||||
import api from "@/apiCa/testManage.js";
|
||||
import theme from '@/uni_modules/lime-echart/static/walden.json';
|
||||
const echarts = require('../../../uni_modules/lime-echart/static/echarts.min.js');
|
||||
const echarts = require('../../uni_modules/lime-echart/static/echarts.min.js');
|
||||
// import * as echarts from '@/uni_modules/lime-echart/static/echarts.min';
|
||||
// // 注册主题
|
||||
// echarts.registerTheme('theme', theme);
|
||||
@@ -415,7 +415,6 @@
|
||||
labelName1: "",//表值1
|
||||
labelName2: "",//表值2
|
||||
params: {},//筛选参数
|
||||
isShowEchart:true,//是否显示图表
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
@@ -431,7 +430,7 @@
|
||||
if (e.routerType != undefined) {
|
||||
this.routerType = e.routerType;
|
||||
}
|
||||
if (uni.getStorageSync("userInfo").user.GradeLevel == 1) {
|
||||
if (uni.getStorageSync("CAuserInfo").user.GradeLevel == 1) {
|
||||
this.testType = "18";
|
||||
this.radarOption.radar.indicator.forEach(item=>{
|
||||
item.max = 72;
|
||||
@@ -442,13 +441,9 @@
|
||||
this.testType = "11";
|
||||
this.getTestRecord();
|
||||
}
|
||||
this.gradeLevel = uni.getStorageSync("userInfo").user.GradeLevel;
|
||||
this.gradeLevel = uni.getStorageSync("CAuserInfo").user.GradeLevel;
|
||||
},
|
||||
methods: {
|
||||
handleChildValueChange(newValue) {
|
||||
console.log("66666====");
|
||||
this.isShowEchart = newValue
|
||||
},
|
||||
showConfirmInfor(){
|
||||
uni.showModal({
|
||||
title:this.layerTitile,
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user