Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c03793daf | ||
|
|
33ecccdcb0 | ||
|
|
d429bae98a | ||
|
|
0b9f2e7333 | ||
|
|
db46766d48 | ||
|
|
27d2592d06 | ||
|
|
c81c9b79dd | ||
|
|
5f4aab8d04 | ||
|
|
15971bffd9 | ||
|
|
bf84da7783 | ||
|
|
0911760e27 | ||
|
|
66026f211c | ||
|
|
7abe158dbb | ||
|
|
aed2535ab2 | ||
|
|
5f723e5573 | ||
|
|
8cd21e7b98 | ||
|
|
e8e2e09e62 | ||
|
|
4be35ced80 | ||
|
|
0e5c7d14d0 | ||
|
|
cf268520e1 | ||
|
|
cd64ded6ae | ||
|
|
ec6ba7ee35 | ||
|
|
72339f332d | ||
|
|
b25f2dde3a | ||
|
|
38e3957da2 | ||
|
|
ed959e6e6d | ||
|
|
f0b29d9abb | ||
|
|
c94a96d14e | ||
|
|
851310a901 | ||
|
|
b740e0cd39 | ||
|
|
9e791345f2 | ||
|
|
73f5bde68f | ||
|
|
78bf7fbebc | ||
|
|
6024ea27e9 | ||
|
|
f90c8be2a9 | ||
|
|
a1a27073e4 | ||
|
|
51be3e5585 | ||
|
|
8773c65b28 | ||
|
|
0aebde7bd3 | ||
|
|
0888d9fa31 | ||
|
|
4eb730208e | ||
|
|
8143a89dab | ||
|
|
065553f53e | ||
|
|
1c3ea6aa3c | ||
|
|
c17f75c707 | ||
|
|
8d6282c3e6 | ||
|
|
403e5e9fc9 | ||
|
|
540d61b6a0 | ||
|
|
2844d99ae1 | ||
|
|
0783ecb570 | ||
|
|
ad9c448fc7 | ||
|
|
5ef8b3a9df | ||
|
|
0fcc19f3f8 | ||
|
|
e6ae57e5fd | ||
|
|
557a6f30f2 | ||
|
|
dde72be9de | ||
|
|
ddb67cfb6f | ||
|
|
59ac8ab783 | ||
|
|
0d1d080cc1 | ||
|
|
a1633978c5 | ||
|
|
0e6fde08c7 | ||
|
|
96071d0105 | ||
|
|
e34bb2a21e | ||
|
|
3dbeddcb8f | ||
|
|
f52a7c56f7 | ||
|
|
a9638fc7ec | ||
|
|
91992a2443 | ||
|
|
b666f0047d | ||
|
|
42768cc4c5 | ||
|
|
833533f780 | ||
|
|
8b6d424b2f | ||
|
|
4b16341f92 | ||
|
|
12baa93e58 | ||
|
|
a3740688ab |
@@ -1,2 +1,5 @@
|
||||
# 开发环境 — 请求走 vite proxy
|
||||
VITE_API_BASE_URL=/api
|
||||
|
||||
# 见识星球接口 — 开发环境走 vite proxy 中转解决跨域
|
||||
VITE_JIANSHI_BASE_URL=/jianshi-api
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
# 生产环境 — 同域路径代理,不需要完整域名
|
||||
VITE_API_BASE_URL=/api
|
||||
|
||||
# 见识星球接口 — 生产环境直接请求真实域名
|
||||
VITE_JIANSHI_BASE_URL=https://www.jianshixingqiu.com/proxy-api
|
||||
|
||||
@@ -16,10 +16,13 @@ inclusion: always
|
||||
## 编码规范
|
||||
|
||||
- 颜色用尽量用variables.scss里的统一颜色变量,特别是背景,按钮,文字的颜色
|
||||
- 除了Home.vue首页外,其他页面我上传了截图要写页面或组件的,需要参考图片里文字和布局结构,在保证美观前提上自由发挥
|
||||
- 全局用1rem=100px的格式并注意对某些特殊元素组件的line-height行高影响,纵布局如非必要不用flex-direction: column布局
|
||||
- 除了Home.vue首页外,其他页面我上传了截图要写页面或组件的,需要参考图片里文字和布局结构,在保证美观前提上自由发挥(如果我粘贴了图片内容里的完整样式过来,那就要参考我给的样式结合图片里的结构和样式代码保证还原度)
|
||||
- 全局用1rem=100px的格式并注意对某些特殊元素组件的line-height行高影响,纵布局能用div自动排列加上下margin的就用div排列,不要用display:flex加flex-direction: column布局,除非是像这个盒子里有个子元素需要固定在底部这样需要明确高度的情况就用flex-direction: column,否则没有高度要求内部子元素只需要正常从上到下排列纵布局只用div
|
||||
- 如果是建一个组件,这个组件看我说是用在views里哪个页面的,比如用在Profile.vue里的组件,组件名字最前面要加Profile,而且整个组件的命名不能过度简化,要容易看懂组件的用途;如果检测到某种名字开头的组件数量比如Profile开头的超过15个,就在components里新建个类似profile这样的页面名字的文件夹,把这类命名的组件都移到文件夹里并查找更新组件所有被引用地方的文件地址
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 页面结构和ts的常量变量和方法都要加中文注释
|
||||
- 页面结构和ts的常量变量和方法都要加中文注释,kiro编程工具沟通要回复中文
|
||||
- 新建 SCSS 文件如果使用了 variables.scss 中的变量(如 `$bg-white`、`$accent` 等),必须在文件顶部加 `@use '../variables' as *;`,否则通过 `@use` 方式引入 index.scss 时变量作用域不会穿透,会报 `Undefined variable` 错误
|
||||
- 因为项目用了 rem(1rem=100px)适配方案,所有 Vue 页面和组件文件的最外层盒子都要加 `font-size: 0.14rem`,避免页面样式中受浏览器默认 rem 行高影响导致文字和布局异常
|
||||
- 需要占满视口高度的元素(页面主容器、侧边栏、聊天面板等)禁止直接写 `height: 100vh`,必须使用 `height: var(--app-height, 100vh)`。原因:项目在小屏下使用 `transform: scale` 缩放,`100vh` 是缩放后的视口高度而非设计稿高度,会导致底部留白。`--app-height` 由 `src/plugins/remAdapt.ts` 动态注入,值为 `视口高度 / scale`(PC 端等于 `100vh`)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# ==================== 第一阶段:构建 ====================
|
||||
FROM node:22-alpine AS builder
|
||||
WORKDIR /build
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
/**
|
||||
* OfferPie Web 前端蓝绿部署流水线
|
||||
*
|
||||
* 工作目录说明:
|
||||
* - Jenkins 会自动为每个项目创建独立的工作空间:/var/jenkins_home/workspace/<项目名>/
|
||||
* - docker-compose.yml、Dockerfile、nginx.conf 都在项目根目录,直接执行即可
|
||||
* - nginx.conf 首次部署时 docker cp 进 nginx 容器
|
||||
*
|
||||
* 内层 Nginx 职责:
|
||||
* - 蓝绿切换(前端静态文件 serve)
|
||||
* - /api/ 代理到 Java 后端(10202)
|
||||
* - /ai-api/ 代理到 Python AI(10502),rewrite 去掉前缀
|
||||
* 架构:Jenkins 本地编译 → scp 镜像到目标机 → SSH 远程蓝绿切换
|
||||
* 目标机目录:/opt/offerpie/web/
|
||||
*/
|
||||
pipeline {
|
||||
agent any
|
||||
@@ -19,14 +12,28 @@ pipeline {
|
||||
}
|
||||
|
||||
environment {
|
||||
CONTAINER_PREFIX = 'offerpie-web' // 容器名前缀,拼接 -blue / -green / -nginx
|
||||
HEALTH_URL = 'http://localhost:80/' // 前端静态页面健康检查
|
||||
// 目标服务器配置
|
||||
DEPLOY_HOST = '8.148.237.97'
|
||||
DEPLOY_PORT = '22'
|
||||
DEPLOY_USER = 'root'
|
||||
DEPLOY_PASS = 'Mzpy520@126.com'
|
||||
|
||||
// 项目配置
|
||||
IMAGE_NAME = 'offerpie-web'
|
||||
IMAGE_TAG = 'latest'
|
||||
CONTAINER_PREFIX = 'offerpie-web'
|
||||
REMOTE_DIR = '/opt/offerpie/web'
|
||||
HEALTH_URL = 'http://localhost:80/'
|
||||
|
||||
// SSH 命令前缀
|
||||
SSH_CMD = "sshpass -p '${DEPLOY_PASS}' ssh -o StrictHostKeyChecking=no -p ${DEPLOY_PORT} ${DEPLOY_USER}@${DEPLOY_HOST}"
|
||||
SCP_CMD = "sshpass -p '${DEPLOY_PASS}' scp -o StrictHostKeyChecking=no -P ${DEPLOY_PORT}"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('开始提示') {
|
||||
stage('环境检查') {
|
||||
steps {
|
||||
echo "OfferPie Web 前端开始构建"
|
||||
sh 'sshpass -V'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,23 +41,41 @@ pipeline {
|
||||
steps {
|
||||
echo "拉取 ${params.BRANCH} 分支代码"
|
||||
git branch: "${params.BRANCH}",
|
||||
credentialsId: 'ef5fffc1-9b35-403d-9ca6-e1b73eb0e45a',
|
||||
url: 'https://codeup.aliyun.com/5f0ed3b9769820a3e817dee2/offerpie/offerpie_web.git'
|
||||
credentialsId: 'gitea-fab089c1-b55d-4b58-9fad',
|
||||
url: 'http://git.jianshixingqiu.com/offerpai/offerpai_web.git'
|
||||
}
|
||||
}
|
||||
|
||||
stage('本地编译') {
|
||||
steps {
|
||||
echo "开始构建镜像"
|
||||
sh "docker build -t ${IMAGE_NAME}:${IMAGE_TAG} ."
|
||||
echo "导出镜像"
|
||||
sh "docker save -o ${IMAGE_NAME}.tar ${IMAGE_NAME}:${IMAGE_TAG}"
|
||||
}
|
||||
}
|
||||
|
||||
stage('文件传输') {
|
||||
steps {
|
||||
echo "传输文件到目标服务器"
|
||||
sh "${SSH_CMD} 'mkdir -p ${REMOTE_DIR}'"
|
||||
sh "${SCP_CMD} ${IMAGE_NAME}.tar ${DEPLOY_USER}@${DEPLOY_HOST}:${REMOTE_DIR}/"
|
||||
sh "${SCP_CMD} proxy_nginx.conf ${DEPLOY_USER}@${DEPLOY_HOST}:${REMOTE_DIR}/proxy_nginx.conf"
|
||||
sh "${SCP_CMD} docker-compose.yml ${DEPLOY_USER}@${DEPLOY_HOST}:${REMOTE_DIR}/docker-compose.yml"
|
||||
}
|
||||
}
|
||||
|
||||
stage('加载镜像') {
|
||||
steps {
|
||||
sh "${SSH_CMD} 'docker load < ${REMOTE_DIR}/${IMAGE_NAME}.tar'"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测部署目标
|
||||
* - 检查 blue 和 green 容器的运行状态
|
||||
* - blue 在运行 → 部署 green;green 在运行 → 部署 blue
|
||||
* - 都不在或都在 → 默认部署 blue
|
||||
*/
|
||||
stage('检测部署目标') {
|
||||
steps {
|
||||
echo "检查当前容器状态"
|
||||
script {
|
||||
def blueRunning = sh(script: "docker ps -q -f name=${CONTAINER_PREFIX}-blue", returnStdout: true).trim()
|
||||
def greenRunning = sh(script: "docker ps -q -f name=${CONTAINER_PREFIX}-green", returnStdout: true).trim()
|
||||
def blueRunning = sh(script: "${SSH_CMD} 'docker ps -q -f name=${CONTAINER_PREFIX}-blue'", returnStdout: true).trim()
|
||||
def greenRunning = sh(script: "${SSH_CMD} 'docker ps -q -f name=${CONTAINER_PREFIX}-green'", returnStdout: true).trim()
|
||||
|
||||
env.DEPLOY_TARGET = ''
|
||||
|
||||
@@ -71,70 +96,42 @@ pipeline {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建新版本
|
||||
* - 先清理目标颜色的旧容器(如果残留)
|
||||
* - docker-compose build 构建新镜像(含 pnpm build)
|
||||
*/
|
||||
stage('构建新版本') {
|
||||
steps {
|
||||
script {
|
||||
def existingContainer = sh(script: "docker ps -aq -f name=${CONTAINER_PREFIX}-${env.DEPLOY_TARGET}", returnStdout: true).trim()
|
||||
if (existingContainer) {
|
||||
echo "清理已存在的容器: ${CONTAINER_PREFIX}-${env.DEPLOY_TARGET}"
|
||||
sh "docker rm -f ${CONTAINER_PREFIX}-${env.DEPLOY_TARGET}"
|
||||
}
|
||||
sh "docker-compose build ${env.DEPLOY_TARGET}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 Nginx
|
||||
* - 检查 nginx 容器是否存在
|
||||
* - 不存在则启动并复制配置文件(首次部署)
|
||||
* - 存在则确保容器运行中
|
||||
*/
|
||||
stage('检查Nginx') {
|
||||
steps {
|
||||
script {
|
||||
def nginxExists = sh(script: "docker ps -aq -f name=${CONTAINER_PREFIX}-nginx", returnStdout: true).trim()
|
||||
if (!nginxExists) {
|
||||
echo "首次部署,初始化 Nginx 容器"
|
||||
sh "docker-compose up -d nginx"
|
||||
sh "sleep 3"
|
||||
// 复制配置文件到容器内
|
||||
sh "docker cp proxy_nginx.conf ${CONTAINER_PREFIX}-nginx:/etc/nginx/nginx.conf"
|
||||
sh "docker exec ${CONTAINER_PREFIX}-nginx nginx -s reload"
|
||||
} else {
|
||||
def nginxRunning = sh(script: "docker ps -q -f name=${CONTAINER_PREFIX}-nginx", returnStdout: true).trim()
|
||||
if (!nginxRunning) {
|
||||
echo "Nginx 容器已停止,重新启动"
|
||||
sh "docker start ${CONTAINER_PREFIX}-nginx"
|
||||
sh "sleep 2"
|
||||
}
|
||||
echo "Nginx 容器已存在且运行中"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('启动新版本') {
|
||||
steps {
|
||||
script {
|
||||
sh "docker-compose up -d ${env.DEPLOY_TARGET}"
|
||||
// 等待 Nginx 容器启动
|
||||
def existingContainer = sh(script: "${SSH_CMD} 'docker ps -aq -f name=${CONTAINER_PREFIX}-${env.DEPLOY_TARGET}'", returnStdout: true).trim()
|
||||
if (existingContainer) {
|
||||
sh "${SSH_CMD} 'docker rm -f ${CONTAINER_PREFIX}-${env.DEPLOY_TARGET}'"
|
||||
}
|
||||
sh "${SSH_CMD} 'cd ${REMOTE_DIR} && docker compose up -d ${env.DEPLOY_TARGET}'"
|
||||
sh 'sleep 5'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 健康检查
|
||||
* - 进入容器检测静态页面是否正常返回
|
||||
* - 最多重试 3 次,每次间隔 5 秒
|
||||
* - 全部失败则终止部署流程
|
||||
*/
|
||||
stage('检查Nginx') {
|
||||
steps {
|
||||
script {
|
||||
def nginxExists = sh(script: "${SSH_CMD} 'docker ps -aq -f name=${CONTAINER_PREFIX}-nginx'", returnStdout: true).trim()
|
||||
if (!nginxExists) {
|
||||
echo "首次部署,初始化 Nginx 容器"
|
||||
sh "${SSH_CMD} 'cd ${REMOTE_DIR} && docker compose up -d nginx'"
|
||||
sh 'sleep 3'
|
||||
} else {
|
||||
def nginxRunning = sh(script: "${SSH_CMD} 'docker ps -q -f name=${CONTAINER_PREFIX}-nginx'", returnStdout: true).trim()
|
||||
if (!nginxRunning) {
|
||||
echo "Nginx 容器已停止,重新启动"
|
||||
sh "${SSH_CMD} 'docker start ${CONTAINER_PREFIX}-nginx'"
|
||||
sh 'sleep 2'
|
||||
}
|
||||
echo "Nginx 容器已存在且运行中"
|
||||
}
|
||||
// docker cp proxy_nginx.conf 进容器
|
||||
sh "${SSH_CMD} 'docker cp ${REMOTE_DIR}/proxy_nginx.conf ${CONTAINER_PREFIX}-nginx:/etc/nginx/nginx.conf'"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('健康检查') {
|
||||
steps {
|
||||
script {
|
||||
@@ -144,7 +141,7 @@ pipeline {
|
||||
|
||||
while (retryCount < maxRetries && !healthy) {
|
||||
try {
|
||||
sh "docker exec ${CONTAINER_PREFIX}-${env.DEPLOY_TARGET} curl -f ${HEALTH_URL}"
|
||||
sh "${SSH_CMD} 'docker exec ${CONTAINER_PREFIX}-${env.DEPLOY_TARGET} curl -f ${HEALTH_URL}'"
|
||||
healthy = true
|
||||
} catch (Exception e) {
|
||||
retryCount++
|
||||
@@ -163,38 +160,34 @@ pipeline {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换流量
|
||||
* - 修改 nginx 配置中的 proxy_pass 指向新版本
|
||||
* - nginx 不挂载宿主机文件,直接 sed -i 修改容器内配置
|
||||
* - reload 使新配置生效,实现零停机切换
|
||||
*/
|
||||
stage('切换流量') {
|
||||
steps {
|
||||
script {
|
||||
sh "docker exec ${CONTAINER_PREFIX}-nginx sed -i 's/proxy_pass http:\\/\\/\\(blue\\|green\\);/proxy_pass http:\\/\\/${env.DEPLOY_TARGET};/' /etc/nginx/nginx.conf"
|
||||
sh "docker exec ${CONTAINER_PREFIX}-nginx nginx -s reload"
|
||||
sh "${SSH_CMD} 'docker exec ${CONTAINER_PREFIX}-nginx sed -i \"s/proxy_pass http:\\/\\/\\(blue\\|green\\):80;/proxy_pass http:\\/\\/${env.DEPLOY_TARGET}:80;/\" /etc/nginx/nginx.conf'"
|
||||
sh "${SSH_CMD} 'docker exec ${CONTAINER_PREFIX}-nginx nginx -s reload'"
|
||||
echo "✅ 流量已切换到 ${env.DEPLOY_TARGET}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止并删除旧版本
|
||||
* - 不能用 docker-compose down,会删除所有服务(包括 nginx)
|
||||
* - 用 docker rm -f 只删除指定的旧颜色容器
|
||||
*/
|
||||
stage('删除旧版本') {
|
||||
steps {
|
||||
script {
|
||||
def otherExists = sh(script: "docker ps -aq -f name=${CONTAINER_PREFIX}-${env.OTHER_TARGET}", returnStdout: true).trim()
|
||||
def otherExists = sh(script: "${SSH_CMD} 'docker ps -aq -f name=${CONTAINER_PREFIX}-${env.OTHER_TARGET}'", returnStdout: true).trim()
|
||||
if (otherExists) {
|
||||
sh "docker rm -f ${CONTAINER_PREFIX}-${env.OTHER_TARGET}"
|
||||
sh "${SSH_CMD} 'docker rm -f ${CONTAINER_PREFIX}-${env.OTHER_TARGET}'"
|
||||
echo "旧版本 ${env.OTHER_TARGET} 已删除"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('清理') {
|
||||
steps {
|
||||
sh "${SSH_CMD} 'rm -f ${REMOTE_DIR}/${IMAGE_NAME}.tar'"
|
||||
sh "rm -f ${IMAGE_NAME}.tar"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
@@ -203,6 +196,7 @@ pipeline {
|
||||
}
|
||||
failure {
|
||||
echo '❌ 部署失败,请检查日志'
|
||||
sh "rm -f ${IMAGE_NAME}.tar || true"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* OfferPie Web 前端蓝绿部署流水线(测试环境)
|
||||
*
|
||||
* 架构:Jenkins 本地编译 → scp 镜像到目标机 → SSH 远程蓝绿切换
|
||||
* 目标机目录:/opt/offerpie/web/
|
||||
*
|
||||
* 与生产差异:
|
||||
* - 部署目标为测试服务器
|
||||
* - 默认分支 test
|
||||
* - 镜像 tag = test(与生产 latest 隔离,避免同一 Jenkins 并发构建串包)
|
||||
* - tar 文件名带 tag(双保险)
|
||||
*
|
||||
* 说明:前端走相对路径 /api、/ai-api,proxy_nginx.conf 代理到本机服务,
|
||||
* 镜像与环境无关,复用生产 Dockerfile / nginx.conf / proxy_nginx.conf。
|
||||
*/
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
parameters {
|
||||
choice(name: 'BRANCH', choices: ['test', 'dev', 'pre', 'master'], description: '选择要部署的分支')
|
||||
}
|
||||
|
||||
environment {
|
||||
// 目标服务器配置(测试)
|
||||
DEPLOY_HOST = '8.163.131.234'
|
||||
DEPLOY_PORT = '22'
|
||||
DEPLOY_USER = 'root'
|
||||
DEPLOY_PASS = 'Mzpy520@126.com'
|
||||
|
||||
// 项目配置
|
||||
IMAGE_NAME = 'offerpie-web'
|
||||
IMAGE_TAG = 'test'
|
||||
IMAGE_TAR = 'offerpie-web-test.tar'
|
||||
CONTAINER_PREFIX = 'offerpie-web'
|
||||
REMOTE_DIR = '/opt/offerpie/web'
|
||||
HEALTH_URL = 'http://localhost:80/'
|
||||
|
||||
// SSH 命令前缀
|
||||
SSH_CMD = "sshpass -p '${DEPLOY_PASS}' ssh -o StrictHostKeyChecking=no -p ${DEPLOY_PORT} ${DEPLOY_USER}@${DEPLOY_HOST}"
|
||||
SCP_CMD = "sshpass -p '${DEPLOY_PASS}' scp -o StrictHostKeyChecking=no -P ${DEPLOY_PORT}"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('环境检查') {
|
||||
steps {
|
||||
sh 'sshpass -V'
|
||||
}
|
||||
}
|
||||
|
||||
stage('拉取代码') {
|
||||
steps {
|
||||
echo "拉取 ${params.BRANCH} 分支代码"
|
||||
git branch: "${params.BRANCH}",
|
||||
credentialsId: 'gitea-fab089c1-b55d-4b58-9fad',
|
||||
url: 'http://git.jianshixingqiu.com/offerpai/offerpai_web.git'
|
||||
}
|
||||
}
|
||||
|
||||
stage('本地编译') {
|
||||
steps {
|
||||
echo "开始构建镜像"
|
||||
sh "docker build -t ${IMAGE_NAME}:${IMAGE_TAG} ."
|
||||
echo "导出镜像"
|
||||
sh "docker save -o ${IMAGE_TAR} ${IMAGE_NAME}:${IMAGE_TAG}"
|
||||
}
|
||||
}
|
||||
|
||||
stage('文件传输') {
|
||||
steps {
|
||||
echo "传输文件到目标服务器"
|
||||
sh "${SSH_CMD} 'mkdir -p ${REMOTE_DIR}'"
|
||||
sh "${SCP_CMD} ${IMAGE_TAR} ${DEPLOY_USER}@${DEPLOY_HOST}:${REMOTE_DIR}/"
|
||||
sh "${SCP_CMD} proxy_nginx.conf ${DEPLOY_USER}@${DEPLOY_HOST}:${REMOTE_DIR}/proxy_nginx.conf"
|
||||
sh "${SCP_CMD} docker-compose.test.yml ${DEPLOY_USER}@${DEPLOY_HOST}:${REMOTE_DIR}/docker-compose.yml"
|
||||
}
|
||||
}
|
||||
|
||||
stage('加载镜像') {
|
||||
steps {
|
||||
sh "${SSH_CMD} 'docker load < ${REMOTE_DIR}/${IMAGE_TAR}'"
|
||||
}
|
||||
}
|
||||
|
||||
stage('检测部署目标') {
|
||||
steps {
|
||||
script {
|
||||
def blueRunning = sh(script: "${SSH_CMD} 'docker ps -q -f name=${CONTAINER_PREFIX}-blue'", returnStdout: true).trim()
|
||||
def greenRunning = sh(script: "${SSH_CMD} 'docker ps -q -f name=${CONTAINER_PREFIX}-green'", returnStdout: true).trim()
|
||||
|
||||
env.DEPLOY_TARGET = ''
|
||||
|
||||
if (blueRunning && !greenRunning) {
|
||||
env.DEPLOY_TARGET = 'green'
|
||||
}
|
||||
if (greenRunning && !blueRunning) {
|
||||
env.DEPLOY_TARGET = 'blue'
|
||||
}
|
||||
if (!env.DEPLOY_TARGET) {
|
||||
echo "当前环境未部署服务或状态异常,默认部署 blue"
|
||||
env.DEPLOY_TARGET = 'blue'
|
||||
}
|
||||
|
||||
env.OTHER_TARGET = (env.DEPLOY_TARGET == 'blue') ? 'green' : 'blue'
|
||||
echo "当前激活: ${env.OTHER_TARGET},即将部署: ${env.DEPLOY_TARGET}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('启动新版本') {
|
||||
steps {
|
||||
script {
|
||||
def existingContainer = sh(script: "${SSH_CMD} 'docker ps -aq -f name=${CONTAINER_PREFIX}-${env.DEPLOY_TARGET}'", returnStdout: true).trim()
|
||||
if (existingContainer) {
|
||||
sh "${SSH_CMD} 'docker rm -f ${CONTAINER_PREFIX}-${env.DEPLOY_TARGET}'"
|
||||
}
|
||||
sh "${SSH_CMD} 'cd ${REMOTE_DIR} && docker compose up -d ${env.DEPLOY_TARGET}'"
|
||||
sh 'sleep 5'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('检查Nginx') {
|
||||
steps {
|
||||
script {
|
||||
def nginxExists = sh(script: "${SSH_CMD} 'docker ps -aq -f name=${CONTAINER_PREFIX}-nginx'", returnStdout: true).trim()
|
||||
if (!nginxExists) {
|
||||
echo "首次部署,初始化 Nginx 容器"
|
||||
sh "${SSH_CMD} 'cd ${REMOTE_DIR} && docker compose up -d nginx'"
|
||||
sh 'sleep 3'
|
||||
} else {
|
||||
def nginxRunning = sh(script: "${SSH_CMD} 'docker ps -q -f name=${CONTAINER_PREFIX}-nginx'", returnStdout: true).trim()
|
||||
if (!nginxRunning) {
|
||||
echo "Nginx 容器已停止,重新启动"
|
||||
sh "${SSH_CMD} 'docker start ${CONTAINER_PREFIX}-nginx'"
|
||||
sh 'sleep 2'
|
||||
}
|
||||
echo "Nginx 容器已存在且运行中"
|
||||
}
|
||||
// docker cp proxy_nginx.conf 进容器
|
||||
sh "${SSH_CMD} 'docker cp ${REMOTE_DIR}/proxy_nginx.conf ${CONTAINER_PREFIX}-nginx:/etc/nginx/nginx.conf'"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('健康检查') {
|
||||
steps {
|
||||
script {
|
||||
def maxRetries = 3
|
||||
def retryCount = 0
|
||||
def healthy = false
|
||||
|
||||
while (retryCount < maxRetries && !healthy) {
|
||||
try {
|
||||
sh "${SSH_CMD} 'docker exec ${CONTAINER_PREFIX}-${env.DEPLOY_TARGET} curl -f ${HEALTH_URL}'"
|
||||
healthy = true
|
||||
} catch (Exception e) {
|
||||
retryCount++
|
||||
if (retryCount < maxRetries) {
|
||||
echo "健康检查失败,5秒后重试 (${retryCount}/${maxRetries})"
|
||||
sleep 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!healthy) {
|
||||
error "健康检查失败,部署中止"
|
||||
}
|
||||
echo "✅ ${CONTAINER_PREFIX}-${env.DEPLOY_TARGET} 健康检查通过"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('切换流量') {
|
||||
steps {
|
||||
script {
|
||||
sh "${SSH_CMD} 'docker exec ${CONTAINER_PREFIX}-nginx sed -i \"s/proxy_pass http:\\/\\/\\(blue\\|green\\):80;/proxy_pass http:\\/\\/${env.DEPLOY_TARGET}:80;/\" /etc/nginx/nginx.conf'"
|
||||
sh "${SSH_CMD} 'docker exec ${CONTAINER_PREFIX}-nginx nginx -s reload'"
|
||||
echo "✅ 流量已切换到 ${env.DEPLOY_TARGET}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('删除旧版本') {
|
||||
steps {
|
||||
script {
|
||||
def otherExists = sh(script: "${SSH_CMD} 'docker ps -aq -f name=${CONTAINER_PREFIX}-${env.OTHER_TARGET}'", returnStdout: true).trim()
|
||||
if (otherExists) {
|
||||
sh "${SSH_CMD} 'docker rm -f ${CONTAINER_PREFIX}-${env.OTHER_TARGET}'"
|
||||
echo "旧版本 ${env.OTHER_TARGET} 已删除"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('清理') {
|
||||
steps {
|
||||
sh "${SSH_CMD} 'rm -f ${REMOTE_DIR}/${IMAGE_TAR}'"
|
||||
sh "rm -f ${IMAGE_TAR}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
success {
|
||||
echo "✅ 蓝绿部署成功!当前运行: ${env.DEPLOY_TARGET}"
|
||||
}
|
||||
failure {
|
||||
echo '❌ 部署失败,请检查日志'
|
||||
sh "rm -f ${IMAGE_TAR} || true"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,16 +12,20 @@ export {}
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AgentApplyProgress: typeof import('./src/components/AgentApplyProgress.vue')['default']
|
||||
AgentApplyProgressPanel: typeof import('./src/components/AgentApplyProgressPanel.vue')['default']
|
||||
AgentBrowserInstallGuide: typeof import('./src/components/AgentBrowserInstallGuide.vue')['default']
|
||||
AgentChatJobList: typeof import('./src/components/AgentChatJobList.vue')['default']
|
||||
AgentJobPreviewPanel: typeof import('./src/components/AgentJobPreviewPanel.vue')['default']
|
||||
AgentMatchJobAdd: typeof import('./src/components/AgentMatchJobAdd.vue')['default']
|
||||
AgentPendingJobListPanel: typeof import('./src/components/AgentPendingJobListPanel.vue')['default']
|
||||
AgentSettingPanel: typeof import('./src/components/AgentSettingPanel.vue')['default']
|
||||
AgentSettingsPanel: typeof import('./src/components/AgentSettingsPanel.vue')['default']
|
||||
AgentSetupWizard: typeof import('./src/components/AgentSetupWizard.vue')['default']
|
||||
AgentTaskListDropdown: typeof import('./src/components/AgentTaskListDropdown.vue')['default']
|
||||
AgreementPreviewDialog: typeof import('./src/components/tools/AgreementPreviewDialog.vue')['default']
|
||||
AiChat: typeof import('./src/components/AiChat.vue')['default']
|
||||
AiThinkingIndicator: typeof import('./src/components/tools/AiThinkingIndicator.vue')['default']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCarousel: typeof import('element-plus/es')['ElCarousel']
|
||||
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
|
||||
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
@@ -31,10 +35,14 @@ declare module 'vue' {
|
||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
|
||||
ElSkeletonItem: typeof import('element-plus/es')['ElSkeletonItem']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||
FullscreenLoading: typeof import('./src/components/FullscreenLoading.vue')['default']
|
||||
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
|
||||
IndustrySelector: typeof import('./src/components/tools/IndustrySelector.vue')['default']
|
||||
JobApplyMethodDialog: typeof import('./src/components/JobApplyMethodDialog.vue')['default']
|
||||
JobCategorySelector: typeof import('./src/components/tools/JobCategorySelector.vue')['default']
|
||||
JobDislikeDialog: typeof import('./src/components/JobDislikeDialog.vue')['default']
|
||||
JobFeedbackDialog: typeof import('./src/components/JobFeedbackDialog.vue')['default']
|
||||
@@ -44,21 +52,28 @@ declare module 'vue' {
|
||||
JobResumeCustomEditPanel: typeof import('./src/components/JobResumeCustomEditPanel.vue')['default']
|
||||
JobResumeTemplate: typeof import('./src/components/JobResumeTemplate.vue')['default']
|
||||
LoginDialog: typeof import('./src/components/LoginDialog.vue')['default']
|
||||
MemberAccessDialog: typeof import('./src/components/MemberAccessDialog.vue')['default']
|
||||
MemberDialog: typeof import('./src/components/MemberDialog.vue')['default']
|
||||
MentorAsidePanel: typeof import('./src/components/MentorAsidePanel.vue')['default']
|
||||
MentorQrCodeDialog: typeof import('./src/components/MentorQrCodeDialog.vue')['default']
|
||||
ProfileEditDrawer: typeof import('./src/components/ProfileEditDrawer.vue')['default']
|
||||
ProfilePageContent: typeof import('./src/components/ProfilePageContent.vue')['default']
|
||||
ProfileWelcomeDialog: typeof import('./src/components/ProfileWelcomeDialog.vue')['default']
|
||||
RegionSelector: typeof import('./src/components/tools/RegionSelector.vue')['default']
|
||||
ResumeAnalysisReportDrawer: typeof import('./src/components/ResumeAnalysisReportDrawer.vue')['default']
|
||||
ResumeEditNameDialog: typeof import('./src/components/ResumeEditNameDialog.vue')['default']
|
||||
ResumeExpInlineEdit: typeof import('./src/components/ResumeExpInlineEdit.vue')['default']
|
||||
ResumeExportDialog: typeof import('./src/components/ResumeExportDialog.vue')['default']
|
||||
ResumeIssueFixAllDrawer: typeof import('./src/components/ResumeIssueFixAllDrawer.vue')['default']
|
||||
ResumeIssueFixDrawer: typeof import('./src/components/ResumeIssueFixDrawer.vue')['default']
|
||||
ResumeUploadDialog: typeof import('./src/components/ResumeUploadDialog.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
SettingsDeleteAccountDialog: typeof import('./src/components/SettingsDeleteAccountDialog.vue')['default']
|
||||
SettingsDialog: typeof import('./src/components/SettingsDialog.vue')['default']
|
||||
SettingsInviteDialog: typeof import('./src/components/SettingsInviteDialog.vue')['default']
|
||||
SideNav: typeof import('./src/components/SideNav.vue')['default']
|
||||
StepProgressOverlay: typeof import('./src/components/StepProgressOverlay.vue')['default']
|
||||
}
|
||||
export interface GlobalDirectives {
|
||||
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
services:
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: offerpie-web-nginx
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "10302:80"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--spider", "-q", "http://localhost/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 256M
|
||||
cpus: '0.5'
|
||||
|
||||
blue:
|
||||
image: offerpie-web:test
|
||||
container_name: offerpie-web-blue
|
||||
restart: unless-stopped
|
||||
expose:
|
||||
- "80"
|
||||
environment:
|
||||
- APP_VERSION=blue
|
||||
- TZ=Asia/Shanghai
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:80/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 128M
|
||||
cpus: '0.25'
|
||||
|
||||
green:
|
||||
image: offerpie-web:test
|
||||
container_name: offerpie-web-green
|
||||
restart: unless-stopped
|
||||
expose:
|
||||
- "80"
|
||||
environment:
|
||||
- APP_VERSION=green
|
||||
- TZ=Asia/Shanghai
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:80/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 128M
|
||||
cpus: '0.25'
|
||||
@@ -5,9 +5,6 @@ services:
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "10302:80"
|
||||
depends_on:
|
||||
- blue
|
||||
- green
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--spider", "-q", "http://localhost/health"]
|
||||
interval: 30s
|
||||
@@ -16,11 +13,11 @@ services:
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 128M
|
||||
cpus: '0.25'
|
||||
memory: 256M
|
||||
cpus: '0.5'
|
||||
|
||||
blue:
|
||||
build: .
|
||||
image: offerpie-web:latest
|
||||
container_name: offerpie-web-blue
|
||||
restart: unless-stopped
|
||||
expose:
|
||||
@@ -41,7 +38,7 @@ services:
|
||||
cpus: '0.25'
|
||||
|
||||
green:
|
||||
build: .
|
||||
image: offerpie-web:latest
|
||||
container_name: offerpie-web-green
|
||||
restart: unless-stopped
|
||||
expose:
|
||||
|
||||
@@ -2,11 +2,21 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<link rel="icon" type="image/svg+xml" href="/logo.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Offer派 - 大学生AI求职平台 | 智能岗位匹配·一键自动网申·AI简历优化</title>
|
||||
<meta name="description" content="Offer派是专为大学生打造的AI求职平台,提供智能岗位匹配、一键自动网申、岗位定制简历、内推人脉直通等功能,让校招求职效率提升80%。" />
|
||||
<meta name="keywords" content="大学生求职,校招,AI求职,智能匹配,自动网申,简历优化,内推,Offer派" />
|
||||
<!-- 友盟统计 -->
|
||||
<script>
|
||||
var _czc = _czc || [];
|
||||
(function () {
|
||||
var um = document.createElement("script");
|
||||
um.src = "https://v1.cnzz.com/z.js?id=1281490571&async=1";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(um, s);
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -13,18 +13,18 @@
|
||||
"axios": "^1.13.6",
|
||||
"element-plus": "^2.13.3",
|
||||
"html2pdf.js": "^0.14.0",
|
||||
"markdown-it": "^14.2.0",
|
||||
"sass": "^1.97.3",
|
||||
"vue": "^3.5.25",
|
||||
"vue-router": "^4.6.4",
|
||||
"vuex": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@prerenderer/renderer-puppeteer": "^1.2.4",
|
||||
"@prerenderer/rollup-plugin": "^0.3.12",
|
||||
"@types/chrome": "^0.2.2",
|
||||
"@types/markdown-it": "^14.1.2",
|
||||
"@types/node": "^24.10.1",
|
||||
"@vitejs/plugin-vue": "^6.0.2",
|
||||
"@vue/tsconfig": "^0.8.1",
|
||||
"puppeteer": "^24.37.5",
|
||||
"typescript": "~5.9.3",
|
||||
"unplugin-auto-import": "^21.0.0",
|
||||
"unplugin-vue-components": "^31.0.0",
|
||||
|
||||
@@ -2,5 +2,4 @@ allowBuilds:
|
||||
'@parcel/watcher': true
|
||||
core-js: true
|
||||
esbuild: true
|
||||
puppeteer: true
|
||||
vue-demi: true
|
||||
|
||||
@@ -23,22 +23,13 @@ http {
|
||||
# 请求体大小限制
|
||||
client_max_body_size 20m;
|
||||
|
||||
# 蓝绿 upstream
|
||||
upstream blue {
|
||||
server offerpie-web-blue:80;
|
||||
}
|
||||
|
||||
upstream green {
|
||||
server offerpie-web-green:80;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
# Java 后端 API 代理
|
||||
location /api/ {
|
||||
proxy_pass http://8.138.5.14:10202/api/;
|
||||
proxy_pass http://172.17.0.1:10202/api/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
@@ -54,7 +45,7 @@ http {
|
||||
|
||||
# Python AI 代理(去掉 /ai-api 前缀)
|
||||
location /ai-api/ {
|
||||
proxy_pass http://8.138.5.14:10502/;
|
||||
proxy_pass http://172.17.0.1:10502/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
@@ -74,7 +65,7 @@ http {
|
||||
|
||||
# 前端静态文件(蓝绿切换,默认 blue,部署时 sed 切换)
|
||||
location / {
|
||||
proxy_pass http://blue;
|
||||
proxy_pass http://blue:80;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
|
After Width: | Height: | Size: 7.4 KiB |
@@ -1,13 +1,11 @@
|
||||
<template>
|
||||
<el-config-provider :locale="zhCn">
|
||||
<RouterView />
|
||||
<LoginDialog />
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { RouterView } from 'vue-router'
|
||||
import LoginDialog from '@/components/LoginDialog.vue'
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||
</script>
|
||||
|
||||
|
||||
@@ -21,7 +21,9 @@ export interface AgentConfig {
|
||||
weeklyTarget?: number
|
||||
/** 投递时自动针对岗位优化简历 0=关闭 1=开启 */
|
||||
autoOptimizeResume?: number
|
||||
/** 是否愿意接受部门调剂 */
|
||||
/** 自动匹配分析 0=关闭 1=开启 */
|
||||
autoMatchAnalysis?: number
|
||||
/** 是否开启深度人岗匹配分析,可选值:是/否(null或空字符串视为关闭) */
|
||||
acceptDeptTransfer?: string
|
||||
/** 是否接受地点调剂 */
|
||||
acceptLocationTransfer?: string
|
||||
@@ -69,8 +71,8 @@ export interface AgentJobMatchDetail {
|
||||
|
||||
/** 推荐岗位项 */
|
||||
export interface AgentRecommendJob {
|
||||
/** 岗位 ID */
|
||||
id: number
|
||||
/** 岗位 ID(字符串,避免大整数精度丢失) */
|
||||
id: string | number
|
||||
/** 岗位名称 */
|
||||
title: string
|
||||
/** 薪资描述 */
|
||||
@@ -101,6 +103,10 @@ export interface AgentRecommendJob {
|
||||
matchScore: number
|
||||
/** 匹配度详情 */
|
||||
matchDetail: AgentJobMatchDetail
|
||||
/** 学历要求 0=不限 1=大专 2=本科 3=硕士 4=博士 */
|
||||
education?: number
|
||||
/** 招聘分类 0=社招 1=校招 2=实习 3=其他 */
|
||||
recruitCategory?: number
|
||||
}
|
||||
|
||||
/** 求职助手岗位推荐返回数据 */
|
||||
@@ -148,9 +154,9 @@ export function applyJob(params: JobApplyParams) {
|
||||
/**
|
||||
* 取消投递 / 从待投递移除
|
||||
* DELETE /job/apply?jobId=xxx
|
||||
* @param jobId 岗位 ID
|
||||
* @param jobId 岗位 ID(字符串,避免大整数精度丢失)
|
||||
*/
|
||||
export function cancelApplyJob(jobId: number) {
|
||||
export function cancelApplyJob(jobId: string | number) {
|
||||
return request.delete<any, ApiResult>('/job/apply', {
|
||||
params: { jobId },
|
||||
})
|
||||
@@ -300,3 +306,24 @@ export function optimizeAgentResume(params: OptimizeResumeParams) {
|
||||
},
|
||||
}).then(res => res.data)
|
||||
}
|
||||
|
||||
// ==================== 岗位匹配度评分(Python 后端) ====================
|
||||
|
||||
/** 匹配度评分请求参数 */
|
||||
export interface MatchScoreParams {
|
||||
/** 定制简历 ID(字符串,避免大整数精度丢失) */
|
||||
customizeResumeId?: string
|
||||
/** 普通简历 ID(关闭优化时使用) */
|
||||
resumeId?: string
|
||||
/** 岗位 ID(字符串,避免大整数精度丢失) */
|
||||
jobId: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 岗位匹配度评分
|
||||
* POST /job-agent/match-score
|
||||
* @returns data 为匹配度分数(0-100)
|
||||
*/
|
||||
export function fetchMatchScore(params: MatchScoreParams) {
|
||||
return aiService.post<any, { data: AiResult<number> }>('/job-agent/match-score', params).then(res => res.data)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import request from '@/utils/request'
|
||||
import store from '@/stores'
|
||||
|
||||
/** 通用响应结构 */
|
||||
export interface ApiResult<T = any> {
|
||||
@@ -31,13 +32,26 @@ export function sendSmsCode(mobileNumber: string) {
|
||||
* POST /public/login/smsLogin
|
||||
* Body: { mobileNumber, code, inviteCode? }
|
||||
* 登录成功后后端会 Set-Cookie: Token=xxx
|
||||
*
|
||||
* inviteCode 优先使用传入参数,其次从全局 store 中读取(URL 邀请码)
|
||||
* 登录成功后自动清空全局邀请码,避免重复发送
|
||||
*/
|
||||
export function smsLogin(mobileNumber: string, code: string, inviteCode?: string) {
|
||||
return request.post<any, ApiResult<LoginData>>('/public/login/smsLogin', {
|
||||
export async function smsLogin(mobileNumber: string, code: string, inviteCode?: string) {
|
||||
// 优先使用显式传入的邀请码,否则从全局 store 取
|
||||
const finalInviteCode = inviteCode || store.state.inviteCode || ''
|
||||
|
||||
const res = await request.post<any, ApiResult<LoginData>>('/public/login/smsLogin', {
|
||||
mobileNumber,
|
||||
code,
|
||||
...(inviteCode ? { inviteCode } : {}),
|
||||
...(finalInviteCode ? { inviteCode: finalInviteCode } : {}),
|
||||
})
|
||||
|
||||
// 登录成功后清空全局邀请码
|
||||
if (res.code === '0' && store.state.inviteCode) {
|
||||
store.commit('SET_INVITE_CODE', '')
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,8 +21,8 @@ export interface IndustryItem {
|
||||
* GET /public/industries/tree
|
||||
* 返回一级二级嵌套的行业分类
|
||||
*/
|
||||
export function fetchIndustryTree() {
|
||||
return request.get<any, ApiResult<IndustryItem[]>>('/public/industries/tree')
|
||||
export function fetchIndustryTree(params?: { includeEmpty?: boolean }) {
|
||||
return request.get<any, ApiResult<IndustryItem[]>>('/public/industries/tree', { params })
|
||||
}
|
||||
|
||||
// ==================== 岗位分类相关 ====================
|
||||
@@ -55,8 +55,8 @@ export interface JobCategoryItem {
|
||||
* GET /public/job-categories/tree
|
||||
* 返回一级二级三级嵌套的岗位分类
|
||||
*/
|
||||
export function fetchJobCategoryTree() {
|
||||
return request.get<any, ApiResult<JobCategoryItem[]>>('/public/job-categories/tree')
|
||||
export function fetchJobCategoryTree(params?: { includeEmpty?: boolean }) {
|
||||
return request.get<any, ApiResult<JobCategoryItem[]>>('/public/job-categories/tree', { params })
|
||||
}
|
||||
|
||||
// ==================== 地区分类相关 ====================
|
||||
@@ -118,3 +118,30 @@ export function uploadFileToOss(file: File, pathEnum: OssPathEnum = 'ResumeFile'
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
})
|
||||
}
|
||||
|
||||
// ==================== 协议查询相关 ====================
|
||||
|
||||
/** 协议数据结构 */
|
||||
export interface AgreementDto {
|
||||
/** 协议表ID */
|
||||
id?: number
|
||||
/** 协议码,唯一标识一类协议 */
|
||||
agreementCode?: string
|
||||
/** 修改版本 */
|
||||
version?: number
|
||||
/** 协议名称 */
|
||||
agreementName?: string
|
||||
/** 协议内容(富文本/Markdown) */
|
||||
content?: string
|
||||
/** 状态 1=启用 0=禁用 */
|
||||
status?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据协议码查询协议内容
|
||||
* GET /public/agreement?code=xxx
|
||||
* @param code 协议码
|
||||
*/
|
||||
export function fetchAgreement(code: string) {
|
||||
return request.get<any, ApiResult<AgreementDto>>('/public/agreement', { params: { code } })
|
||||
}
|
||||
|
||||
@@ -3,6 +3,16 @@ import aiService from '@/utils/aiRequest'
|
||||
import type { ApiResult } from '@/api/auth'
|
||||
import type { AiResult } from '@/utils/aiRequest'
|
||||
|
||||
// ==================== 岗位总数 ====================
|
||||
|
||||
/**
|
||||
* 获取全网实时岗位总数
|
||||
* GET /job/count
|
||||
*/
|
||||
export function fetchJobCount() {
|
||||
return request.get<any, ApiResult<number>>('/job/count')
|
||||
}
|
||||
|
||||
// ==================== 匹配详情 ====================
|
||||
|
||||
/** 匹配度详情 */
|
||||
@@ -29,6 +39,8 @@ export interface JobListItem {
|
||||
companyShortName: string
|
||||
/** 公司类型(如"上市企业") */
|
||||
companyType: string
|
||||
/** 公司标签列表(如 ["新能源汽车", "乘用车制造", "10000人以上"]) */
|
||||
companyTags: string[]
|
||||
/** 地区名称 */
|
||||
regionName: string
|
||||
/** 岗位分类名称 */
|
||||
@@ -45,6 +57,10 @@ export interface JobListItem {
|
||||
matchScore: number
|
||||
/** 匹配度详情 */
|
||||
matchDetail: MatchDetail
|
||||
/** 招聘分类:0=社招 1=校招 2=实习 */
|
||||
recruitCategory?: number
|
||||
/** 学历要求 0=不限 1=大专 2=本科 3=硕士 4=博士 */
|
||||
education?: number
|
||||
}
|
||||
|
||||
// ==================== 分页结构 ====================
|
||||
@@ -75,14 +91,18 @@ export interface JobListParams {
|
||||
categoryIds?: number[]
|
||||
/** 行业 ID 列表 */
|
||||
industryIds?: number[]
|
||||
/** 工作类型:0=全职 1=兼职 */
|
||||
employmentType?: number
|
||||
/** 指定岗位 ID 列表(用于收藏列表) */
|
||||
jobIds?: number[]
|
||||
/** 岗位状态过滤(0=有效 1=已下架 2=已过期,可多选,null或空=查所有) */
|
||||
statusFilter?: number[]
|
||||
/** 搜索关键词 */
|
||||
keyword?: string
|
||||
/** 招聘分类 0=校招 1=实习 2=社招 3=其他 */
|
||||
recruitCategory?: number
|
||||
/** 排除岗位ID列表(用于推荐时排除已推荐过的) */
|
||||
excludeJobIds?: number[]
|
||||
/** 公司类型列表(上市企业、独角兽、国企等,可多选) */
|
||||
companyTypes?: string[]
|
||||
}
|
||||
|
||||
// ==================== 求职意向 ====================
|
||||
@@ -95,8 +115,14 @@ export interface JobIntention {
|
||||
regionCodes?: string[]
|
||||
/** 期望行业 ID 列表 */
|
||||
industryIds?: number[]
|
||||
/** 就业类型:0=全职,1=实习 */
|
||||
employmentType?: number
|
||||
/** 就业类型:0=校招,1=实习,2=社招 */
|
||||
employmentType?: number | null
|
||||
/** 招聘分类:0=社招,1=校招,2=实习,3=其他 */
|
||||
recruitCategory?: number | null
|
||||
/** AI 推荐的岗位分类 ID 列表 */
|
||||
aiCategoryIds?: string[]
|
||||
/** AI 推荐的行业 ID 列表 */
|
||||
aiIndustryIds?: string[]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,6 +232,8 @@ export interface ApplyListParams {
|
||||
pageSize?: number
|
||||
/** 投递状态筛选(0=已投递 1=面试中 2=有Offer 3=未通过 4=已结束) */
|
||||
status?: number | null
|
||||
/** 搜索关键词 */
|
||||
keyword?: string
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,6 +245,7 @@ export function fetchApplyList(params: ApplyListParams = {}) {
|
||||
pageNum: params.pageNum ?? 1,
|
||||
pageSize: params.pageSize ?? 10,
|
||||
...(params.status !== null && params.status !== undefined ? { status: params.status } : {}),
|
||||
...(params.keyword ? { keyword: params.keyword } : {}),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -295,6 +324,8 @@ export interface JobDetailData {
|
||||
salary: string
|
||||
/** 工作类型 0=全职 1=兼职 */
|
||||
employmentType: number
|
||||
/** 招聘分类 0=社招 1=校招 2=实习 3=其他 */
|
||||
recruitCategory: number
|
||||
/** 学历要求 0=不限 1=大专 2=本科 3=硕士 4=博士 */
|
||||
education: number
|
||||
/** 最低工作年限 */
|
||||
@@ -415,6 +446,16 @@ export interface SkillGapResume {
|
||||
targetPosition: string
|
||||
}
|
||||
|
||||
/** 技能差距分析 — 差距项 */
|
||||
export interface SkillGapItem {
|
||||
/** 关键词 */
|
||||
keyword: string
|
||||
/** 差距标题 */
|
||||
title: string
|
||||
/** 差距描述 */
|
||||
description: string
|
||||
}
|
||||
|
||||
/** 技能差距分析返回数据 */
|
||||
export interface SkillGapData {
|
||||
/** 匹配度分数 */
|
||||
@@ -423,8 +464,10 @@ export interface SkillGapData {
|
||||
job: SkillGapJob
|
||||
/** 简历信息 */
|
||||
resume: SkillGapResume
|
||||
/** 缺少的技能列表 */
|
||||
missingSkills: string[]
|
||||
/** 缺少的技能列表(兼容旧版) */
|
||||
missingSkills?: string[]
|
||||
/** 差距分析列表(新版) */
|
||||
gaps?: SkillGapItem[]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -451,6 +494,9 @@ export function fetchSkillGap(jobId: string) {
|
||||
/** 定制简历接口返回的简历数据 */
|
||||
export interface CustomizeResumeData {
|
||||
/** 简历基本信息 */
|
||||
id?: string
|
||||
resumeId?: string
|
||||
resumeName?: string
|
||||
resume: {
|
||||
avatarUrl?: string
|
||||
name?: string
|
||||
|
||||
@@ -36,6 +36,8 @@ export interface MemberProduct {
|
||||
export interface MemberStatus {
|
||||
/** 是否是会员 */
|
||||
isMember: boolean
|
||||
/** 会员类型 1=正式 2=试用 */
|
||||
memberType?: number
|
||||
/** 到期时间(毫秒时间戳) */
|
||||
expireTime?: number
|
||||
/** 首次开通时间(毫秒时间戳) */
|
||||
@@ -115,3 +117,27 @@ export function fetchOrderDetail(orderId: string) {
|
||||
params: { orderId },
|
||||
})
|
||||
}
|
||||
|
||||
// ==================== 邀请统计相关 ====================
|
||||
|
||||
/** 用户邀请统计DTO */
|
||||
export interface InviteStatsDto {
|
||||
/** 累计邀请人数 */
|
||||
inviteCount?: number
|
||||
/** 当前周期已邀请人数 */
|
||||
milestoneProgress?: number
|
||||
/** 累计获得会员天数 */
|
||||
rewardDays?: number
|
||||
/** 里程碑目标人数 */
|
||||
milestoneTarget?: number
|
||||
/** 里程碑奖励天数 */
|
||||
milestoneDays?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户邀请统计
|
||||
* GET /user/manage/inviteStats
|
||||
*/
|
||||
export function fetchInviteStats() {
|
||||
return request.get<any, ApiResult<InviteStatsDto>>('/user/manage/inviteStats')
|
||||
}
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 分页查询导师列表请求参数
|
||||
*/
|
||||
export interface MentorListParams {
|
||||
/** 页码,>= 1 */
|
||||
page: number
|
||||
/** 每页条数,1~100 */
|
||||
pageSize: number
|
||||
/** 搜索关键词,可选 */
|
||||
keyword?: string
|
||||
/** 行业ids,可选 */
|
||||
industryIds?: number[]
|
||||
/** 导师ids,可选 */
|
||||
mentorIds?: number[]
|
||||
/** 身份类型:0企业在职 1生涯规划师 2心理咨询师 3教职工 4在校学生,可选 */
|
||||
identityType?: number | null
|
||||
/** 标签ids,可选 */
|
||||
labelIds?: number[]
|
||||
/** 约聊方式:0语音电话 1线下约见,可选 */
|
||||
chatType?: number
|
||||
/** 价格最大值,可选 */
|
||||
maxChatPrice?: number
|
||||
/** 价格最小值,可选 */
|
||||
minChatPrice?: number
|
||||
/** 公司名,可选 */
|
||||
agencyName?: string
|
||||
/** 机构类型,可选 */
|
||||
type?: string | null
|
||||
/** 排序:0默认 1金牌导师优先 2好评优先 3价格升序 4价格降序 */
|
||||
sort: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 导师列表项数据
|
||||
*/
|
||||
export interface MentorItem {
|
||||
/** 导师id(字符串,避免大数精度丢失) */
|
||||
id: string
|
||||
/** 用户id */
|
||||
userId: number
|
||||
/** 平台名 */
|
||||
platformName: string
|
||||
/** 头像 */
|
||||
picture: string
|
||||
/** 话题标题字符串 */
|
||||
titleStr: string
|
||||
/** 话题列表 */
|
||||
titles: string[]
|
||||
/** 标签字符串 */
|
||||
labelStr: string
|
||||
/** 标签列表 */
|
||||
labels: string[]
|
||||
/** 最低价格 */
|
||||
price: number
|
||||
/** 机构名 */
|
||||
agencyName: string
|
||||
/** 岗位 */
|
||||
position: string
|
||||
/** 机构logo */
|
||||
agencyLogo: string
|
||||
/** 排序 */
|
||||
sort: number
|
||||
/** 认证类型 */
|
||||
type: string
|
||||
/** 身份类型 */
|
||||
identityType: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询导师列表响应
|
||||
*/
|
||||
export interface MentorPageResult {
|
||||
records: MentorItem[]
|
||||
total: number
|
||||
size: number
|
||||
current: number
|
||||
pages: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询导师列表
|
||||
* POST /public/mentor/page(offerpai 后端)
|
||||
*/
|
||||
export function fetchMentorList(params: MentorListParams): Promise<MentorPageResult> {
|
||||
return request.post('/public/mentor/page', params)
|
||||
}
|
||||
|
||||
// ==================== 导师详情接口 ====================
|
||||
|
||||
/**
|
||||
* 导师详情 — 在职人士认证信息
|
||||
*/
|
||||
export interface MentorWorking {
|
||||
companyName: string
|
||||
type: number
|
||||
companyLogo: string
|
||||
industryId: number
|
||||
position: string
|
||||
currentPositionTerm: number
|
||||
term: number
|
||||
images: string[]
|
||||
link: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 导师详情 — 认证信息
|
||||
*/
|
||||
export interface MentorVerification {
|
||||
career?: { agencyName: string; position: string; type: number; term: number; agencyLogo: string; images: string[] }
|
||||
psychology?: { agencyName: string; position: string; type: number; agencyLogo: string; term: number; images: string[] }
|
||||
staff?: { schoolName: string; type: number; schoolLogo: string; position: string; term: number; images: string[] }
|
||||
student?: { schoolName: string; type: number; schoolLogo: string; major: string; startTime: string; endTime: string; degree: number; images: string[] }
|
||||
working?: MentorWorking
|
||||
}
|
||||
|
||||
/**
|
||||
* 导师详情 — 基本信息
|
||||
*/
|
||||
export interface MentorInfo {
|
||||
platformName: string
|
||||
realName: string
|
||||
nickName: string
|
||||
picture: string
|
||||
identityType: number
|
||||
country?: string
|
||||
province?: string
|
||||
everCompany?: string
|
||||
city?: string
|
||||
phone: string
|
||||
mail?: string
|
||||
introduce?: string
|
||||
introduceImages?: string[]
|
||||
wechat?: string
|
||||
cooperationCount?: number
|
||||
starLevel?: number
|
||||
remark?: string
|
||||
sort?: number
|
||||
status: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 导师详情 — 支持服务项
|
||||
*/
|
||||
export interface MentorSupport {
|
||||
type: number
|
||||
introduce?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 导师详情 — 标签关系
|
||||
*/
|
||||
export interface MentorLabelRelation {
|
||||
labelId: string
|
||||
labelName: string
|
||||
alias?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 导师详情完整数据
|
||||
*/
|
||||
export interface MentorFullInfo {
|
||||
id: number
|
||||
mentorInfo: MentorInfo
|
||||
verification?: MentorVerification
|
||||
supports?: MentorSupport[]
|
||||
labelRelations?: MentorLabelRelation[]
|
||||
}
|
||||
|
||||
/**
|
||||
* 导师话题项
|
||||
*/
|
||||
export interface MentorTalk {
|
||||
id: number
|
||||
teacherUserId: number
|
||||
title: string
|
||||
content: string
|
||||
chatType: string
|
||||
seePrice: number
|
||||
seeSalePrice: number
|
||||
chatPrice: number
|
||||
chatSalePrice: number
|
||||
tags: string
|
||||
status: string
|
||||
talkTimes: number
|
||||
jobBusinessType: string
|
||||
caseImages?: string[]
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导师详情信息
|
||||
* GET /public/mentor/info?mentorId=xxx(offerpai 后端)
|
||||
*/
|
||||
export function fetchMentorFullInfo(mentorId: string): Promise<MentorFullInfo> {
|
||||
return request.get('/public/mentor/info', { params: { mentorId } })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导师话题列表
|
||||
* GET /public/mentor/talk?teacherId=xxx(offerpai 后端)
|
||||
*/
|
||||
export function fetchMentorTalks(teacherId: string): Promise<MentorTalk[]> {
|
||||
return request.get('/public/mentor/talk', { params: { teacherId } })
|
||||
}
|
||||
|
||||
// ==================== 导师模拟对话接口 ====================
|
||||
|
||||
/**
|
||||
* 模拟对话消息项
|
||||
*/
|
||||
export interface MentorMockMessage {
|
||||
/** 角色:user=用户,mentor=导师 */
|
||||
role: string
|
||||
/** 消息内容 */
|
||||
content: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 模拟对话响应
|
||||
*/
|
||||
export interface MentorMockChatResult {
|
||||
/** 对话消息列表 */
|
||||
messages: MentorMockMessage[]
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导师模拟对话
|
||||
* GET /public/mentor/mockChat?mentorId=xxx
|
||||
* 注意:mentorId 使用字符串传递,避免大数精度丢失
|
||||
*/
|
||||
export function fetchMentorMockChat(mentorId: string): Promise<MentorMockChatResult> {
|
||||
return request.get('/public/mentor/mockChat', { params: { mentorId } })
|
||||
}
|
||||
|
||||
// ==================== 导师小程序二维码接口 ====================
|
||||
|
||||
/**
|
||||
* 获取导师小程序二维码(base64 图片)
|
||||
* POST /public/mentor/getQrCode
|
||||
* @param teacherId 导师ID(字符串,避免精度丢失)
|
||||
* @returns base64 格式的图片数据
|
||||
*/
|
||||
export function fetchMentorQrCode(teacherId: string): Promise<any> {
|
||||
return request.post('/public/mentor/getQrCode', {
|
||||
path: 'pages/teacher/teacher',
|
||||
teacherId,
|
||||
loginAppid: 'wx3adfa65f9d8db17d',
|
||||
})
|
||||
}
|
||||
@@ -1,15 +1,35 @@
|
||||
import request from '@/utils/request'
|
||||
import type { ApiResult } from '@/api/auth'
|
||||
|
||||
/**
|
||||
* 获取当前用户有权限的路由列表
|
||||
*
|
||||
* 【mock 阶段】直接返回写死的数据,模拟后端接口
|
||||
* 【对接真实接口时】把下面的 mock 数据替换成:
|
||||
* return axios.get('/api/user/menus').then(res => res.data)
|
||||
*
|
||||
* 返回格式约定:
|
||||
* path — 路由路径
|
||||
* name — 路由名称(唯一标识,也用于 removeRoute)
|
||||
* component — 字符串,对应前端组件映射表的 key
|
||||
* meta — 可选,传给路由的 meta 信息(图标、标题等)
|
||||
* 路由菜单项 — 后端 /route/menu 接口返回的数据结构
|
||||
*/
|
||||
export interface RouteMenuVo {
|
||||
/** 主键 */
|
||||
id: string
|
||||
/** 根节点ID */
|
||||
rootId: string
|
||||
/** 父级路由ID */
|
||||
parentId: string
|
||||
/** 路由名称(用于侧边栏显示) */
|
||||
routeName: string
|
||||
/** 前端路径 */
|
||||
routePath: string
|
||||
/** 前端组件路径(对应 componentMap 的 key) */
|
||||
component: string
|
||||
/** 图标 key */
|
||||
icon: string
|
||||
/** 排序 */
|
||||
sortOrder: number
|
||||
/** 是否有使用权限:true=可用 false=无权限(需会员) */
|
||||
accessible: boolean
|
||||
/** 递归子菜单 */
|
||||
children?: RouteMenuVo[]
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容旧版 MenuItemRaw 类型(供 SideNav 和 store 使用)
|
||||
* 在新接口基础上补充原有字段映射
|
||||
*/
|
||||
export interface MenuItemRaw {
|
||||
path: string
|
||||
@@ -22,14 +42,40 @@ export interface MenuItemRaw {
|
||||
/** 'footer' 表示该菜单项显示在底部区域而非主导航 */
|
||||
position?: string
|
||||
}
|
||||
/** 排序字段 */
|
||||
sortOrder: number
|
||||
/** 是否有使用权限 */
|
||||
accessible: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* 将后端返回的 RouteMenuVo 转换为前端使用的 MenuItemRaw
|
||||
*/
|
||||
function mapRouteMenuToMenuItem(item: RouteMenuVo): MenuItemRaw {
|
||||
return {
|
||||
path: item.routePath,
|
||||
name: item.component, // component 作为路由 name(与 componentMap 对应)
|
||||
component: item.component,
|
||||
meta: {
|
||||
label: item.routeName,
|
||||
icon: item.icon,
|
||||
},
|
||||
sortOrder: item.sortOrder,
|
||||
accessible: item.accessible,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户有权限的路由菜单列表
|
||||
* GET /route/menu
|
||||
* Cookie 自动携带 Token
|
||||
*/
|
||||
export async function fetchUserRoutes(): Promise<MenuItemRaw[]> {
|
||||
// TODO: 替换为真实接口 → return axios.get('/api/user/menus').then(res => res.data)
|
||||
return [
|
||||
{ path: '/resume', name: 'Resume', component: 'Resume', meta: { label: '简历', icon: 'nav-resume-icon' } },
|
||||
{ path: '/profile', name: 'Profile', component: 'Profile', meta: { label: '个人资料', icon: 'nav-profile-icon' } },
|
||||
{ path: '/agent', name: 'Agent', component: 'Agent', meta: { label: 'AI助手', icon: 'nav-agent-icon', badge: 'NEW' } },
|
||||
{ path: '/settings', name: 'Settings', component: 'Settings', meta: { label: '设置', icon: 'nav-setting-icon', position: 'footer' } },
|
||||
]
|
||||
const res = await request.get<any, ApiResult<RouteMenuVo[]>>('/route/menu')
|
||||
if (res.code === '0' && res.data) {
|
||||
// 按 sortOrder 排序后转换格式
|
||||
const sorted = [...res.data].sort((a, b) => a.sortOrder - b.sortOrder)
|
||||
return sorted.map(mapRouteMenuToMenuItem)
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ export interface MessageDto {
|
||||
bizId: number
|
||||
/** 是否已读 */
|
||||
read: boolean
|
||||
/** 创建时间 */
|
||||
createTime: { seconds: number; nanos: number }
|
||||
/** 创建时间(毫秒时间戳) */
|
||||
createTime: number
|
||||
}
|
||||
|
||||
/** 分页响应结构 */
|
||||
|
||||
@@ -32,9 +32,12 @@ export interface ResumeListItem {
|
||||
/**
|
||||
* 获取简历列表
|
||||
* GET /resume/list
|
||||
* @param pageSize 每页条数,默认 50
|
||||
*/
|
||||
export function fetchResumeList() {
|
||||
return request.get<any, ApiResult<ResumeListItem[]>>('/resume/list')
|
||||
export function fetchResumeList(pageSize = 50) {
|
||||
return request.get<any, ApiResult<ResumeListItem[]>>('/resume/list', {
|
||||
params: { pageSize },
|
||||
})
|
||||
}
|
||||
|
||||
// ==================== 描述段落(通用) ====================
|
||||
@@ -67,8 +70,10 @@ export interface ResumeMainData {
|
||||
email?: string
|
||||
/** 手机号码 */
|
||||
mobileNumber?: string
|
||||
/** 所在城市 */
|
||||
/** 所在城市(名称) */
|
||||
city?: string
|
||||
/** 所在城市编码 */
|
||||
regionCode?: string
|
||||
/** 微信号 */
|
||||
wechatNumber?: string
|
||||
/** 作品集链接 */
|
||||
@@ -251,8 +256,10 @@ export interface SaveResumeMainParams {
|
||||
email?: string
|
||||
/** 手机号码 */
|
||||
mobileNumber?: string
|
||||
/** 所在城市 */
|
||||
/** 所在城市(名称) */
|
||||
city?: string
|
||||
/** 所在城市编码 */
|
||||
regionCode?: string
|
||||
/** 微信号 */
|
||||
wechatNumber?: string
|
||||
/** 作品集链接 */
|
||||
@@ -531,6 +538,16 @@ export function deleteResume(resumeId: string) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 设为默认简历
|
||||
* POST /resume/setDefault
|
||||
*/
|
||||
export function setDefaultResume(resumeId: string) {
|
||||
return request.post<any, ApiResult>('/resume/setDefault', null, {
|
||||
params: { resumeId },
|
||||
})
|
||||
}
|
||||
|
||||
// ==================== 简历诊断相关 ====================
|
||||
|
||||
/** 诊断报告数据 */
|
||||
@@ -644,13 +661,12 @@ export interface PolishIssueData {
|
||||
}
|
||||
|
||||
/**
|
||||
* 对诊断问题进行 AI 润色(AI 接口)
|
||||
* POST /resume/diagnose/issue/{issue_id}/polish
|
||||
* @param issueId 问题 ID
|
||||
* @param content 用户编辑后的文本段落数组
|
||||
* AI 润色简历段落(Python 后端接口)
|
||||
* POST /resume/polish
|
||||
* @param content 待润色的简历段落文本数组
|
||||
*/
|
||||
export function polishDiagnosisIssue(issueId: string, content: string[]) {
|
||||
return aiService.post<AiResult<PolishIssueData>>(`/resume/diagnose/issue/${issueId}/polish`, { content }, {
|
||||
export function polishDiagnosisIssue(content: string[]) {
|
||||
return aiService.post<AiResult<PolishIssueData>>('/resume/polish', { content }, {
|
||||
transformResponse: [(data: string) => {
|
||||
try {
|
||||
const processed = data.replace(/:\s*(\d{16,})/g, ':"$1"')
|
||||
@@ -702,3 +718,31 @@ export function resolveDiagnosisIssue(issueId: string) {
|
||||
}],
|
||||
}).then(res => res.data)
|
||||
}
|
||||
|
||||
// ==================== 修改简历名称和目标岗位(新 Java 后端接口) ====================
|
||||
|
||||
/** 修改简历名称/目标岗位 请求参数 */
|
||||
export interface UpdateResumeInfoParams {
|
||||
/** 简历 ID(必需,字符串避免大整数精度丢失) */
|
||||
resumeId: string
|
||||
/** 简历名称(可选,<= 100 字符) */
|
||||
resumeName?: string
|
||||
/** 目标岗位(可选,<= 100 字符) */
|
||||
targetPosition?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改简历名称和目标岗位
|
||||
* POST /resume/updateInfo
|
||||
*/
|
||||
export function updateResumeInfo(data: UpdateResumeInfoParams) {
|
||||
return request.post<any, ApiResult>('/resume/updateInfo', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据当前用户个人资料创建一份新简历
|
||||
* POST /user/profile/createResume
|
||||
*/
|
||||
export function createResumeFromProfile() {
|
||||
return request.post<any, ApiResult>('/user/profile/createResume')
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 911 B |
|
After Width: | Height: | Size: 839 B |
|
After Width: | Height: | Size: 998 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 480 B |
|
After Width: | Height: | Size: 794 B |
|
After Width: | Height: | Size: 1008 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 211 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 402 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 191 KiB |
@@ -3,10 +3,67 @@ html{
|
||||
font-size: 100px;
|
||||
}
|
||||
|
||||
// 全局滚动条美化(必须在 body 包裹外,才能作用到 body/html 自身的滚动条)
|
||||
::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #D4D4D4;
|
||||
border-radius: 4px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
html, body {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #D4D4D4 transparent;
|
||||
}
|
||||
|
||||
// body 滚动条在缩放模式下会被 transform scale 放大变丑,强制隐藏
|
||||
body {
|
||||
&::-webkit-scrollbar {
|
||||
width: 0 !important;
|
||||
display: none !important;
|
||||
}
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
// 用 body:not(#_) 包裹,提升选择器权重到 id 级别,确保工具类优先级最高
|
||||
// :not(#_) 永远为 true,不影响匹配,只提升权重
|
||||
body:not(#_) {
|
||||
|
||||
// 统一细滚动条工具类(4px 宽、圆角、无按钮)
|
||||
.scrollbar-thin {
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #D4D4D4;
|
||||
border-radius: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
&::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #D4D4D4 transparent;
|
||||
}
|
||||
|
||||
//组件定制样式
|
||||
.box-shadow-head{
|
||||
box-shadow: 0px 6px 16px rgba(0, 0, 0, 0.08), 0px 3px 6px -4px rgba(0, 0, 0, 0.12), 0px -3px 6px -4px rgba(0, 0, 0, 0.12);
|
||||
@@ -304,7 +361,9 @@ body:not(#_) {
|
||||
.aliite-e{
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.aliite-st{
|
||||
align-items: stretch;
|
||||
}
|
||||
//英文字母或数字一行溢出超出,打断
|
||||
.word-bra{
|
||||
word-break: break-all;
|
||||
@@ -391,6 +450,12 @@ body:not(#_) {
|
||||
.flex-warp{
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.flex1{
|
||||
flex: 1;
|
||||
}
|
||||
.flex2{
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
//字体粗细
|
||||
.fw600{
|
||||
@@ -466,6 +531,11 @@ body:not(#_) {
|
||||
.color-2{
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.color-2F7DEA{
|
||||
color: #2F7DEA;
|
||||
}
|
||||
|
||||
.color-3{
|
||||
color: #333;
|
||||
}
|
||||
@@ -518,6 +588,34 @@ body:not(#_) {
|
||||
.color-9B9EAB{
|
||||
color:#9B9EAB;
|
||||
}
|
||||
.color-D31414{
|
||||
color: #D31414;
|
||||
}
|
||||
|
||||
.color-accent{
|
||||
color:$accent;
|
||||
}
|
||||
.color-dark{
|
||||
color:$text-dark;
|
||||
}
|
||||
.color-middle{
|
||||
color:$text-middle;
|
||||
}
|
||||
.color-light{
|
||||
color:$text-light;
|
||||
}
|
||||
.color-accent-ho:hover{
|
||||
color:$accent;
|
||||
}
|
||||
.color-dark-ho:hover{
|
||||
color:$text-dark;
|
||||
}
|
||||
.color-middle-ho:hover{
|
||||
color:$text-middle;
|
||||
}
|
||||
.color-light-ho:hover{
|
||||
color:$text-light;
|
||||
}
|
||||
|
||||
|
||||
/*border*/
|
||||
@@ -533,7 +631,12 @@ body:not(#_) {
|
||||
.border-red1{
|
||||
border: 0.01rem solid #C86667;
|
||||
}
|
||||
|
||||
.border-EDF9FA-bottom-2{
|
||||
border: 0.02rem solid #EDF9FA;
|
||||
}
|
||||
.border-F0F0F0-bottom-1{
|
||||
border: 0.01rem solid #F0F0F0;
|
||||
}
|
||||
//圆角
|
||||
.border-ra0{border-radius: 0rem;}
|
||||
.border-ra1{border-radius: 0.01rem;}
|
||||
@@ -557,6 +660,9 @@ body:not(#_) {
|
||||
.border-ra19{border-radius: 0.19rem;}
|
||||
.border-ra20{border-radius: 0.2rem;}
|
||||
|
||||
.border-ra50p{
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.bor-ra50p{
|
||||
border-radius: 50%;
|
||||
@@ -610,6 +716,11 @@ body:not(#_) {
|
||||
background: $bg-white;
|
||||
}
|
||||
|
||||
.bg-linear-1{
|
||||
background: linear-gradient(to right, #52CAD1, #9FD051)
|
||||
}
|
||||
|
||||
|
||||
/*文字超出隐藏*/
|
||||
.text-over-h{
|
||||
white-space: nowrap; /* 保持文本在一行内显示 */
|
||||
@@ -725,6 +836,9 @@ body:not(#_) {
|
||||
.mb0 {margin-bottom: 0rem;}
|
||||
.mb1 {margin-bottom: 0.01rem;} .mb2 {margin-bottom: 0.02rem;} .mb3 {margin-bottom: 0.03rem;} .mb4 {margin-bottom: 0.04rem;} .mb5 {margin-bottom: 0.05rem;} .mb6 {margin-bottom: 0.06rem;} .mb7 {margin-bottom: 0.07rem;} .mb8 {margin-bottom: 0.08rem;} .mb9 {margin-bottom: 0.09rem;} .mb10 {margin-bottom: 0.1rem;} .mb11 {margin-bottom: 0.11rem;} .mb12 {margin-bottom: 0.12rem;} .mb13 {margin-bottom: 0.13rem;} .mb14 {margin-bottom: 0.14rem;} .mb15 {margin-bottom: 0.15rem;} .mb16 {margin-bottom: 0.16rem;} .mb17 {margin-bottom: 0.17rem;} .mb18 {margin-bottom: 0.18rem;} .mb19 {margin-bottom: 0.19rem;} .mb20 {margin-bottom: 0.2rem;} .mb21 {margin-bottom: 0.21rem;} .mb22 {margin-bottom: 0.22rem;} .mb23 {margin-bottom: 0.23rem;} .mb24 {margin-bottom: 0.24rem;} .mb25 {margin-bottom: 0.25rem;} .mb26 {margin-bottom: 0.26rem;} .mb27 {margin-bottom: 0.27rem;} .mb28 {margin-bottom: 0.28rem;} .mb29 {margin-bottom: 0.29rem;} .mb30 {margin-bottom: 0.3rem;} .mb31 {margin-bottom: 0.31rem;} .mb32 {margin-bottom: 0.32rem;} .mb33 {margin-bottom: 0.33rem;} .mb34 {margin-bottom: 0.34rem;} .mb35 {margin-bottom: 0.35rem;} .mb36 {margin-bottom: 0.36rem;} .mb37 {margin-bottom: 0.37rem;} .mb38 {margin-bottom: 0.38rem;} .mb39 {margin-bottom: 0.39rem;} .mb40 {margin-bottom: 0.4rem;} .mb41 {margin-bottom: 0.41rem;} .mb42 {margin-bottom: 0.42rem;} .mb43 {margin-bottom: 0.43rem;} .mb44 {margin-bottom: 0.44rem;} .mb45 {margin-bottom: 0.45rem;} .mb46 {margin-bottom: 0.46rem;} .mb47 {margin-bottom: 0.47rem;} .mb48 {margin-bottom: 0.48rem;} .mb49 {margin-bottom: 0.49rem;} .mb50 {margin-bottom: 0.5rem;} .mb51 {margin-bottom: 0.51rem;} .mb52 {margin-bottom: 0.52rem;} .mb53 {margin-bottom: 0.53rem;} .mb54 {margin-bottom: 0.54rem;} .mb55 {margin-bottom: 0.55rem;} .mb56 {margin-bottom: 0.56rem;} .mb57 {margin-bottom: 0.57rem;} .mb58 {margin-bottom: 0.58rem;} .mb59 {margin-bottom: 0.59rem;} .mb60 {margin-bottom: 0.6rem;} .mb61 {margin-bottom: 0.61rem;} .mb62 {margin-bottom: 0.62rem;} .mb63 {margin-bottom: 0.63rem;} .mb64 {margin-bottom: 0.64rem;} .mb65 {margin-bottom: 0.65rem;} .mb66 {margin-bottom: 0.66rem;} .mb67 {margin-bottom: 0.67rem;} .mb68 {margin-bottom: 0.68rem;} .mb69 {margin-bottom: 0.69rem;} .mb70 {margin-bottom: 0.7rem;} .mb71 {margin-bottom: 0.71rem;} .mb72 {margin-bottom: 0.72rem;} .mb73 {margin-bottom: 0.73rem;} .mb74 {margin-bottom: 0.74rem;} .mb75 {margin-bottom: 0.75rem;} .mb76 {margin-bottom: 0.76rem;} .mb77 {margin-bottom: 0.77rem;} .mb78 {margin-bottom: 0.78rem;} .mb79 {margin-bottom: 0.79rem;} .mb80 {margin-bottom: 0.8rem;} .mb81 {margin-bottom: 0.81rem;} .mb82 {margin-bottom: 0.82rem;} .mb83 {margin-bottom: 0.83rem;} .mb84 {margin-bottom: 0.84rem;} .mb85 {margin-bottom: 0.85rem;} .mb86 {margin-bottom: 0.86rem;} .mb87 {margin-bottom: 0.87rem;} .mb88 {margin-bottom: 0.88rem;} .mb89 {margin-bottom: 0.89rem;} .mb90 {margin-bottom: 0.9rem;} .mb91 {margin-bottom: 0.91rem;} .mb92 {margin-bottom: 0.92rem;} .mb93 {margin-bottom: 0.93rem;} .mb94 {margin-bottom: 0.94rem;} .mb95 {margin-bottom: 0.95rem;} .mb96 {margin-bottom: 0.96rem;} .mb97 {margin-bottom: 0.97rem;} .mb98 {margin-bottom: 0.98rem;} .mb99 {margin-bottom: 0.99rem;}
|
||||
.mb100 {margin-bottom: 1rem;}
|
||||
.mb-20{
|
||||
margin-bottom: -0.2rem;
|
||||
}
|
||||
|
||||
/* margin-top-bottom */
|
||||
.mtb0 {margin-top: 0rem;margin-bottom: 0rem;}
|
||||
@@ -737,10 +851,13 @@ body:not(#_) {
|
||||
.ml100 {margin-left: 1rem;}
|
||||
.ml135 {margin-left: 1.35rem;}
|
||||
|
||||
.mlauto {margin-left: auto;}
|
||||
|
||||
/* margin-right */
|
||||
.mr0 {margin-right: 0rem;}
|
||||
.mr1 {margin-right: 0.01rem;} .mr2 {margin-right: 0.02rem;} .mr3 {margin-right: 0.03rem;} .mr4 {margin-right: 0.04rem;} .mr5 {margin-right: 0.05rem;} .mr6 {margin-right: 0.06rem;} .mr7 {margin-right: 0.07rem;} .mr8 {margin-right: 0.08rem;} .mr9 {margin-right: 0.09rem;} .mr10 {margin-right: 0.1rem;} .mr11 {margin-right: 0.11rem;} .mr12 {margin-right: 0.12rem;} .mr13 {margin-right: 0.13rem;} .mr14 {margin-right: 0.14rem;} .mr15 {margin-right: 0.15rem;} .mr16 {margin-right: 0.16rem;} .mr17 {margin-right: 0.17rem;} .mr18 {margin-right: 0.18rem;} .mr19 {margin-right: 0.19rem;} .mr20 {margin-right: 0.2rem;} .mr21 {margin-right: 0.21rem;} .mr22 {margin-right: 0.22rem;} .mr23 {margin-right: 0.23rem;} .mr24 {margin-right: 0.24rem;} .mr25 {margin-right: 0.25rem;} .mr26 {margin-right: 0.26rem;} .mr27 {margin-right: 0.27rem;} .mr28 {margin-right: 0.28rem;} .mr29 {margin-right: 0.29rem;} .mr30 {margin-right: 0.3rem;} .mr31 {margin-right: 0.31rem;} .mr32 {margin-right: 0.32rem;} .mr33 {margin-right: 0.33rem;} .mr34 {margin-right: 0.34rem;} .mr35 {margin-right: 0.35rem;} .mr36 {margin-right: 0.36rem;} .mr37 {margin-right: 0.37rem;} .mr38 {margin-right: 0.38rem;} .mr39 {margin-right: 0.39rem;} .mr40 {margin-right: 0.4rem;} .mr41 {margin-right: 0.41rem;} .mr42 {margin-right: 0.42rem;} .mr43 {margin-right: 0.43rem;} .mr44 {margin-right: 0.44rem;} .mr45 {margin-right: 0.45rem;} .mr46 {margin-right: 0.46rem;} .mr47 {margin-right: 0.47rem;} .mr48 {margin-right: 0.48rem;} .mr49 {margin-right: 0.49rem;} .mr50 {margin-right: 0.5rem;} .mr51 {margin-right: 0.51rem;} .mr52 {margin-right: 0.52rem;} .mr53 {margin-right: 0.53rem;} .mr54 {margin-right: 0.54rem;} .mr55 {margin-right: 0.55rem;} .mr56 {margin-right: 0.56rem;} .mr57 {margin-right: 0.57rem;} .mr58 {margin-right: 0.58rem;} .mr59 {margin-right: 0.59rem;} .mr60 {margin-right: 0.6rem;} .mr61 {margin-right: 0.61rem;} .mr62 {margin-right: 0.62rem;} .mr63 {margin-right: 0.63rem;} .mr64 {margin-right: 0.64rem;} .mr65 {margin-right: 0.65rem;} .mr66 {margin-right: 0.66rem;} .mr67 {margin-right: 0.67rem;} .mr68 {margin-right: 0.68rem;} .mr69 {margin-right: 0.69rem;} .mr70 {margin-right: 0.7rem;} .mr71 {margin-right: 0.71rem;} .mr72 {margin-right: 0.72rem;} .mr73 {margin-right: 0.73rem;} .mr74 {margin-right: 0.74rem;} .mr75 {margin-right: 0.75rem;} .mr76 {margin-right: 0.76rem;} .mr77 {margin-right: 0.77rem;} .mr78 {margin-right: 0.78rem;} .mr79 {margin-right: 0.79rem;} .mr80 {margin-right: 0.8rem;} .mr81 {margin-right: 0.81rem;} .mr82 {margin-right: 0.82rem;} .mr83 {margin-right: 0.83rem;} .mr84 {margin-right: 0.84rem;} .mr85 {margin-right: 0.85rem;} .mr86 {margin-right: 0.86rem;} .mr87 {margin-right: 0.87rem;} .mr88 {margin-right: 0.88rem;} .mr89 {margin-right: 0.89rem;} .mr90 {margin-right: 0.9rem;} .mr91 {margin-right: 0.91rem;} .mr92 {margin-right: 0.92rem;} .mr93 {margin-right: 0.93rem;} .mr94 {margin-right: 0.94rem;} .mr95 {margin-right: 0.95rem;} .mr96 {margin-right: 0.96rem;} .mr97 {margin-right: 0.97rem;} .mr98 {margin-right: 0.98rem;} .mr99 {margin-right: 0.99rem;}
|
||||
.mr100 {margin-right: 1rem;}
|
||||
.mrauto {margin-right: auto;}
|
||||
|
||||
/* margin-right-left */
|
||||
.mrl0 {margin-right: 0rem;margin-left: 0rem;}
|
||||
@@ -789,6 +906,9 @@ body:not(#_) {
|
||||
.max-w1200{
|
||||
max-width: 12rem;
|
||||
}
|
||||
.max-w602{
|
||||
max-width: 6.02rem;
|
||||
}
|
||||
.w0{width: 0rem;}
|
||||
.w1{width: 0.01rem;} .w2{width: 0.02rem;} .w3{width: 0.03rem;} .w4{width: 0.04rem;} .w5{width: 0.05rem;} .w6{width: 0.06rem;} .w7{width: 0.07rem;} .w8{width: 0.08rem;} .w9{width: 0.09rem;} .w10{width: 0.1rem;} .w11{width: 0.11rem;} .w12{width: 0.12rem;} .w13{width: 0.13rem;} .w14{width: 0.14rem;} .w15{width: 0.15rem;} .w16{width: 0.16rem;} .w17{width: 0.17rem;} .w18{width: 0.18rem;} .w19{width: 0.19rem;} .w20{width: 0.2rem;} .w21{width: 0.21rem;} .w22{width: 0.22rem;} .w23{width: 0.23rem;} .w24{width: 0.24rem;} .w25{width: 0.25rem;} .w26{width: 0.26rem;} .w27{width: 0.27rem;} .w28{width: 0.28rem;} .w29{width: 0.29rem;} .w30{width: 0.3rem;} .w31{width: 0.31rem;} .w32{width: 0.32rem;} .w33{width: 0.33rem;} .w34{width: 0.34rem;} .w35{width: 0.35rem;} .w36{width: 0.36rem;} .w37{width: 0.37rem;} .w38{width: 0.38rem;} .w39{width: 0.39rem;} .w40{width: 0.4rem;} .w41{width: 0.41rem;} .w42{width: 0.42rem;} .w43{width: 0.43rem;} .w44{width: 0.44rem;} .w45{width: 0.45rem;} .w46{width: 0.46rem;} .w47{width: 0.47rem;} .w48{width: 0.48rem;} .w49{width: 0.49rem;} .w50{width: 0.5rem;} .w51{width: 0.51rem;} .w52{width: 0.52rem;} .w53{width: 0.53rem;} .w54{width: 0.54rem;} .w55{width: 0.55rem;} .w56{width: 0.56rem;} .w57{width: 0.57rem;} .w58{width: 0.58rem;} .w59{width: 0.59rem;} .w60{width: 0.6rem;} .w61{width: 0.61rem;} .w62{width: 0.62rem;} .w63{width: 0.63rem;} .w64{width: 0.64rem;} .w65{width: 0.65rem;} .w66{width: 0.66rem;} .w67{width: 0.67rem;} .w68{width: 0.68rem;} .w69{width: 0.69rem;} .w70{width: 0.7rem;} .w71{width: 0.71rem;} .w72{width: 0.72rem;} .w73{width: 0.73rem;} .w74{width: 0.74rem;} .w75{width: 0.75rem;} .w76{width: 0.76rem;} .w77{width: 0.77rem;} .w78{width: 0.78rem;} .w79{width: 0.79rem;} .w80{width: 0.8rem;} .w81{width: 0.81rem;} .w82{width: 0.82rem;} .w83{width: 0.83rem;} .w84{width: 0.84rem;} .w85{width: 0.85rem;} .w86{width: 0.86rem;} .w87{width: 0.87rem;} .w88{width: 0.88rem;} .w89{width: 0.89rem;} .w90{width: 0.9rem;} .w91{width: 0.91rem;} .w92{width: 0.92rem;} .w93{width: 0.93rem;} .w94{width: 0.94rem;} .w95{width: 0.95rem;} .w96{width: 0.96rem;} .w97{width: 0.97rem;} .w98{width: 0.98rem;} .w99{width: 0.99rem;}
|
||||
.w100{width: 1rem;}
|
||||
@@ -809,12 +929,16 @@ body:not(#_) {
|
||||
.w192{width: 1.92rem;}
|
||||
.w200{width: 2rem;}
|
||||
.w244{width: 2.44rem;}
|
||||
.w263{width: 2.63rem;}
|
||||
.w444{width: 4.44rem;}
|
||||
.w706{width: 7.06rem;}
|
||||
.w1200{width:12rem}
|
||||
|
||||
/*height*/
|
||||
.h0{height: 0rem;}
|
||||
.h1{height: 0.01rem;} .h2{height: 0.02rem;} .h3{height: 0.03rem;} .h4{height: 0.04rem;} .h5{height: 0.05rem;} .h6{height: 0.06rem;} .h7{height: 0.07rem;} .h8{height: 0.08rem;} .h9{height: 0.09rem;} .h10{height: 0.1rem;} .h11{height: 0.11rem;} .h12{height: 0.12rem;} .h13{height: 0.13rem;} .h14{height: 0.14rem;} .h15{height: 0.15rem;} .h16{height: 0.16rem;} .h17{height: 0.17rem;} .h18{height: 0.18rem;} .h19{height: 0.19rem;} .h20{height: 0.2rem;} .h21{height: 0.21rem;} .h22{height: 0.22rem;} .h23{height: 0.23rem;} .h24{height: 0.24rem;} .h25{height: 0.25rem;} .h26{height: 0.26rem;} .h27{height: 0.27rem;} .h28{height: 0.28rem;} .h29{height: 0.29rem;} .h30{height: 0.3rem;} .h31{height: 0.31rem;} .h32{height: 0.32rem;} .h33{height: 0.33rem;} .h34{height: 0.34rem;} .h35{height: 0.35rem;} .h36{height: 0.36rem;} .h37{height: 0.37rem;} .h38{height: 0.38rem;} .h39{height: 0.39rem;} .h40{height: 0.4rem;} .h41{height: 0.41rem;} .h42{height: 0.42rem;} .h43{height: 0.43rem;} .h44{height: 0.44rem;} .h45{height: 0.45rem;} .h46{height: 0.46rem;} .h47{height: 0.47rem;} .h48{height: 0.48rem;} .h49{height: 0.49rem;} .h50{height: 0.5rem;} .h51{height: 0.51rem;} .h52{height: 0.52rem;} .h53{height: 0.53rem;} .h54{height: 0.54rem;} .h55{height: 0.55rem;} .h56{height: 0.56rem;} .h57{height: 0.57rem;} .h58{height: 0.58rem;} .h59{height: 0.59rem;} .h60{height: 0.6rem;} .h61{height: 0.61rem;} .h62{height: 0.62rem;} .h63{height: 0.63rem;} .h64{height: 0.64rem;} .h65{height: 0.65rem;} .h66{height: 0.66rem;} .h67{height: 0.67rem;} .h68{height: 0.68rem;} .h69{height: 0.69rem;} .h70{height: 0.7rem;} .h71{height: 0.71rem;} .h72{height: 0.72rem;} .h73{height: 0.73rem;} .h74{height: 0.74rem;} .h75{height: 0.75rem;} .h76{height: 0.76rem;} .h77{height: 0.77rem;} .h78{height: 0.78rem;} .h79{height: 0.79rem;} .h80{height: 0.8rem;} .h81{height: 0.81rem;} .h82{height: 0.82rem;} .h83{height: 0.83rem;} .h84{height: 0.84rem;} .h85{height: 0.85rem;} .h86{height: 0.86rem;} .h87{height: 0.87rem;} .h88{height: 0.88rem;} .h89{height: 0.89rem;} .h90{height: 0.9rem;} .h91{height: 0.91rem;} .h92{height: 0.92rem;} .h93{height: 0.93rem;} .h94{height: 0.94rem;} .h95{height: 0.95rem;} .h96{height: 0.96rem;} .h97{height: 0.97rem;} .h98{height: 0.98rem;} .h99{height: 0.99rem;}
|
||||
.h100{height: 1rem;}
|
||||
.h452{height: 4.52rem;}
|
||||
|
||||
//行高
|
||||
.lh0{line-height: 0rem;}
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
@use '../variables' as *;
|
||||
|
||||
/* 申请进度面板样式 */
|
||||
.agent-apply-progress-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
background: $bg-white;
|
||||
border-radius: 0.2rem;
|
||||
overflow: hidden;
|
||||
|
||||
/* 顶部标题栏 */
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.16rem 0.2rem;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 0.16rem;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
/* 关闭按钮 */
|
||||
&__close-btn {
|
||||
width: 0.28rem;
|
||||
height: 0.28rem;
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* 筛选栏 */
|
||||
&__filter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.1rem;
|
||||
padding: 0 0.2rem 0.14rem;
|
||||
}
|
||||
|
||||
/* 下拉选择容器 */
|
||||
&__select-wrap {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__select {
|
||||
padding: 0.08rem 0.12rem;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 0.06rem;
|
||||
font-size: 0.13rem;
|
||||
color: $text-dark;
|
||||
background: $bg-white;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
min-width: 1rem;
|
||||
|
||||
&:focus {
|
||||
border-color: $accent;
|
||||
}
|
||||
}
|
||||
|
||||
/* 搜索框 */
|
||||
&__search {
|
||||
flex: 1;
|
||||
padding: 0.08rem 0.12rem;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 0.06rem;
|
||||
font-size: 0.13rem;
|
||||
color: $text-dark;
|
||||
outline: none;
|
||||
|
||||
&::placeholder {
|
||||
color: $text-light;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: $accent;
|
||||
}
|
||||
}
|
||||
|
||||
/* 列表区域(可滚动) */
|
||||
&__list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0 0.2rem 0.2rem;
|
||||
}
|
||||
|
||||
/* 单个岗位项 */
|
||||
&__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.14rem 0.16rem;
|
||||
background: $bg-main;
|
||||
border-radius: 0.12rem;
|
||||
margin-bottom: 0.1rem;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 左侧信息区域 */
|
||||
&__info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.12rem;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 公司 Logo */
|
||||
&__logo {
|
||||
width: 0.4rem;
|
||||
height: 0.4rem;
|
||||
border-radius: 0.08rem;
|
||||
background: $bg-middle;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
|
||||
svg {
|
||||
width: 0.22rem;
|
||||
height: 0.22rem;
|
||||
color: $text-middle;
|
||||
}
|
||||
}
|
||||
|
||||
/* 岗位详情 */
|
||||
&__detail {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&__company {
|
||||
font-size: 0.13rem;
|
||||
font-weight: 500;
|
||||
color: $text-dark;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&__position {
|
||||
font-size: 0.12rem;
|
||||
color: $text-middle;
|
||||
margin-top: 0.02rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* 标签 */
|
||||
&__tags {
|
||||
display: flex;
|
||||
gap: 0.06rem;
|
||||
margin-top: 0.06rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&__tag {
|
||||
font-size: 0.11rem;
|
||||
color: $text-middle;
|
||||
background: $bg-white;
|
||||
padding: 0.02rem 0.08rem;
|
||||
border-radius: 0.04rem;
|
||||
}
|
||||
|
||||
/* 右侧区域 */
|
||||
&__right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 匹配度环 */
|
||||
&__score {
|
||||
position: relative;
|
||||
width: 0.4rem;
|
||||
height: 0.4rem;
|
||||
}
|
||||
|
||||
&__ring {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&__score-text {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 0.1rem;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
/* 状态下拉 */
|
||||
&__status-select {
|
||||
padding: 0.05rem 0.1rem;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 0.04rem;
|
||||
font-size: 0.12rem;
|
||||
color: $text-dark;
|
||||
background: $bg-white;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
|
||||
&:focus {
|
||||
border-color: $accent;
|
||||
}
|
||||
}
|
||||
|
||||
/* 删除按钮 */
|
||||
&__delete-btn {
|
||||
width: 0.2rem;
|
||||
height: 0.2rem;
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&:hover svg circle {
|
||||
fill: $danger;
|
||||
}
|
||||
}
|
||||
|
||||
/* 加载中 */
|
||||
&__loading {
|
||||
text-align: center;
|
||||
padding: 0.16rem 0;
|
||||
font-size: 0.12rem;
|
||||
color: $text-light;
|
||||
}
|
||||
|
||||
/* 暂无更多数据 */
|
||||
&__no-more {
|
||||
text-align: center;
|
||||
padding: 0.16rem 0;
|
||||
font-size: 0.12rem;
|
||||
color: $text-light;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
&__empty {
|
||||
text-align: center;
|
||||
padding: 0.4rem 0;
|
||||
font-size: 0.13rem;
|
||||
color: $text-light;
|
||||
}
|
||||
}
|
||||
@@ -1,317 +1,240 @@
|
||||
@use '../variables' as *;
|
||||
|
||||
// 申请进度消息组件
|
||||
// 投递进度卡片组件(新版4步骤)
|
||||
.agent-apply-progress {
|
||||
background: $bg-middle;
|
||||
border-radius: 0.12rem;
|
||||
padding: 0.2rem;
|
||||
font-size: 0.14rem;
|
||||
background: $bg-white;
|
||||
border: 1px solid #F0F0F0;
|
||||
border-radius: 0.08rem;
|
||||
padding: 0.16rem 0.2rem;
|
||||
|
||||
// 顶部标题栏
|
||||
&__header {
|
||||
// 已完成状态
|
||||
&--completed {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
// 顶部区域:岗位信息 + 步骤条
|
||||
&__top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.16rem;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 0.15rem;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
|
||||
// 可点击状态(暂停/恢复)
|
||||
&--clickable {
|
||||
cursor: pointer;
|
||||
color: $accent;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__cancel {
|
||||
font-size: 0.13rem;
|
||||
color: $text-middle;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: $text-dark;
|
||||
}
|
||||
}
|
||||
|
||||
// 岗位信息卡片
|
||||
&__job-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.12rem;
|
||||
background: $bg-white;
|
||||
border-radius: 0.1rem;
|
||||
padding: 0.14rem 0.16rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
&__job-icon {
|
||||
width: 0.36rem;
|
||||
height: 0.36rem;
|
||||
border-radius: 0.08rem;
|
||||
background: $bg-main;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
color: $text-middle;
|
||||
|
||||
svg {
|
||||
width: 0.2rem;
|
||||
height: 0.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__job-info {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&__job-company {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
&__job-title {
|
||||
font-size: 0.12rem;
|
||||
color: $text-middle;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
// 步骤列表
|
||||
&__steps {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.14rem;
|
||||
}
|
||||
|
||||
&__step {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
// 勾选框
|
||||
&__step-check {
|
||||
width: 0.18rem;
|
||||
height: 0.18rem;
|
||||
border: 1.5px solid $text-light;
|
||||
border-radius: 0.03rem;
|
||||
// 岗位信息
|
||||
&__job-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
margin-top: 0.01rem;
|
||||
|
||||
svg {
|
||||
width: 0.12rem;
|
||||
height: 0.12rem;
|
||||
}
|
||||
|
||||
// 已完成态
|
||||
&--done {
|
||||
border-color: $text-dark;
|
||||
background: $text-dark;
|
||||
color: $bg-white;
|
||||
}
|
||||
gap: 0.28rem;
|
||||
}
|
||||
|
||||
&__step-label {
|
||||
font-size: 0.14rem;
|
||||
&__job-title {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 620;
|
||||
color: $text-dark;
|
||||
line-height: 0.2rem;
|
||||
line-height: 0.27rem;
|
||||
}
|
||||
|
||||
// 步骤展开内容
|
||||
&__step-content {
|
||||
width: 100%;
|
||||
margin-top: 0.08rem;
|
||||
padding-left: 0.28rem;
|
||||
}
|
||||
|
||||
// 第2步:简历确认区域
|
||||
&__resume-confirm {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: $bg-white;
|
||||
border-radius: 0.08rem;
|
||||
padding: 0.1rem 0.14rem;
|
||||
}
|
||||
|
||||
&__resume-file {
|
||||
&__company {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.08rem;
|
||||
}
|
||||
|
||||
&__file-icon {
|
||||
width: 0.18rem;
|
||||
height: 0.18rem;
|
||||
color: $text-dark;
|
||||
}
|
||||
&__company-logo {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
border-radius: 0.04rem;
|
||||
object-fit: cover;
|
||||
|
||||
&__resume-name {
|
||||
font-size: 0.13rem;
|
||||
color: $text-dark;
|
||||
}
|
||||
&--placeholder {
|
||||
background: $bg-main;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: $text-middle;
|
||||
|
||||
&__confirm-btn {
|
||||
height: 0.28rem;
|
||||
padding: 0 0.16rem;
|
||||
background: $btn-dark;
|
||||
color: $bg-white;
|
||||
border: none;
|
||||
border-radius: 0.14rem;
|
||||
font-size: 0.12rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: $btn-dark-hover;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: $text-light;
|
||||
cursor: not-allowed;
|
||||
svg {
|
||||
width: 0.14rem;
|
||||
height: 0.14rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 第3步:投递操作区域
|
||||
&__apply-area {
|
||||
background: $bg-white;
|
||||
border-radius: 0.08rem;
|
||||
padding: 0.14rem 0.16rem;
|
||||
&__company-name {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 330;
|
||||
color: $text-dark;
|
||||
line-height: 0.27rem;
|
||||
}
|
||||
|
||||
&__apply-desc {
|
||||
font-size: 0.12rem;
|
||||
color: $text-middle;
|
||||
line-height: 1.8;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&__apply-actions {
|
||||
// 步骤条
|
||||
&__steps {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 0.1rem;
|
||||
margin-top: 0.14rem;
|
||||
gap: 0.12rem;
|
||||
}
|
||||
|
||||
&__skip-btn {
|
||||
font-size: 0.12rem;
|
||||
color: $text-middle;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
// 步骤项
|
||||
&__step-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.08rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
// 步骤图标
|
||||
&__step-icon {
|
||||
width: 0.40rem;
|
||||
height: 0.40rem;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
|
||||
svg {
|
||||
width: 0.20rem;
|
||||
height: 0.20rem;
|
||||
}
|
||||
|
||||
// 已完成
|
||||
&--done {
|
||||
background: $accent;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
// 进行中
|
||||
&--active {
|
||||
background: #EDF9FA;
|
||||
color: $accent;
|
||||
}
|
||||
|
||||
// 待处理
|
||||
&--pending {
|
||||
background: $bg-main;
|
||||
color: $text-middle;
|
||||
}
|
||||
}
|
||||
|
||||
// 步骤文字区域
|
||||
&__step-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.04rem;
|
||||
}
|
||||
|
||||
// 步骤名称
|
||||
&__step-name {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 620;
|
||||
line-height: 0.19rem;
|
||||
|
||||
&--done {
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
color: $text-light;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
&--active {
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
&--pending {
|
||||
color: $text-middle;
|
||||
}
|
||||
}
|
||||
|
||||
&__applied-btn {
|
||||
height: 0.28rem;
|
||||
padding: 0 0.14rem;
|
||||
background: $btn-dark;
|
||||
color: $bg-white;
|
||||
border: none;
|
||||
border-radius: 0.14rem;
|
||||
// 步骤状态文字
|
||||
&__step-status {
|
||||
font-size: 0.12rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-weight: 330;
|
||||
line-height: 0.16rem;
|
||||
|
||||
&:hover {
|
||||
background: $btn-dark-hover;
|
||||
&--done {
|
||||
color: #9FD051;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: $text-light;
|
||||
cursor: not-allowed;
|
||||
&--active {
|
||||
color: #F59E0B;
|
||||
}
|
||||
|
||||
&--pending {
|
||||
color: $text-middle;
|
||||
}
|
||||
}
|
||||
|
||||
&__goto-btn {
|
||||
height: 0.28rem;
|
||||
padding: 0 0.14rem;
|
||||
background: $btn-dark;
|
||||
color: $bg-white;
|
||||
border: none;
|
||||
border-radius: 0.14rem;
|
||||
font-size: 0.12rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: $btn-dark-hover;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: $text-light;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 右侧面板:简历生成进度
|
||||
.agent-resume-generating {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
padding: 0.4rem;
|
||||
|
||||
// 进度条容器
|
||||
&__progress-bar {
|
||||
width: 100%;
|
||||
max-width: 3rem;
|
||||
height: 0.04rem;
|
||||
background: $border-color;
|
||||
border-radius: 0.02rem;
|
||||
overflow: hidden;
|
||||
margin-bottom: 0.2rem;
|
||||
// 步骤连接线
|
||||
&__step-line {
|
||||
width: 0.40rem;
|
||||
height: 0.02rem;
|
||||
background: #E5E7EB;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__progress-fill {
|
||||
height: 100%;
|
||||
background: $text-dark;
|
||||
border-radius: 0.02rem;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 700;
|
||||
color: $text-dark;
|
||||
margin-bottom: 0.1rem;
|
||||
// 底部区域:提示 + 按钮
|
||||
&__bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
margin-top: 0.16rem;
|
||||
}
|
||||
|
||||
// 提示文字
|
||||
&__hint {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
color: $text-middle;
|
||||
line-height: 0.19rem;
|
||||
|
||||
// 警告色(橙色)
|
||||
&--warning {
|
||||
color: #F59E0B;
|
||||
}
|
||||
|
||||
// 匹配度偏低(红橙色)
|
||||
&--low-match {
|
||||
color: #FE6D52;
|
||||
}
|
||||
|
||||
// 强调色(品牌色)
|
||||
&--accent {
|
||||
color: $accent;
|
||||
}
|
||||
}
|
||||
|
||||
// 操作按钮区
|
||||
&__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.06rem;
|
||||
font-size: 0.12rem;
|
||||
color: $text-middle;
|
||||
gap: 0.16rem;
|
||||
}
|
||||
|
||||
&__hint-icon {
|
||||
width: 0.14rem;
|
||||
height: 0.14rem;
|
||||
color: $accent;
|
||||
// 按钮基础样式
|
||||
&__btn {
|
||||
height: 0.27rem;
|
||||
padding: 0.04rem 0.12rem;
|
||||
border-radius: 0.08rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 380;
|
||||
line-height: 0.19rem;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
// 边框按钮
|
||||
&--outline {
|
||||
background: transparent;
|
||||
border: 1px solid $accent;
|
||||
color: $accent;
|
||||
}
|
||||
|
||||
// 实心按钮
|
||||
&--primary {
|
||||
background: $accent;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
// Agent浏览器插件安装步骤指引组件样式
|
||||
@use '../variables' as *;
|
||||
|
||||
/* 步骤内容区域 */
|
||||
.agent-browser-guide-drawer__body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0 0.32rem 0.32rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.16rem;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
/* 步骤卡片 */
|
||||
.agent-browser-guide-drawer__card {
|
||||
border: 1px solid #F0F0F0;
|
||||
border-radius: 0.12rem;
|
||||
padding: 0.16rem 0.2rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.agent-browser-guide-drawer__step-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.12rem;
|
||||
margin-bottom: 0.16rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.agent-browser-guide-drawer__step-num {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 0.32rem;
|
||||
height: 0.32rem;
|
||||
background: #EDF9FA;
|
||||
border-radius: 0.08rem;
|
||||
font-size: 0.18rem;
|
||||
font-weight: 620;
|
||||
color: $accent;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.agent-browser-guide-drawer__step-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.agent-browser-guide-drawer__step-title {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 620;
|
||||
color: $text-dark;
|
||||
line-height: 0.24rem;
|
||||
margin: 0 0 0.04rem;
|
||||
}
|
||||
|
||||
.agent-browser-guide-drawer__step-desc {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 330;
|
||||
color: $text-middle;
|
||||
line-height: 0.19rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 下载按钮区域 */
|
||||
.agent-browser-guide-drawer__download-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.16rem;
|
||||
padding: 0.04rem 0.04rem 0.04rem 0.16rem;
|
||||
background: $bg-main;
|
||||
border-radius: 0.12rem;
|
||||
height: 0.44rem;
|
||||
margin-left: 0.4rem;
|
||||
}
|
||||
|
||||
.agent-browser-guide-drawer__download-name {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
color: $text-dark;
|
||||
line-height: 0.19rem;
|
||||
}
|
||||
|
||||
.agent-browser-guide-drawer__download-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.04rem;
|
||||
padding: 0.08rem 0.12rem;
|
||||
background: $accent;
|
||||
border: none;
|
||||
border-radius: 0.08rem;
|
||||
color: $bg-white;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 620;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: $accent-hover;
|
||||
}
|
||||
}
|
||||
|
||||
/* 浏览器链接区域 */
|
||||
.agent-browser-guide-drawer__browser-links {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.24rem;
|
||||
margin-bottom: 0.16rem;
|
||||
margin-left: 0.4rem;
|
||||
}
|
||||
|
||||
.agent-browser-guide-drawer__browser-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.04rem;
|
||||
padding: 0.12rem 0.16rem;
|
||||
background: $bg-white;
|
||||
border: 1px solid #F0F0F0;
|
||||
border-radius: 0.08rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
color: $text-middle;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
border-color: $accent;
|
||||
}
|
||||
|
||||
svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
span {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.agent-browser-guide-drawer__copy-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.04rem;
|
||||
color: $accent;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
margin-left: 0.12rem;
|
||||
}
|
||||
|
||||
/* 步骤示意图 */
|
||||
.agent-browser-guide-drawer__step-img {
|
||||
width: 100%;
|
||||
max-width: 3.52rem;
|
||||
border-radius: 0.08rem;
|
||||
margin-top: 0.12rem;
|
||||
margin-left: 0.4rem;
|
||||
}
|
||||
@@ -1,19 +1,51 @@
|
||||
@use '../variables' as *;
|
||||
|
||||
// ==================== Agent会话岗位列表组件样式 ====================
|
||||
// ==================== Agent推荐岗位列表组件样式 ====================
|
||||
.agent-chat-job-list {
|
||||
background: $bg-middle;
|
||||
background: $bg-white;
|
||||
border: 1px solid #F0F0F0;
|
||||
box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.04);
|
||||
border-radius: 0.12rem;
|
||||
padding: 0.2rem;
|
||||
margin-top: 0.16rem;
|
||||
padding: 0.24rem;
|
||||
font-size: 0.14rem;
|
||||
|
||||
// 标题
|
||||
&__header {
|
||||
font-size: 0.22rem;
|
||||
font-weight: 620;
|
||||
color: $text-dark;
|
||||
margin-bottom: 0.04rem;
|
||||
line-height: 0.29rem;
|
||||
}
|
||||
|
||||
// 推荐说明文字
|
||||
&__summary {
|
||||
font-size: 0.13rem;
|
||||
color: $text-dark;
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.14rem;
|
||||
line-height: 1.6;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 330;
|
||||
color: $text-middle;
|
||||
margin-bottom: 0.16rem;
|
||||
line-height: 0.19rem;
|
||||
}
|
||||
|
||||
// 可滚动岗位列表区域(默认显示约3.5个岗位高度)
|
||||
&__scroll {
|
||||
max-height: 3.64rem;
|
||||
overflow-y: auto;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: $border-color transparent;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: $border-color;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
// 单个岗位项
|
||||
@@ -21,94 +53,39 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: $bg-white;
|
||||
border-radius: 0.1rem;
|
||||
padding: 0.14rem 0.16rem;
|
||||
flex-wrap: wrap;
|
||||
padding: 0.16rem 0.2rem;
|
||||
border: 1px solid #F0F0F0;
|
||||
border-radius: 0.08rem;
|
||||
margin-bottom: 0.08rem;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s ease;
|
||||
|
||||
&:last-of-type {
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: $accent;
|
||||
}
|
||||
}
|
||||
|
||||
// 左侧信息区域
|
||||
&__info {
|
||||
// 左侧区域(匹配度 + 岗位信息)
|
||||
&__left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.12rem;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.16rem;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
// 公司 Logo
|
||||
&__logo {
|
||||
width: 0.36rem;
|
||||
height: 0.36rem;
|
||||
border-radius: 0.06rem;
|
||||
background: $bg-main;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
color: $text-middle;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 0.2rem;
|
||||
height: 0.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
// 岗位详情
|
||||
&__detail {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
// 公司名称
|
||||
&__company {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
// 岗位名称
|
||||
&__title {
|
||||
font-size: 0.12rem;
|
||||
color: $text-middle;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 0.04rem;
|
||||
}
|
||||
|
||||
// 标签行
|
||||
&__tags {
|
||||
display: flex;
|
||||
gap: 0.06rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
// 单个标签
|
||||
&__tag {
|
||||
font-size: 0.11rem;
|
||||
color: $text-middle;
|
||||
background: $bg-main;
|
||||
padding: 0.02rem 0.08rem;
|
||||
border-radius: 0.03rem;
|
||||
}
|
||||
|
||||
// 匹配度环形容器
|
||||
&__score {
|
||||
width: 0.62rem;
|
||||
height: 0.62rem;
|
||||
position: relative;
|
||||
width: 0.44rem;
|
||||
height: 0.44rem;
|
||||
flex-shrink: 0;
|
||||
margin-left: 0.12rem;
|
||||
}
|
||||
|
||||
// 环形 SVG
|
||||
@@ -123,34 +100,243 @@
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 0.11rem;
|
||||
font-weight: 600;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 630;
|
||||
color: #9FD051;
|
||||
line-height: 0.22rem;
|
||||
}
|
||||
|
||||
// 岗位详情区域
|
||||
&__detail {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
gap: 0.24rem;
|
||||
}
|
||||
|
||||
// 岗位标题行(岗位名 + 公司)
|
||||
&__title-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.32rem;
|
||||
}
|
||||
|
||||
// 岗位名称
|
||||
&__title {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 620;
|
||||
color: $text-dark;
|
||||
line-height: 0.27rem;
|
||||
}
|
||||
|
||||
// 公司信息容器
|
||||
&__company {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.08rem;
|
||||
}
|
||||
|
||||
// 公司 Logo
|
||||
&__company-logo {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
border-radius: 0.04rem;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
// 公司名称
|
||||
&__company-name {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 330;
|
||||
color: $text-dark;
|
||||
line-height: 0.27rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
// 标签行
|
||||
&__tags {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.12rem;
|
||||
}
|
||||
|
||||
// 单个标签
|
||||
&__tag {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 330;
|
||||
color: $text-middle;
|
||||
line-height: 0.19rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.02rem;
|
||||
|
||||
svg {
|
||||
width: 0.16rem;
|
||||
height: 0.16rem;
|
||||
color: $text-middle;
|
||||
}
|
||||
|
||||
// 招聘分类标签(校招等)
|
||||
&--category {
|
||||
padding: 0.02rem 0.04rem;
|
||||
background: #EDF9FA;
|
||||
border-radius: 0.04rem;
|
||||
font-size: 0.12rem;
|
||||
color: $accent;
|
||||
}
|
||||
}
|
||||
|
||||
// 右侧操作按钮区域
|
||||
&__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.08rem;
|
||||
flex-shrink: 0;
|
||||
margin-left: 0.16rem;
|
||||
}
|
||||
|
||||
// 不再推荐按钮
|
||||
&__dismiss-btn {
|
||||
height: 0.35rem;
|
||||
padding: 0 0.12rem;
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 620;
|
||||
color: $accent;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
transition: opacity 0.2s ease;
|
||||
border-radius: 0.08rem;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
// 加入投递按钮
|
||||
&__add-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.04rem;
|
||||
height: 0.35rem;
|
||||
padding: 0 0.12rem;
|
||||
background: $accent;
|
||||
color: $bg-white;
|
||||
border: none;
|
||||
border-radius: 0.08rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 620;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
svg {
|
||||
width: 0.16rem;
|
||||
height: 0.16rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
// 已加入状态
|
||||
&--added {
|
||||
background: transparent;
|
||||
color: $accent;
|
||||
border: 1px solid $accent;
|
||||
}
|
||||
}
|
||||
|
||||
// 空状态
|
||||
&__empty {
|
||||
text-align: center;
|
||||
color: $text-light;
|
||||
padding: 0.4rem 0;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
// 底部按钮区域
|
||||
&__footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 0.14rem;
|
||||
gap: 0.32rem;
|
||||
margin-top: 0.24rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
// 查看全部岗位按钮
|
||||
&__view-all-btn {
|
||||
height: 0.38rem;
|
||||
padding: 0 0.32rem;
|
||||
background: $btn-dark;
|
||||
color: $bg-white;
|
||||
border: none;
|
||||
border-radius: 0.19rem;
|
||||
font-size: 0.13rem;
|
||||
font-weight: 500;
|
||||
// 换一批按钮
|
||||
&__refresh-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.04rem;
|
||||
height: 0.43rem;
|
||||
padding: 0 0.16rem;
|
||||
min-width: 2.8rem;
|
||||
background: $bg-white;
|
||||
color: $accent;
|
||||
border: 1px solid $accent;
|
||||
border-radius: 0.22rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 620;
|
||||
cursor: pointer;
|
||||
transition: all 0.25s ease;
|
||||
line-height: 0.38rem;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
svg {
|
||||
width: 0.16rem;
|
||||
height: 0.16rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $btn-dark-hover;
|
||||
background: #EDF9FA;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
// 全部添加按钮
|
||||
&__add-all-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.04rem;
|
||||
height: 0.43rem;
|
||||
padding: 0 0.16rem;
|
||||
min-width: 2.8rem;
|
||||
background: $accent;
|
||||
color: $bg-white;
|
||||
border: none;
|
||||
border-radius: 0.22rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 620;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
svg {
|
||||
width: 0.16rem;
|
||||
height: 0.16rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
&:active {
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
@use '../variables' as *;
|
||||
|
||||
/* Agent岗位预览抽屉 — 从浏览器右侧弹出 */
|
||||
|
||||
/* 遮罩层 */
|
||||
.agent-job-drawer-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: var(--app-height, 100vh);
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
z-index: 2000;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* 抽屉主体 */
|
||||
.agent-job-drawer {
|
||||
width: 6.4rem;
|
||||
height: var(--app-height, 100vh);
|
||||
background: $bg-white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 0.14rem;
|
||||
box-shadow: -4px 0 20px rgba(0, 0, 0, 0.08);
|
||||
|
||||
/* 顶部标题栏 */
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.2rem 0.24rem;
|
||||
height: 0.64rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&__header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.16rem;
|
||||
}
|
||||
|
||||
/* 关闭按钮 */
|
||||
&__close {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__close-icon {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
color: $text-middle;
|
||||
}
|
||||
|
||||
/* 标题文字 */
|
||||
&__title {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 620;
|
||||
color: $text-dark;
|
||||
line-height: 0.24rem;
|
||||
}
|
||||
|
||||
/* 内容区域(可滚动) */
|
||||
&__body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0.24rem;
|
||||
}
|
||||
|
||||
/* 岗位标题区域 */
|
||||
&__job-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 0.24rem;
|
||||
margin-bottom: 0.24rem;
|
||||
}
|
||||
|
||||
&__job-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 岗位标题 */
|
||||
&__job-title {
|
||||
font-size: 0.24rem;
|
||||
font-weight: 620;
|
||||
color: $text-dark;
|
||||
line-height: 0.32rem;
|
||||
margin: 0 0 0.08rem;
|
||||
}
|
||||
|
||||
/* 元信息 */
|
||||
&__meta {
|
||||
font-size: 0.12rem;
|
||||
color: $text-middle;
|
||||
line-height: 0.16rem;
|
||||
font-weight: 330;
|
||||
}
|
||||
|
||||
/* 匹配度环 */
|
||||
&__match {
|
||||
position: relative;
|
||||
width: 0.62rem;
|
||||
height: 0.62rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__ring-svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&__match-text {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 0.14rem;
|
||||
font-weight: 630;
|
||||
color: #9FD051;
|
||||
}
|
||||
|
||||
/* 内容段落 */
|
||||
&__section {
|
||||
margin-bottom: 0.24rem;
|
||||
}
|
||||
|
||||
&__section-title {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
line-height: 0.24rem;
|
||||
margin-bottom: 0.16rem;
|
||||
|
||||
/* 加分项标题样式 */
|
||||
&--bonus {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 330;
|
||||
color: $text-dark;
|
||||
line-height: 0.19rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__section-content {
|
||||
font-size: 0.14rem;
|
||||
color: $text-middle;
|
||||
line-height: 0.19rem;
|
||||
font-weight: 330;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* 技能标签 */
|
||||
&__tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.08rem;
|
||||
margin-bottom: 0.12rem;
|
||||
}
|
||||
|
||||
&__tag {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0.04rem 0.06rem;
|
||||
background: $bg-main;
|
||||
border-radius: 0.04rem;
|
||||
font-size: 0.12rem;
|
||||
color: $text-middle;
|
||||
line-height: 0.18rem;
|
||||
font-weight: 330;
|
||||
}
|
||||
|
||||
/* 公司概况 */
|
||||
&__company {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.12rem;
|
||||
}
|
||||
|
||||
&__company-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.12rem;
|
||||
}
|
||||
|
||||
&__company-logo {
|
||||
width: 0.48rem;
|
||||
height: 0.48rem;
|
||||
border-radius: 0.08rem;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
background: #EDF9FA;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 0.32rem;
|
||||
height: 0.32rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__company-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.06rem;
|
||||
}
|
||||
|
||||
&__company-name {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 620;
|
||||
color: $text-dark;
|
||||
line-height: 0.24rem;
|
||||
}
|
||||
|
||||
&__company-detail {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 400;
|
||||
color: $text-middle;
|
||||
line-height: 0.19rem;
|
||||
}
|
||||
|
||||
&__company-desc {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 330;
|
||||
color: $text-middle;
|
||||
line-height: 0.24rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 抽屉动画 */
|
||||
.agent-job-drawer-enter-active,
|
||||
.agent-job-drawer-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
|
||||
.agent-job-drawer {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.agent-job-drawer-enter-from,
|
||||
.agent-job-drawer-leave-to {
|
||||
opacity: 0;
|
||||
|
||||
.agent-job-drawer {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
@@ -110,6 +110,7 @@
|
||||
gap: 0.12rem;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// 公司 Logo
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
@use '../variables' as *;
|
||||
|
||||
/* 待投递岗位列表面板样式 */
|
||||
.agent-pending-job-list-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
background: $bg-white;
|
||||
border-radius: 0.2rem;
|
||||
overflow: hidden;
|
||||
|
||||
/* 顶部标题栏 */
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.16rem 0.2rem;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 0.16rem;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
/* 关闭按钮 */
|
||||
&__close-btn {
|
||||
width: 0.28rem;
|
||||
height: 0.28rem;
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* 列表区域(可滚动) */
|
||||
&__list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0 0.2rem 0.2rem;
|
||||
}
|
||||
|
||||
/* 单个岗位项 */
|
||||
&__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.14rem 0.16rem;
|
||||
background: $bg-main;
|
||||
border-radius: 0.12rem;
|
||||
margin-bottom: 0.1rem;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 左侧信息区域 */
|
||||
&__info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.12rem;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 公司 Logo */
|
||||
&__logo {
|
||||
width: 0.4rem;
|
||||
height: 0.4rem;
|
||||
border-radius: 0.08rem;
|
||||
background: $bg-middle;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
|
||||
svg {
|
||||
width: 0.22rem;
|
||||
height: 0.22rem;
|
||||
color: $text-middle;
|
||||
}
|
||||
}
|
||||
|
||||
/* 岗位详情 */
|
||||
&__detail {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&__company {
|
||||
font-size: 0.13rem;
|
||||
font-weight: 500;
|
||||
color: $text-dark;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&__position {
|
||||
font-size: 0.12rem;
|
||||
color: $text-middle;
|
||||
margin-top: 0.02rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* 标签 */
|
||||
&__tags {
|
||||
display: flex;
|
||||
gap: 0.06rem;
|
||||
margin-top: 0.06rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&__tag {
|
||||
font-size: 0.11rem;
|
||||
color: $text-middle;
|
||||
background: $bg-white;
|
||||
padding: 0.02rem 0.08rem;
|
||||
border-radius: 0.04rem;
|
||||
}
|
||||
|
||||
/* 右侧区域 */
|
||||
&__right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.14rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 匹配度环 */
|
||||
&__score {
|
||||
position: relative;
|
||||
width: 0.4rem;
|
||||
height: 0.4rem;
|
||||
}
|
||||
|
||||
&__ring {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&__score-text {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 0.1rem;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
/* 移出按钮 */
|
||||
&__remove-btn {
|
||||
padding: 0.06rem 0.16rem;
|
||||
background: $text-dark;
|
||||
color: $bg-white;
|
||||
border: none;
|
||||
border-radius: 0.2rem;
|
||||
font-size: 0.12rem;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
/* 加载中 */
|
||||
&__loading {
|
||||
text-align: center;
|
||||
padding: 0.16rem 0;
|
||||
font-size: 0.12rem;
|
||||
color: $text-light;
|
||||
}
|
||||
|
||||
/* 暂无更多数据 */
|
||||
&__no-more {
|
||||
text-align: center;
|
||||
padding: 0.16rem 0;
|
||||
font-size: 0.12rem;
|
||||
color: $text-light;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
&__empty {
|
||||
text-align: center;
|
||||
padding: 0.4rem 0;
|
||||
font-size: 0.13rem;
|
||||
color: $text-light;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,632 @@
|
||||
@use '../variables' as *;
|
||||
|
||||
// ==================== Agent设置面板样式(重新设计) ====================
|
||||
.agent-setting-panel {
|
||||
position: relative;
|
||||
width: 3.60rem;
|
||||
height: var(--app-height, 100vh);
|
||||
background: #FFFFFF;
|
||||
font-size: 0.14rem;
|
||||
overflow-y: auto;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
&::-webkit-scrollbar { display: none; }
|
||||
|
||||
// 头部标题区
|
||||
&__header {
|
||||
padding: 0.24rem 0.24rem 0;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 0.20rem;
|
||||
font-weight: 630;
|
||||
line-height: 0.27rem;
|
||||
color: #1A1A1A;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
margin-top: 0.04rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 330;
|
||||
line-height: 0.19rem;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
// 分隔线
|
||||
&__divider {
|
||||
width: 3.12rem;
|
||||
height: 1px;
|
||||
margin: 0.24rem auto;
|
||||
background: #F0F0F0;
|
||||
}
|
||||
|
||||
// 通用区块
|
||||
&__section {
|
||||
padding: 0 0.24rem;
|
||||
margin-bottom: 0.08rem;
|
||||
}
|
||||
|
||||
// 区块头部
|
||||
&__section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.08rem;
|
||||
}
|
||||
|
||||
// 区块标题
|
||||
&__section-title {
|
||||
font-size: 0.16rem;
|
||||
font-weight: 620;
|
||||
line-height: 0.21rem;
|
||||
color: #1A1A1A;
|
||||
}
|
||||
|
||||
// 编辑按钮
|
||||
&__edit-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.04rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
color: $accent;
|
||||
cursor: pointer;
|
||||
|
||||
svg {
|
||||
width: 0.14rem;
|
||||
height: 0.14rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
// 个人信息文字
|
||||
&__info-text {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 330;
|
||||
line-height: 0.19rem;
|
||||
color: $text-middle;
|
||||
}
|
||||
|
||||
// 求职偏好内容
|
||||
&__goal-content {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 330;
|
||||
line-height: 0.24rem;
|
||||
color: $text-middle;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 空状态
|
||||
&__empty-text {
|
||||
font-size: 0.14rem;
|
||||
color: $text-light;
|
||||
}
|
||||
|
||||
// 简历下拉
|
||||
&__resume-dropdown {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.08rem 0.12rem;
|
||||
margin-top: 0.08rem;
|
||||
background: #F3F4F6;
|
||||
border-radius: 0.08rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__resume-name {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
color: $text-middle;
|
||||
}
|
||||
|
||||
&__resume-arrow {
|
||||
width: 0.14rem;
|
||||
height: 0.14rem;
|
||||
transition: transform 0.2s;
|
||||
|
||||
&--open {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
&__resume-options {
|
||||
margin-top: 0.04rem;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #F0F0F0;
|
||||
border-radius: 0.08rem;
|
||||
box-shadow: 0 0.02rem 0.08rem rgba(0, 0, 0, 0.06);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__resume-option {
|
||||
padding: 0.08rem 0.12rem;
|
||||
font-size: 0.14rem;
|
||||
color: $text-dark;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: #F6FCFC;
|
||||
}
|
||||
|
||||
&--active {
|
||||
color: $accent;
|
||||
background: #F6FCFC;
|
||||
}
|
||||
}
|
||||
|
||||
// 开关项
|
||||
&__switch-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.16rem 0;
|
||||
}
|
||||
|
||||
&__switch-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.04rem;
|
||||
}
|
||||
|
||||
&__switch-label {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
line-height: 0.19rem;
|
||||
color: #1A1A1A;
|
||||
}
|
||||
|
||||
&__switch-desc {
|
||||
font-size: 0.12rem;
|
||||
font-weight: 330;
|
||||
line-height: 0.16rem;
|
||||
color: $text-middle;
|
||||
}
|
||||
|
||||
// 自定义开关
|
||||
&__toggle {
|
||||
position: relative;
|
||||
width: 0.42rem;
|
||||
height: 0.24rem;
|
||||
background: #F3F4F6;
|
||||
border-radius: 0.12rem;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
flex-shrink: 0;
|
||||
|
||||
&--on {
|
||||
background: $accent;
|
||||
|
||||
.agent-setting-panel__toggle-dot {
|
||||
left: 0.20rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__toggle-dot {
|
||||
position: absolute;
|
||||
width: 0.18rem;
|
||||
height: 0.18rem;
|
||||
left: 0.04rem;
|
||||
top: 0.03rem;
|
||||
background: #FFFFFF;
|
||||
border-radius: 50%;
|
||||
transition: left 0.2s;
|
||||
}
|
||||
|
||||
// 浏览器插件按钮
|
||||
&__browser-btns {
|
||||
display: flex;
|
||||
gap: 0.16rem;
|
||||
margin-top: 0.12rem;
|
||||
}
|
||||
|
||||
&__browser-btn {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.04rem;
|
||||
padding: 0.12rem 0.16rem;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #F0F0F0;
|
||||
border-radius: 0.08rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
color: $text-middle;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s;
|
||||
|
||||
svg {
|
||||
width: 0.16rem;
|
||||
height: 0.16rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: $accent;
|
||||
}
|
||||
|
||||
&--active {
|
||||
border-color: $accent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==================== 编辑弹窗 ====================
|
||||
&__edit-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
z-index: 2000;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-end;
|
||||
padding-top: 1.20rem;
|
||||
padding-right: 0.30rem;
|
||||
}
|
||||
|
||||
&__edit-dialog {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
padding: 0.24rem 0.32rem;
|
||||
gap: 0.24rem;
|
||||
width: 4.80rem;
|
||||
background: linear-gradient(180deg, #EDF9FA 0%, #FFFFFF 20.63%);
|
||||
border: 1px solid #F0F0F0;
|
||||
box-shadow: 0 0 0.16rem rgba(0, 0, 0, 0.05);
|
||||
border-radius: 0.12rem;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
&__edit-dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__edit-dialog-title {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 620;
|
||||
line-height: 0.24rem;
|
||||
color: #1A1A1A;
|
||||
}
|
||||
|
||||
&__edit-dialog-close {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
&__edit-dialog-body {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.16rem;
|
||||
}
|
||||
|
||||
&__edit-row {
|
||||
display: flex;
|
||||
gap: 0.08rem;
|
||||
}
|
||||
|
||||
&__edit-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.08rem;
|
||||
flex: 1;
|
||||
|
||||
&--full {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&__edit-label {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 330;
|
||||
line-height: 0.19rem;
|
||||
color: $text-middle;
|
||||
}
|
||||
|
||||
&__edit-input {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 0.08rem 0.16rem;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #AEE6EA;
|
||||
border-radius: 0.08rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 330;
|
||||
line-height: 0.19rem;
|
||||
color: #1A1A1A;
|
||||
outline: none;
|
||||
transition: border-color 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: $accent;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: $text-light;
|
||||
}
|
||||
}
|
||||
|
||||
&__edit-city {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__edit-dialog-save {
|
||||
width: 100%;
|
||||
padding: 0.12rem 0.16rem;
|
||||
background: $accent;
|
||||
border: none;
|
||||
border-radius: 0.08rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
line-height: 0.19rem;
|
||||
color: #FFFFFF;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 浏览器插件安装教程抽屉 ====================
|
||||
|
||||
/* 遮罩层 */
|
||||
.agent-browser-guide-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: var(--app-height, 100vh);
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
z-index: 2000;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* 抽屉主体 */
|
||||
.agent-browser-guide-drawer {
|
||||
width: 9.6rem;
|
||||
max-width: 9.6rem;
|
||||
height: var(--app-height, 100vh);
|
||||
background: $bg-white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 0.14rem;
|
||||
box-shadow: -4px 0 20px rgba(0, 0, 0, 0.08);
|
||||
|
||||
/* 顶部标题栏 */
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.2rem 0.24rem;
|
||||
height: 0.64rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&__header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.16rem;
|
||||
}
|
||||
|
||||
&__close {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__close-icon {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
color: $text-middle;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 620;
|
||||
color: $text-dark;
|
||||
line-height: 0.24rem;
|
||||
}
|
||||
|
||||
/* 内容区域 */
|
||||
&__body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0 0.32rem 0.32rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.16rem;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
/* 步骤卡片 */
|
||||
&__card {
|
||||
border: 1px solid #F0F0F0;
|
||||
border-radius: 0.12rem;
|
||||
padding: 0.16rem 0.2rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&__step-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.12rem;
|
||||
margin-bottom: 0.16rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
&__step-num {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 0.32rem;
|
||||
height: 0.32rem;
|
||||
background: #EDF9FA;
|
||||
border-radius: 0.08rem;
|
||||
font-size: 0.18rem;
|
||||
font-weight: 620;
|
||||
color: $accent;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__step-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__step-title {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 620;
|
||||
color: $text-dark;
|
||||
line-height: 0.24rem;
|
||||
margin: 0 0 0.04rem;
|
||||
}
|
||||
|
||||
&__step-desc {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 330;
|
||||
color: $text-middle;
|
||||
line-height: 0.19rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 下载按钮区域 */
|
||||
&__download-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.16rem;
|
||||
padding: 0.04rem 0.04rem 0.04rem 0.16rem;
|
||||
background: $bg-main;
|
||||
border-radius: 0.12rem;
|
||||
height: 0.44rem;
|
||||
margin-left: 0.4rem;
|
||||
}
|
||||
|
||||
&__download-name {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
color: $text-dark;
|
||||
line-height: 0.19rem;
|
||||
}
|
||||
|
||||
&__download-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.04rem;
|
||||
padding: 0.08rem 0.12rem;
|
||||
background: $accent;
|
||||
border: none;
|
||||
border-radius: 0.08rem;
|
||||
color: $bg-white;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 620;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: $accent-hover;
|
||||
}
|
||||
}
|
||||
|
||||
/* 浏览器链接区域 */
|
||||
&__browser-links {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.24rem;
|
||||
margin-bottom: 0.16rem;
|
||||
margin-left: 0.4rem;
|
||||
}
|
||||
|
||||
&__browser-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.04rem;
|
||||
padding: 0.12rem 0.16rem;
|
||||
background: $bg-white;
|
||||
border: 1px solid #F0F0F0;
|
||||
border-radius: 0.08rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
color: $text-middle;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
border-color: $accent;
|
||||
}
|
||||
|
||||
svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
span {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
&__copy-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.04rem;
|
||||
color: $accent;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
margin-left: 0.12rem;
|
||||
}
|
||||
|
||||
/* 步骤示意图 */
|
||||
&__step-img {
|
||||
width: 100%;
|
||||
max-width: 3.52rem;
|
||||
border-radius: 0.08rem;
|
||||
margin-top: 0.12rem;
|
||||
margin-left: 0.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 抽屉动画 */
|
||||
.agent-browser-guide-drawer-enter-active,
|
||||
.agent-browser-guide-drawer-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
|
||||
.agent-browser-guide-drawer {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.agent-browser-guide-drawer-enter-from,
|
||||
.agent-browser-guide-drawer-leave-to {
|
||||
opacity: 0;
|
||||
|
||||
.agent-browser-guide-drawer {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
@use '../variables' as *;
|
||||
|
||||
/* 投递任务抽屉 — 从浏览器右侧弹出 */
|
||||
|
||||
/* 遮罩层 */
|
||||
.agent-task-drawer-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: var(--app-height, 100vh);
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
z-index: 2000;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* 抽屉主体 */
|
||||
.agent-task-drawer {
|
||||
width: 6.4rem;
|
||||
height: var(--app-height, 100vh);
|
||||
background: $bg-white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 0.14rem;
|
||||
box-shadow: -4px 0 20px rgba(0, 0, 0, 0.08);
|
||||
|
||||
/* 顶部标题栏 */
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.2rem 0.24rem;
|
||||
height: 0.64rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&__header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.16rem;
|
||||
}
|
||||
|
||||
/* 关闭按钮 */
|
||||
&__close {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__close-icon {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
color: $text-middle;
|
||||
}
|
||||
|
||||
/* 标题文字 */
|
||||
&__title {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 620;
|
||||
color: $text-dark;
|
||||
line-height: 0.24rem;
|
||||
}
|
||||
|
||||
/* Tab 切换按钮区域 */
|
||||
&__tabs {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.16rem;
|
||||
padding: 0 0.24rem 0.2rem;
|
||||
}
|
||||
|
||||
&__tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.08rem 0.12rem;
|
||||
gap: 0.04rem;
|
||||
border-radius: 0.08rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
line-height: 0.19rem;
|
||||
cursor: pointer;
|
||||
border: 1px solid #F0F0F0;
|
||||
background: $bg-white;
|
||||
color: $text-middle;
|
||||
transition: all 0.2s;
|
||||
|
||||
&--active {
|
||||
background: $accent;
|
||||
color: $bg-white;
|
||||
border-color: $accent;
|
||||
}
|
||||
}
|
||||
|
||||
/* 列表内容区域 */
|
||||
&__body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0 0.24rem 0.2rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.16rem;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
&__empty {
|
||||
text-align: center;
|
||||
color: $text-light;
|
||||
font-size: 0.14rem;
|
||||
padding: 0.4rem 0;
|
||||
}
|
||||
|
||||
/* 岗位卡片 */
|
||||
&__card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.16rem 0.2rem;
|
||||
background: $bg-white;
|
||||
border: 1px solid #F0F0F0;
|
||||
border-radius: 0.08rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&__card-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.12rem;
|
||||
}
|
||||
|
||||
/* 岗位标题 */
|
||||
&__card-title {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 620;
|
||||
color: $text-dark;
|
||||
line-height: 0.27rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 公司信息行 */
|
||||
&__card-company {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.08rem;
|
||||
font-size: 0.18rem;
|
||||
font-weight: 330;
|
||||
color: $text-dark;
|
||||
line-height: 0.27rem;
|
||||
}
|
||||
|
||||
&__card-logo {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
border-radius: 0.04rem;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__card-logo-placeholder {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
color: $text-light;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 移出任务按钮 */
|
||||
&__remove-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.08rem 0.12rem;
|
||||
gap: 0.04rem;
|
||||
border: 1px solid $accent;
|
||||
border-radius: 0.08rem;
|
||||
background: $bg-white;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
color: $accent;
|
||||
line-height: 0.19rem;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
transition: all 0.2s;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:hover {
|
||||
background: $accent;
|
||||
color: $bg-white;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 抽屉动画 */
|
||||
.agent-task-drawer-enter-active,
|
||||
.agent-task-drawer-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
|
||||
.agent-task-drawer {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.agent-task-drawer-enter-from,
|
||||
.agent-task-drawer-leave-to {
|
||||
opacity: 0;
|
||||
|
||||
.agent-task-drawer {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
@use '../variables' as *;
|
||||
|
||||
// 协议预览弹窗样式
|
||||
.agreement-preview-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 2500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.agreement-preview-dialog {
|
||||
width: 7rem;
|
||||
max-width: 90vw;
|
||||
height: 80vh;
|
||||
background: #fff;
|
||||
border-radius: 0.12rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
// 顶部标题栏
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.16rem 0.24rem;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 0.18rem;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&__close {
|
||||
font-size: 0.18rem;
|
||||
color: #9ca3af;
|
||||
cursor: pointer;
|
||||
padding: 0.04rem;
|
||||
transition: color 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: #374151;
|
||||
}
|
||||
}
|
||||
|
||||
// 内容区域
|
||||
&__body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0.24rem;
|
||||
}
|
||||
|
||||
&__loading {
|
||||
text-align: center;
|
||||
padding: 0.4rem 0;
|
||||
color: #999;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
// Markdown 渲染内容样式
|
||||
&__content {
|
||||
font-size: 0.13rem;
|
||||
color: #555;
|
||||
line-height: 1.8;
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: $text-dark;
|
||||
font-weight: 600;
|
||||
margin: 0.14rem 0 0.08rem;
|
||||
}
|
||||
h1 { font-size: 0.2rem; }
|
||||
h2 { font-size: 0.17rem; }
|
||||
h3 { font-size: 0.15rem; }
|
||||
h4 { font-size: 0.14rem; }
|
||||
|
||||
p {
|
||||
margin: 0 0 0.08rem;
|
||||
text-align: justify;
|
||||
&:last-child { margin-bottom: 0; }
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
padding-left: 0.2rem;
|
||||
margin: 0.06rem 0;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 0.04rem;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 700;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #2563eb;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid #cbd5e1;
|
||||
padding-left: 0.1rem;
|
||||
margin: 0.08rem 0;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 0.1rem 0;
|
||||
font-size: 0.12rem;
|
||||
|
||||
th, td {
|
||||
border: 1px solid #e5e7eb;
|
||||
padding: 0.06rem 0.1rem;
|
||||
text-align: left;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
th {
|
||||
background: #f8fafc;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background: #fafbfc;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
margin: 0.1rem 0;
|
||||
}
|
||||
|
||||
code {
|
||||
background: #f1f5f9;
|
||||
padding: 0.01rem 0.04rem;
|
||||
border-radius: 0.03rem;
|
||||
font-size: 0.12rem;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #1e293b;
|
||||
color: #e2e8f0;
|
||||
padding: 0.1rem 0.12rem;
|
||||
border-radius: 0.06rem;
|
||||
overflow-x: auto;
|
||||
margin: 0.08rem 0;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
padding: 0;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,82 +1,119 @@
|
||||
// 颜色变量已移至全局 variables.scss
|
||||
@use '../variables' as *;
|
||||
|
||||
.ai-chat {
|
||||
width: 4.0rem;
|
||||
height: 100vh;
|
||||
background: #f3f4f6;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
font-size: 0.14rem;
|
||||
width: var(--chat-width, 3.6rem);
|
||||
height: var(--app-height, 100vh);
|
||||
background: $bg-white;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
border-left: 1px solid #e5e7eb;
|
||||
|
||||
&__banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #0F172B;
|
||||
color: #fff;
|
||||
padding: 0.12rem 0.18rem;
|
||||
font-size: 0.15rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
border-radius: 0.2rem;
|
||||
margin: 0.15rem;
|
||||
height: 0.41rem;
|
||||
}
|
||||
|
||||
&__banner-arrow {
|
||||
font-size: 0.16rem;
|
||||
padding-bottom: 0.05rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
|
||||
// ==================== 顶部头部区域 ====================
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.1rem;
|
||||
justify-content: space-between;
|
||||
padding: 0.16rem;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
height: 0.80rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&__header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.12rem;
|
||||
}
|
||||
|
||||
&__avatar {
|
||||
width: 0.4rem;
|
||||
height: 0.4rem;
|
||||
width: 0.44rem;
|
||||
height: 0.44rem;
|
||||
border-radius: 50%;
|
||||
background: #e5e7eb;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.2rem;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
&__info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&__name {
|
||||
font-size: 0.16rem;
|
||||
font-weight: 600;
|
||||
color: #1a1a2e;
|
||||
font-size: 0.15rem;
|
||||
font-weight: 620;
|
||||
line-height: 0.22rem;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
&__desc {
|
||||
font-size: 0.12rem;
|
||||
color: #6b7280;
|
||||
margin-top: 0.02rem;
|
||||
font-weight: 330;
|
||||
line-height: 0.18rem;
|
||||
color: #99A1AF;
|
||||
}
|
||||
|
||||
// 在线状态标签
|
||||
&__online-tag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.04rem 0.08rem;
|
||||
gap: 0.04rem;
|
||||
background: #52CAD1;
|
||||
border-radius: 0.12rem;
|
||||
font-size: 0.12rem;
|
||||
font-weight: 330;
|
||||
line-height: 0.16rem;
|
||||
color: $bg-white;
|
||||
}
|
||||
|
||||
&__online-dot {
|
||||
width: 0.06rem;
|
||||
height: 0.06rem;
|
||||
background: $bg-white;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
// ==================== 聊天消息区域 ====================
|
||||
&__messages {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0.16rem;
|
||||
padding: 0 0.16rem;
|
||||
padding-bottom: 0.16rem;
|
||||
}
|
||||
|
||||
// 欢迎气泡
|
||||
&__welcome-bubble {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
padding: 0.16rem;
|
||||
gap: 0.08rem;
|
||||
background: #F4FBFB;
|
||||
border: 1px solid #AEE6EA;
|
||||
border-radius: 0.12rem;
|
||||
margin-bottom: 0.17rem;
|
||||
}
|
||||
|
||||
&__welcome-title {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 620;
|
||||
line-height: 0.16rem;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
&__welcome-text {
|
||||
font-size: 0.12rem;
|
||||
font-weight: 330;
|
||||
line-height: 0.18rem;
|
||||
color: #99A1AF;
|
||||
}
|
||||
|
||||
// ==================== 消息气泡 ====================
|
||||
&__msg {
|
||||
margin-bottom: 0.12rem;
|
||||
margin-bottom: 0.17rem;
|
||||
display: flex;
|
||||
|
||||
&--ai {
|
||||
@@ -89,117 +126,267 @@
|
||||
}
|
||||
|
||||
&__msg-bubble {
|
||||
border-radius: 0.1rem;
|
||||
padding: 0.12rem 0.14rem;
|
||||
font-size: 0.13rem;
|
||||
line-height: 1.6;
|
||||
max-width: 85%;
|
||||
}
|
||||
|
||||
&__msg--ai &__msg-bubble {
|
||||
background: #fff;
|
||||
border: 1px solid #e5e7eb;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
&__msg--user &__msg-bubble {
|
||||
background: #fff;
|
||||
color: #1a1a2e;
|
||||
}
|
||||
|
||||
&__msg-title {
|
||||
font-weight: 600;
|
||||
max-width: 2.8rem;
|
||||
padding: 0.08rem 0.12rem;
|
||||
font-size: 0.14rem;
|
||||
margin-bottom: 0.06rem;
|
||||
color: #1a1a2e;
|
||||
font-weight: 330;
|
||||
line-height: 0.24rem;
|
||||
box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.04);
|
||||
|
||||
// Markdown 渲染样式
|
||||
p {
|
||||
margin: 0 0 0.08rem;
|
||||
&:last-child { margin-bottom: 0; }
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin: 0.12rem 0 0.06rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
}
|
||||
h1 { font-size: 0.18rem; }
|
||||
h2 { font-size: 0.16rem; }
|
||||
h3 { font-size: 0.14rem; }
|
||||
|
||||
ul, ol {
|
||||
padding-left: 0.2rem;
|
||||
margin: 0.06rem 0;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 0.04rem;
|
||||
}
|
||||
|
||||
code {
|
||||
background: #f1f5f9;
|
||||
padding: 0.01rem 0.04rem;
|
||||
border-radius: 0.03rem;
|
||||
font-size: 0.12rem;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #1e293b;
|
||||
color: #e2e8f0;
|
||||
padding: 0.1rem 0.12rem;
|
||||
border-radius: 0.06rem;
|
||||
overflow-x: auto;
|
||||
margin: 0.08rem 0;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
padding: 0;
|
||||
color: inherit;
|
||||
font-size: 0.11rem;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid #cbd5e1;
|
||||
padding-left: 0.1rem;
|
||||
margin: 0.08rem 0;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #2563eb;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
margin: 0.08rem 0;
|
||||
width: 100%;
|
||||
font-size: 0.12rem;
|
||||
|
||||
th, td {
|
||||
border: 1px solid #e5e7eb;
|
||||
padding: 0.06rem 0.1rem;
|
||||
text-align: left;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
th {
|
||||
background: #f8fafc;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__msg-text {
|
||||
color: #6b7280;
|
||||
font-size: 0.12rem;
|
||||
// 用户消息气泡 — 品牌色背景,右上圆角小
|
||||
&__msg--user &__msg-bubble {
|
||||
background: #52CAD1;
|
||||
color: $bg-white;
|
||||
border-radius: 0.12rem 0.04rem 0.12rem 0.12rem;
|
||||
}
|
||||
|
||||
&__quick-questions {
|
||||
// AI 消息气泡 — 白色背景绿色边框,左上圆角小
|
||||
&__msg--ai &__msg-bubble {
|
||||
background: $bg-white;
|
||||
color: $text-dark;
|
||||
border: 1px solid #AEE6EA;
|
||||
box-shadow: 0px 2px 4px rgba(82, 202, 209, 0.1);
|
||||
border-radius: 0.04rem 0.12rem 0.12rem 0.12rem;
|
||||
}
|
||||
|
||||
// ==================== 三点等待动效 ====================
|
||||
&__typing-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.14rem 0.12rem;
|
||||
gap: 0.06rem;
|
||||
background: $bg-white;
|
||||
border: 1px solid #AEE6EA;
|
||||
box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.04);
|
||||
border-radius: 0.04rem 0.12rem 0.12rem 0.12rem;
|
||||
}
|
||||
|
||||
&__typing-dot {
|
||||
width: 0.06rem;
|
||||
height: 0.06rem;
|
||||
border-radius: 50%;
|
||||
background: #AEE6EA;
|
||||
animation: typingBounce 1.4s infinite ease-in-out both;
|
||||
|
||||
&:nth-child(1) {
|
||||
animation-delay: 0s;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
background: rgba(174, 230, 234, 0.6);
|
||||
}
|
||||
&:nth-child(3) {
|
||||
animation-delay: 0.4s;
|
||||
background: rgba(174, 230, 234, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes typingBounce {
|
||||
0%, 80%, 100% {
|
||||
transform: scale(1);
|
||||
opacity: 0.6;
|
||||
}
|
||||
40% {
|
||||
transform: scale(1.3);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 话题推荐模块 ====================
|
||||
&__topics {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.08rem;
|
||||
margin-top: 0.12rem;
|
||||
align-items: flex-start;
|
||||
padding: 0.16rem 0.16rem 0.16rem 0.16rem;
|
||||
gap: 0.12rem;
|
||||
background: linear-gradient(180deg, #EDF9FA 0%, #FFFFFF 20.63%);
|
||||
border: 1px solid #AEE6EA;
|
||||
border-radius: 0.12rem;
|
||||
margin: 0 0.16rem;
|
||||
margin-bottom: 0.12rem;
|
||||
}
|
||||
|
||||
&__quick-item {
|
||||
background: #fff;
|
||||
border: 1px solid #e5e7eb;
|
||||
&__topics-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.04rem;
|
||||
}
|
||||
|
||||
&__topics-icon {
|
||||
width: 0.16rem;
|
||||
height: 0.16rem;
|
||||
}
|
||||
|
||||
&__topics-title {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 620;
|
||||
line-height: 0.19rem;
|
||||
color: #52CAD1;
|
||||
}
|
||||
|
||||
&__topic-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.08rem 0.12rem;
|
||||
background: $bg-white;
|
||||
border: 1px solid #F0F0F0;
|
||||
border-radius: 0.08rem;
|
||||
padding: 0.1rem 0.14rem;
|
||||
color: $text-middle;
|
||||
font-size: 0.12rem;
|
||||
font-weight: 330;
|
||||
line-height: 0.16rem;
|
||||
color: $text-middle;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
max-width: 80%;
|
||||
|
||||
&:hover {
|
||||
background: #f9fafb;
|
||||
color: #374151;
|
||||
background: $accent;
|
||||
color: #fff;
|
||||
|
||||
}
|
||||
|
||||
/* AI 提问靠左 */
|
||||
&--ai {
|
||||
align-self: flex-start;
|
||||
}
|
||||
// 第一个按钮用品牌色
|
||||
&--primary {
|
||||
background: #52CAD1;
|
||||
border-color: #52CAD1;
|
||||
color: $bg-white;
|
||||
|
||||
/* 用户提问靠右 */
|
||||
&--user {
|
||||
align-self: flex-end;
|
||||
background: #f0f3f6;
|
||||
border-color: #e0e3e6;
|
||||
&:hover {
|
||||
background: #47b8bf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 底部输入框 ====================
|
||||
&__input-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.08rem 0.12rem;
|
||||
gap: 0.08rem;
|
||||
padding: 0.12rem 0.16rem;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
background: #fff;
|
||||
margin: 0 0.16rem;
|
||||
margin-bottom: 0.16rem;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border: 1px solid #AEE6EA;
|
||||
border-radius: 0.08rem;
|
||||
backdrop-filter: blur(12px);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&__input {
|
||||
flex: 1;
|
||||
background: #f3f4f6;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 0.06rem;
|
||||
padding: 0.1rem 0.12rem;
|
||||
color: #1a1a2e;
|
||||
font-size: 0.12rem;
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
font-size: 0.12rem;
|
||||
font-weight: 400;
|
||||
line-height: 0.15rem;
|
||||
color: $text-dark;
|
||||
|
||||
&::placeholder {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: #9ca3af;
|
||||
color: #99A1AF;
|
||||
}
|
||||
}
|
||||
|
||||
&__send-btn {
|
||||
width: 0.36rem;
|
||||
height: 0.36rem;
|
||||
border-radius: 50%;
|
||||
background: #1a1a2e;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 0.16rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 0.32rem;
|
||||
height: 0.32rem;
|
||||
background: #52CAD1;
|
||||
border-radius: 0.08rem;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
transition: background 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: #2e3142;
|
||||
background: #47b8bf;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,145 +1,125 @@
|
||||
@use '../variables' as *;
|
||||
|
||||
// ==================== 求职偏好弹窗样式(重新设计) ====================
|
||||
|
||||
// 遮罩层 — 右上角定位
|
||||
.job-goal-dialog__overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
z-index: 2000;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-end;
|
||||
padding-top: 1.20rem;
|
||||
padding-right: 0.30rem;
|
||||
}
|
||||
|
||||
.job-goal-dialog {
|
||||
.el-dialog__header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 0;
|
||||
}
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
padding: 0.24rem 0.32rem;
|
||||
gap: 0.24rem;
|
||||
width: 4.80rem;
|
||||
background: linear-gradient(180deg, #EDF9FA 0%, #FFFFFF 20.63%);
|
||||
border: 1px solid #F0F0F0;
|
||||
box-shadow: 0 0 0.16rem rgba(0, 0, 0, 0.05);
|
||||
border-radius: 0.12rem;
|
||||
font-size: 0.14rem;
|
||||
|
||||
// 头部
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.12rem;
|
||||
padding: 0.2rem 0.24rem 0.16rem;
|
||||
}
|
||||
|
||||
&__close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: $text-dark;
|
||||
font-size: 0.16rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.04rem;
|
||||
border-radius: 0.04rem;
|
||||
transition: background 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: $bg-main;
|
||||
}
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 0.16rem;
|
||||
font-weight: 700;
|
||||
color: $text-dark;
|
||||
font-size: 0.18rem;
|
||||
font-weight: 620;
|
||||
line-height: 0.24rem;
|
||||
color: #1A1A1A;
|
||||
}
|
||||
|
||||
&__close-btn {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
// 表单区块
|
||||
&__section {
|
||||
padding: 0.12rem 0.24rem;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.08rem;
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
margin-bottom: 0.12rem;
|
||||
}
|
||||
|
||||
&__tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.08rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
&__tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.06rem;
|
||||
background: $bg-main;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 0.16rem;
|
||||
padding: 0.05rem 0.12rem;
|
||||
font-size: 0.13rem;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
&__tag-close {
|
||||
cursor: pointer;
|
||||
font-size: 0.12rem;
|
||||
color: $text-light;
|
||||
transition: color 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: $danger;
|
||||
}
|
||||
}
|
||||
|
||||
&__select {
|
||||
width: 100%;
|
||||
|
||||
.el-select__wrapper {
|
||||
background: $bg-main;
|
||||
border-radius: 0.08rem;
|
||||
box-shadow: none;
|
||||
border: 1px solid $border-color;
|
||||
}
|
||||
font-weight: 330;
|
||||
line-height: 0.19rem;
|
||||
color: $text-middle;
|
||||
}
|
||||
|
||||
// 招聘类型按钮组
|
||||
&__type-group {
|
||||
display: flex;
|
||||
gap: 0.12rem;
|
||||
gap: 0.10rem;
|
||||
}
|
||||
|
||||
&__type-btn {
|
||||
flex: 1;
|
||||
padding: 0.1rem 0;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 0.2rem;
|
||||
background: $bg-white;
|
||||
color: $text-dark;
|
||||
font-size: 0.13rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.08rem 0.16rem;
|
||||
width: 0.96rem;
|
||||
height: 0.35rem;
|
||||
background: #F3F4F6;
|
||||
border: none;
|
||||
border-radius: 0.08rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 330;
|
||||
color: #1A1A1A;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
border-color: $text-light;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&--active {
|
||||
background: $btn-dark;
|
||||
border-color: $btn-dark;
|
||||
color: $bg-white;
|
||||
font-weight: 500;
|
||||
background: $accent;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
padding: 0.3rem 0.24rem 0.24rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
// 保存按钮
|
||||
&__save-btn {
|
||||
width: 100%;
|
||||
padding: 0.12rem 0;
|
||||
padding: 0.12rem 0.16rem;
|
||||
background: $accent;
|
||||
color: $bg-white;
|
||||
border: none;
|
||||
border-radius: 0.24rem;
|
||||
font-size: 0.16rem;
|
||||
font-weight: 600;
|
||||
border-radius: 0.08rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 450;
|
||||
line-height: 0.19rem;
|
||||
color: #FFFFFF;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: $accent-hover;
|
||||
opacity: 0.85;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,91 @@
|
||||
@use '../variables' as *;
|
||||
|
||||
/* ==================== 岗位统计卡片 ==================== */
|
||||
.job-stats-cards {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.16rem;
|
||||
margin-left: auto;
|
||||
filter: drop-shadow(0px 2px 10px rgba(0, 221, 179, 0.16));
|
||||
|
||||
/* 全网实时岗位卡片 */
|
||||
&__count-card {
|
||||
position: relative;
|
||||
height: 0.43rem;
|
||||
background: #0A171C;
|
||||
border: 1px solid #1C4C55;
|
||||
border-radius: 0.05rem;
|
||||
}
|
||||
|
||||
/* 状态指示圆点 */
|
||||
&__dot {
|
||||
//position: absolute;
|
||||
width: 0.08rem;
|
||||
height: 0.08rem;
|
||||
background: #2FE9F4;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0px 0px 4px rgba(47, 233, 244, 0.75);
|
||||
}
|
||||
|
||||
/* 岗位数字 */
|
||||
&__count-num {
|
||||
|
||||
font-family: 'MiSans';
|
||||
font-weight: 630;
|
||||
font-size: 0.16rem;
|
||||
line-height: 0.21rem;
|
||||
color: #F4FFFF;
|
||||
}
|
||||
|
||||
/* 岗位标签文字 */
|
||||
&__count-label {
|
||||
font-family: 'MiSans';
|
||||
font-weight: 330;
|
||||
font-size: 0.10rem;
|
||||
line-height: 0.13rem;
|
||||
color: #8AA8AF;
|
||||
}
|
||||
|
||||
/* 可投率卡片 */
|
||||
&__match-card {
|
||||
position: relative;
|
||||
width: 0.52rem;
|
||||
height: 0.42rem;
|
||||
background: #08161B;
|
||||
border: 1px solid #20626D;
|
||||
border-radius: 0.05rem;
|
||||
}
|
||||
|
||||
/* 可投率数字 */
|
||||
&__match-num {
|
||||
position: absolute;
|
||||
left: 0.08rem;
|
||||
top: 0.04rem;
|
||||
font-family: 'MiSans';
|
||||
font-weight: 630;
|
||||
font-size: 0.16rem;
|
||||
line-height: 0.21rem;
|
||||
color: #2FE9F4;
|
||||
}
|
||||
|
||||
/* 可投率标签文字 */
|
||||
&__match-label {
|
||||
position: absolute;
|
||||
left: 0.08rem;
|
||||
top: 0.245rem;
|
||||
font-family: 'MiSans';
|
||||
font-weight: 620;
|
||||
font-size: 0.10rem;
|
||||
line-height: 0.13rem;
|
||||
color: #8FB7BE;
|
||||
}
|
||||
}
|
||||
|
||||
.job-page-header {
|
||||
margin-bottom: 0;
|
||||
|
||||
|
||||
&__title {
|
||||
font-size: 0.24rem;
|
||||
font-size: 0.18rem;
|
||||
font-weight: 700;
|
||||
color: $text-dark;
|
||||
margin: 0 !important;
|
||||
@@ -15,8 +96,6 @@
|
||||
&__subtitle {
|
||||
font-size: 0.13rem;
|
||||
color: $text-light;
|
||||
margin: 0.02rem 0 0 0 !important;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&__tabs {
|
||||
@@ -24,7 +103,6 @@
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: 0.04rem;
|
||||
margin: 0.1rem 0 0.16rem 0;
|
||||
background: $bg-white;
|
||||
border-radius: 0.22rem;
|
||||
padding: 0.04rem;
|
||||
@@ -51,13 +129,16 @@
|
||||
|
||||
&__tab {
|
||||
font-size: 0.13rem;
|
||||
color: $text-light;
|
||||
color: $text-middle;
|
||||
cursor: pointer;
|
||||
padding: 0.06rem 0.16rem;
|
||||
border-radius: 0.18rem;
|
||||
padding: 0.06rem 0.20rem;
|
||||
border-radius: 0.08rem;
|
||||
transition: all 0.25s ease;
|
||||
user-select: none;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.06rem;
|
||||
|
||||
&:hover {
|
||||
color: $text-dark;
|
||||
@@ -76,4 +157,20 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 计数圆形徽章 */
|
||||
&__tab-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 0.20rem;
|
||||
height: 0.20rem;
|
||||
padding: 0 0.05rem;
|
||||
border-radius: 0.1rem;
|
||||
background: #F3F4F6;
|
||||
font-size: 0.11rem;
|
||||
font-weight: 500;
|
||||
color: $text-middle;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,15 +156,13 @@
|
||||
&__card-index {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.04rem;
|
||||
font-size: 0.12rem;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
font-size: 0.14rem;
|
||||
color: $accent;
|
||||
}
|
||||
|
||||
&__card-index-dot {
|
||||
width: 0.08rem;
|
||||
height: 0.08rem;
|
||||
width: 0.0rem;
|
||||
height: 0.0rem;
|
||||
color: $accent;
|
||||
}
|
||||
|
||||
@@ -174,7 +172,7 @@
|
||||
border: none;
|
||||
padding: 0.03rem;
|
||||
cursor: pointer;
|
||||
color: $text-light;
|
||||
color: $accent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 0.04rem;
|
||||
|
||||
@@ -12,13 +12,15 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
// 简历HTML内容区
|
||||
// 简历HTML内容区(默认预览模式用小padding,导出模式用大padding)
|
||||
.resume-html {
|
||||
padding: 50px 60px;
|
||||
padding: 10px;
|
||||
font-family: 'SimSun', 'Songti SC', serif;
|
||||
color: $text-dark;
|
||||
line-height: 1.6;
|
||||
|
||||
// 导出模式:恢复完整内边距,去除差异样式 → 见底部统一 &--export 块
|
||||
|
||||
// 姓名
|
||||
&__name {
|
||||
font-size: 28px;
|
||||
@@ -150,9 +152,30 @@
|
||||
|
||||
// ==================== 差异对比高亮样式 ====================
|
||||
&__diff-highlight {
|
||||
background-color: #D4EDDA;
|
||||
color: #155724;
|
||||
border-radius: 2px;
|
||||
padding: 0 1px;
|
||||
font-weight: 700;
|
||||
color: #52CAD1;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: #52CAD1;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
|
||||
// 含有差异文字的经历块/个人概述背景色(仅预览模式)
|
||||
&__diff-block {
|
||||
background-color: #EDF9FA;
|
||||
}
|
||||
|
||||
// 导出模式下去除差异相关样式
|
||||
&--export {
|
||||
padding: 50px 60px;
|
||||
|
||||
.resume-html__diff-highlight {
|
||||
font-weight: inherit;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.resume-html__diff-block {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/* 会员权限拦截弹窗样式 */
|
||||
@use '../variables' as *;
|
||||
|
||||
.member-access-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: $overlay-bg;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
.member-access-dialog {
|
||||
background: $bg-white;
|
||||
border-radius: 0.12rem;
|
||||
padding: 0.4rem 0.36rem 0.3rem;
|
||||
width: 3.8rem;
|
||||
text-align: center;
|
||||
box-shadow: 0 0.04rem 0.2rem rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
/* 锁图标 */
|
||||
.member-access-dialog__icon {
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.member-access-dialog__lock-svg {
|
||||
width: 0.48rem;
|
||||
height: 0.48rem;
|
||||
color: $accent;
|
||||
}
|
||||
|
||||
/* 提示文字 */
|
||||
.member-access-dialog__text {
|
||||
font-size: 0.15rem;
|
||||
color: $text-dark;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
/* 操作按钮区域 */
|
||||
.member-access-dialog__actions {
|
||||
display: flex;
|
||||
gap: 0.16rem;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.member-access-dialog__btn {
|
||||
flex: 1;
|
||||
height: 0.4rem;
|
||||
border-radius: 0.06rem;
|
||||
font-size: 0.14rem;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.85;
|
||||
}
|
||||
}
|
||||
|
||||
/* 灰色取消按钮 */
|
||||
.member-access-dialog__btn--cancel {
|
||||
background: $bg-main;
|
||||
color: $text-middle;
|
||||
}
|
||||
|
||||
/* 主题色确认按钮 */
|
||||
.member-access-dialog__btn--confirm {
|
||||
background: $btn-dark;
|
||||
color: $bg-white;
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
@use '../variables' as *;
|
||||
|
||||
// ==================== 导师页右侧广告面板样式 ====================
|
||||
|
||||
.mentor-aside-panel {
|
||||
font-size: 0.14rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
background: $bg-white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
// 顶部渐变区域
|
||||
&__header {
|
||||
padding: 0.24rem;
|
||||
background: linear-gradient(180deg, #EDF9FA 0%, #FFFFFF 100%);
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-weight: 630;
|
||||
font-size: 0.20rem;
|
||||
line-height: 0.27rem;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-weight: 330;
|
||||
font-size: 0.14rem;
|
||||
line-height: 0.19rem;
|
||||
color: $text-middle;
|
||||
margin-top: 0.04rem;
|
||||
}
|
||||
|
||||
// 统计数字区域
|
||||
&__stats {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 0.24rem;
|
||||
height: 1rem;
|
||||
background: linear-gradient(270deg, rgba(82, 202, 209, 0.05) 0%, rgba(159, 208, 81, 0.05) 100%);
|
||||
border-radius: 0.12rem;
|
||||
position: relative;
|
||||
|
||||
// 渐变边框:从上到下 #9FD051 → #52CAD1
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 0.12rem;
|
||||
padding: 0.012rem;
|
||||
background: linear-gradient(180deg, #9FD051 0%, #52CAD1 100%);
|
||||
-webkit-mask:
|
||||
linear-gradient(#fff 0 0) content-box,
|
||||
linear-gradient(#fff 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__stat-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.08rem;
|
||||
padding: 0.20rem 0;
|
||||
}
|
||||
|
||||
&__stat-num {
|
||||
font-weight: 620;
|
||||
font-size: 0.24rem;
|
||||
line-height: 0.32rem;
|
||||
background: linear-gradient(128.17deg, #52CAD1 0%, #82D79B 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
&__stat-label {
|
||||
font-weight: 450;
|
||||
font-size: 0.14rem;
|
||||
line-height: 0.19rem;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
&__stat-divider {
|
||||
width: 0;
|
||||
height: 0.98rem;
|
||||
border-left: 1px solid $border-color;
|
||||
}
|
||||
|
||||
// 小节标题(共用)
|
||||
&__section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.08rem;
|
||||
}
|
||||
|
||||
&__section-icon {
|
||||
font-size: 0.16rem;
|
||||
background: linear-gradient(128.17deg, #52CAD1 0%, #82D79B 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
&__section-text {
|
||||
font-weight: 620;
|
||||
font-size: 0.16rem;
|
||||
line-height: 0.21rem;
|
||||
background: linear-gradient(128.17deg, #52CAD1 0%, #82D79B 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
// 为什么选择我们的导师
|
||||
&__reasons {
|
||||
margin: 0.24rem 0.24rem 0;
|
||||
}
|
||||
|
||||
&__reason-list {
|
||||
margin-top: 0.24rem;
|
||||
}
|
||||
|
||||
&__reason-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.08rem;
|
||||
margin-bottom: 0.20rem;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__reason-icon {
|
||||
width: 0.42rem;
|
||||
height: 0.42rem;
|
||||
background: #EDF9FA;
|
||||
border-radius: 0.08rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
|
||||
svg {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__reason-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.04rem;
|
||||
}
|
||||
|
||||
&__reason-title {
|
||||
font-weight: 620;
|
||||
font-size: 0.14rem;
|
||||
line-height: 0.19rem;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
&__reason-desc {
|
||||
font-weight: 330;
|
||||
font-size: 0.14rem;
|
||||
line-height: 0.19rem;
|
||||
color: $text-middle;
|
||||
}
|
||||
|
||||
// 热门导师方向
|
||||
&__directions {
|
||||
margin: 0.24rem 0.24rem 0;
|
||||
}
|
||||
|
||||
&__direction-list {
|
||||
margin-top: 0.24rem;
|
||||
}
|
||||
|
||||
&__direction-card {
|
||||
box-sizing: border-box;
|
||||
padding: 0.12rem 0.16rem;
|
||||
background: $bg-white;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 0.12rem;
|
||||
margin-bottom: 0.20rem;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__direction-name {
|
||||
font-weight: 620;
|
||||
font-size: 0.14rem;
|
||||
line-height: 0.19rem;
|
||||
color: $text-dark;
|
||||
margin-bottom: 0.08rem;
|
||||
}
|
||||
|
||||
&__direction-tags {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.08rem;
|
||||
}
|
||||
|
||||
&__direction-tag {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0.04rem 0.08rem;
|
||||
background: #EDF9FA;
|
||||
border-radius: 0.04rem;
|
||||
font-weight: 330;
|
||||
font-size: 0.12rem;
|
||||
line-height: 0.16rem;
|
||||
color: $accent;
|
||||
}
|
||||
|
||||
// 底部按钮区域
|
||||
&__footer {
|
||||
margin-top: auto;
|
||||
padding: 0.24rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__cta-btn {
|
||||
width: 100%;
|
||||
height: 0.40rem;
|
||||
background: linear-gradient(128.17deg, #52CAD1 0%, #82D79B 100%);
|
||||
border-radius: 0.12rem;
|
||||
border: none;
|
||||
font-weight: 620;
|
||||
font-size: 0.14rem;
|
||||
line-height: 0.19rem;
|
||||
color: $bg-white;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.15s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer-tip {
|
||||
font-weight: 330;
|
||||
font-size: 0.12rem;
|
||||
line-height: 0.16rem;
|
||||
color: $text-middle;
|
||||
margin-top: 0.08rem;
|
||||
}
|
||||
|
||||
// ==================== 模式二:模拟对话样式 ====================
|
||||
|
||||
&__chat {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0.16rem 0.24rem;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: $border-color;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
// 对话加载中
|
||||
&__chat-loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.12rem;
|
||||
padding: 0.4rem 0;
|
||||
color: $text-middle;
|
||||
font-size: 0.13rem;
|
||||
}
|
||||
|
||||
&__chat-spinner {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
border: 2px solid $border-color;
|
||||
border-top-color: $accent;
|
||||
border-radius: 50%;
|
||||
animation: mentorChatSpin 0.7s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes mentorChatSpin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
// 对话气泡
|
||||
&__chat-bubble {
|
||||
display: flex;
|
||||
margin-bottom: 0.16rem;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
// 用户消息 — 右对齐,品牌色背景
|
||||
&--user {
|
||||
justify-content: flex-end;
|
||||
|
||||
.mentor-aside-panel__chat-text {
|
||||
background: $accent;
|
||||
color: #FFFFFF;
|
||||
border-radius: 0.12rem 0.04rem 0.12rem 0.12rem;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
}
|
||||
|
||||
// 导师消息 — 左对齐,白色背景
|
||||
&--mentor {
|
||||
justify-content: flex-start;
|
||||
|
||||
.mentor-aside-panel__chat-text {
|
||||
background: #FFFFFF;
|
||||
color: $text-dark;
|
||||
border-radius: 0.04rem 0.12rem 0.12rem 0.12rem;
|
||||
box-shadow: 0 2px 4px rgba(82, 202, 209, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__chat-text {
|
||||
display: inline-block;
|
||||
max-width: 2.38rem;
|
||||
padding: 0.08rem 0.12rem;
|
||||
font-weight: 330;
|
||||
font-size: 0.14rem;
|
||||
line-height: 0.24rem;
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 二维码弹窗样式 ====================
|
||||
|
||||
/* 遮罩层 */
|
||||
.mentor-qr-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 9999;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 弹窗卡片 */
|
||||
.mentor-qr-card {
|
||||
font-size: 0.14rem;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
padding: 0.24rem 0.32rem;
|
||||
gap: 0.24rem;
|
||||
width: 4.80rem;
|
||||
background: linear-gradient(180deg, #EDF9FA 0%, #FFFFFF 20.63%);
|
||||
border: 1px solid #F0F0F0;
|
||||
box-shadow: 0px 0px 16px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 0.12rem;
|
||||
|
||||
// 头部:标题 + 关闭按钮
|
||||
&__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__title-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.04rem;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-weight: 620;
|
||||
font-size: 0.18rem;
|
||||
line-height: 0.24rem;
|
||||
color: #1A1A1A;
|
||||
}
|
||||
|
||||
&__desc {
|
||||
font-weight: 330;
|
||||
font-size: 0.12rem;
|
||||
line-height: 0.16rem;
|
||||
color: #6A7282;
|
||||
}
|
||||
|
||||
&__close {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 0.24rem;
|
||||
height: 0.24rem;
|
||||
}
|
||||
}
|
||||
|
||||
// 二维码展示区域
|
||||
&__qr-area {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0.16rem 0;
|
||||
width: 100%;
|
||||
min-height: 2.72rem;
|
||||
background: #F4FBFB;
|
||||
border: 1px solid #AEE6EA;
|
||||
border-radius: 0.08rem;
|
||||
}
|
||||
|
||||
&__qr-img {
|
||||
width: 2.40rem;
|
||||
height: 2.40rem;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
&__placeholder {
|
||||
font-size: 0.14rem;
|
||||
color: #6A7282;
|
||||
}
|
||||
|
||||
&__loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2.40rem;
|
||||
height: 2.40rem;
|
||||
}
|
||||
|
||||
&__spinner {
|
||||
width: 0.32rem;
|
||||
height: 0.32rem;
|
||||
border: 3px solid #AEE6EA;
|
||||
border-top-color: #52CAD1;
|
||||
border-radius: 50%;
|
||||
animation: mentorQrSpin 0.7s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes mentorQrSpin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
// 底部提示
|
||||
&__footer {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__footer-text {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0.12rem 0.16rem;
|
||||
width: 100%;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #F0F0F0;
|
||||
border-radius: 0.08rem;
|
||||
font-weight: 330;
|
||||
font-size: 0.14rem;
|
||||
line-height: 0.19rem;
|
||||
color: #6A7282;
|
||||
}
|
||||
}
|
||||
@@ -1,95 +1,50 @@
|
||||
@use '../variables' as *;
|
||||
@use 'sass:color';
|
||||
|
||||
// ==================== 个人资料编辑抽屉 ====================
|
||||
// ==================== 个人资料内联编辑组件 ====================
|
||||
|
||||
// 遮罩层
|
||||
.profile-drawer-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: $overlay-bg;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
// 抽屉主体 — 固定在右侧,占满屏幕高度
|
||||
// 重置 font-size + line-height 避免 html font-size:100px 导致行高撑大间距
|
||||
.profile-drawer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 6.2rem;
|
||||
height: 100vh;
|
||||
background: $bg-white;
|
||||
z-index: 2001;
|
||||
box-shadow: -0.04rem 0 0.2rem rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// 内联编辑容器 — 直接嵌入页面卡片中
|
||||
.profile-edit-inline {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
background: #F7F7F7;
|
||||
border-radius: 0.12rem;
|
||||
padding: 0.16rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
// 顶部栏
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.1rem;
|
||||
padding: 0.16rem 0.2rem;
|
||||
border-bottom: 1px solid $border-color;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0.04rem;
|
||||
cursor: pointer;
|
||||
color: $text-dark;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 0.04rem;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: $accent;
|
||||
background: $theme-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__close-icon {
|
||||
width: 0.16rem;
|
||||
height: 0.16rem;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 0.16rem;
|
||||
font-weight: 700;
|
||||
color: $text-dark;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
// 表单内容区 — 中间可滚动
|
||||
// 表单内容区
|
||||
&__body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0.2rem 0.2rem 3rem;
|
||||
padding: 0.1rem 0;
|
||||
}
|
||||
|
||||
// 地区选择器下拉面板提升层级,避免被其他元素遮挡
|
||||
.region-selector__panel {
|
||||
z-index: 2100;
|
||||
}
|
||||
// 基本信息横排字段容器(姓名、电话、微信、邮箱、城市一行排列,允许换行)
|
||||
&__fields-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.16rem;
|
||||
}
|
||||
|
||||
// 横排中的单个字段项
|
||||
&__field-item {
|
||||
flex: 1;
|
||||
min-width: 1.6rem;
|
||||
}
|
||||
|
||||
// 作品集链接整行字段
|
||||
&__field-full {
|
||||
margin-top: 0.16rem;
|
||||
}
|
||||
|
||||
// 单个字段
|
||||
&__field {
|
||||
margin-bottom: 0.18rem;
|
||||
margin-bottom: 0.02rem;
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: 0.13rem;
|
||||
display: block;
|
||||
font-size: 0.12rem;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
color: $text-middle;
|
||||
margin-bottom: 0.06rem;
|
||||
}
|
||||
|
||||
@@ -101,12 +56,12 @@
|
||||
&__input {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 0.1rem 0.14rem;
|
||||
padding: 0.08rem 0.12rem;
|
||||
font-size: 0.13rem;
|
||||
color: $text-dark;
|
||||
background: $bg-main;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0.06rem;
|
||||
background: $bg-white;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 0.04rem;
|
||||
outline: none;
|
||||
transition: all 0.2s;
|
||||
|
||||
@@ -120,21 +75,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 多行文本输入框(经历描述等)
|
||||
// 多行文本输入框
|
||||
&__textarea {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 0.1rem 0.14rem;
|
||||
padding: 0.08rem 0.12rem;
|
||||
font-size: 0.13rem;
|
||||
color: $text-dark;
|
||||
background: $bg-main;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0.06rem;
|
||||
background: $bg-white;
|
||||
border: none;
|
||||
border-radius: 0.04rem;
|
||||
outline: none;
|
||||
transition: all 0.2s;
|
||||
resize: vertical;
|
||||
font-family: inherit;
|
||||
line-height: 1.6;
|
||||
padding-right: 0.3rem;
|
||||
|
||||
&::placeholder {
|
||||
color: $text-light;
|
||||
@@ -144,33 +100,26 @@
|
||||
border-color: $accent;
|
||||
background: $bg-white;
|
||||
}
|
||||
|
||||
// 矮版 textarea — 用于分段描述,右侧留出删除按钮空间
|
||||
&--short {
|
||||
padding-right: 0.36rem;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 描述段落编辑 ====================
|
||||
|
||||
// 单条描述段落容器 — textarea + 右侧删除按钮
|
||||
// 描述段落容器
|
||||
&__desc-item {
|
||||
position: relative;
|
||||
margin-bottom: 0.08rem;
|
||||
}
|
||||
|
||||
// 描述段落内的删除按钮(叉号)
|
||||
// 描述删除按钮
|
||||
&__desc-remove {
|
||||
position: absolute;
|
||||
right: 0.18rem;
|
||||
top: 0.08rem;
|
||||
right: 0.08rem;
|
||||
top: 0.06rem;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0.02rem;
|
||||
padding: 0.02rem 0.04rem;
|
||||
cursor: pointer;
|
||||
color: $text-light;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 0.14rem;
|
||||
line-height: 1;
|
||||
border-radius: 0.03rem;
|
||||
transition: all 0.2s;
|
||||
|
||||
@@ -179,91 +128,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__desc-remove-icon {
|
||||
width: 0.12rem;
|
||||
height: 0.12rem;
|
||||
}
|
||||
|
||||
// 小号新增按钮 — 用于"新增一段描述"
|
||||
&__add-btn--small {
|
||||
font-size: 0.11rem;
|
||||
padding: 0.04rem 0.12rem;
|
||||
margin-top: 0.04rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
// 空状态占位
|
||||
&__empty {
|
||||
text-align: center;
|
||||
padding: 0.6rem 0;
|
||||
}
|
||||
|
||||
&__empty-text {
|
||||
font-size: 0.14rem;
|
||||
color: $text-light;
|
||||
}
|
||||
|
||||
// ==================== 教育经历模块 ====================
|
||||
|
||||
// 单条教育经历卡片
|
||||
&__edu-card {
|
||||
padding-bottom: 0.2rem;
|
||||
margin-bottom: 0.2rem;
|
||||
border-bottom: 1px solid $border-color;
|
||||
|
||||
&:last-of-type {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
// 教育经历标题栏
|
||||
&__edu-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.14rem;
|
||||
}
|
||||
|
||||
// 序号标识
|
||||
&__edu-index {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.06rem;
|
||||
font-size: 0.14rem;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
&__edu-index-icon {
|
||||
width: 0.1rem;
|
||||
height: 0.1rem;
|
||||
color: $accent;
|
||||
}
|
||||
|
||||
// 删除按钮
|
||||
&__edu-delete {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0.04rem;
|
||||
cursor: pointer;
|
||||
color: $text-light;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 0.04rem;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: $danger;
|
||||
background: rgba($danger, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
&__edu-delete-icon {
|
||||
width: 0.15rem;
|
||||
height: 0.15rem;
|
||||
}
|
||||
|
||||
// 横排字段容器(学院+专业、学历+GPA、入学+毕业时间)
|
||||
// 横排字段容器
|
||||
&__row {
|
||||
display: flex;
|
||||
gap: 0.12rem;
|
||||
@@ -275,60 +140,81 @@
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
// 下拉选择器包裹(带箭头图标)
|
||||
&__select-wrap {
|
||||
position: relative;
|
||||
// ==================== 经历卡片模块 ====================
|
||||
|
||||
&__edu-card {
|
||||
padding-bottom: 0.16rem;
|
||||
margin-bottom: 0.16rem;
|
||||
border-bottom: 1px solid $border-color;
|
||||
|
||||
&:last-of-type {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__select-wrap &__input {
|
||||
padding-right: 0.3rem;
|
||||
&__edu-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.12rem;
|
||||
}
|
||||
|
||||
&__select-arrow {
|
||||
position: absolute;
|
||||
right: 0.1rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 0.12rem;
|
||||
height: 0.12rem;
|
||||
&__edu-index {
|
||||
font-size: 0.13rem;
|
||||
font-weight: 600;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
&__edu-delete {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0.04rem 0.08rem;
|
||||
cursor: pointer;
|
||||
color: $text-light;
|
||||
pointer-events: none;
|
||||
font-size: 0.12rem;
|
||||
border-radius: 0.04rem;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: $danger;
|
||||
background: rgba($danger, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
// 新增教育经历按钮
|
||||
// 新增按钮
|
||||
&__add-btn {
|
||||
text-align: center;
|
||||
background: none;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 0.2rem;
|
||||
padding: 0.06rem 0.16rem;
|
||||
border: 1px dashed $border-color;
|
||||
border-radius: 0.04rem;
|
||||
padding: 0.04rem 0.12rem;
|
||||
font-size: 0.12rem;
|
||||
color: $text-dark;
|
||||
color: $text-middle;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
margin-top: 0.04rem;
|
||||
margin-top: 0.06rem;
|
||||
|
||||
&:hover {
|
||||
border-color: $accent;
|
||||
color: $accent;
|
||||
}
|
||||
|
||||
&--full {
|
||||
width: 100%;
|
||||
margin-top: 0.12rem;
|
||||
padding: 0.08rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__add-icon {
|
||||
font-size: 0.14rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
// ==================== 日期选择器样式覆盖 ====================
|
||||
// Element Plus 的 el-date-picker 在 html font-size:100px 下需要用 px 还原
|
||||
// ==================== 日期选择器 ====================
|
||||
|
||||
&__date-picker {
|
||||
width: 100% !important;
|
||||
|
||||
.el-input__wrapper {
|
||||
background: $bg-main !important;
|
||||
border: 1px solid transparent !important;
|
||||
border-radius: 6px !important;
|
||||
border: 1px solid $border-color !important;
|
||||
border-radius: 4px !important;
|
||||
box-shadow: none !important;
|
||||
padding: 4px 12px !important;
|
||||
font-size: 13px !important;
|
||||
@@ -336,7 +222,7 @@
|
||||
height: auto !important;
|
||||
|
||||
&:hover {
|
||||
border-color: $border-color !important;
|
||||
border-color: $accent !important;
|
||||
}
|
||||
|
||||
&.is-focus {
|
||||
@@ -368,26 +254,146 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 技能模块 ====================
|
||||
// 日期范围容器(开始-结束横排)
|
||||
&__date-range {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.04rem;
|
||||
}
|
||||
|
||||
&__date-sep {
|
||||
color: $text-light;
|
||||
font-size: 0.12rem;
|
||||
}
|
||||
|
||||
// ==================== AI润色功能 ====================
|
||||
|
||||
// 个人概述标题栏(含AI润色按钮)
|
||||
&__summary-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.12rem;
|
||||
margin-bottom: 0.08rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
// AI润色按钮
|
||||
&__ai-polish-btn {
|
||||
padding: 0.01rem 0.06rem;
|
||||
font-size: 0.11rem;
|
||||
background: $accent;
|
||||
color: $bg-white;
|
||||
border: 1px solid $accent;
|
||||
border-radius: 0.04rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
white-space: nowrap;
|
||||
>span>span{
|
||||
color: #FCD34D;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $accent;
|
||||
color: $bg-white;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
// AI润色结果区域
|
||||
&__ai-result {
|
||||
margin-top: 0.04rem;
|
||||
}
|
||||
|
||||
&__ai-result-label {
|
||||
font-size: 0.12rem;
|
||||
font-weight: 600;
|
||||
color: $accent;
|
||||
margin-bottom: 0.08rem;
|
||||
}
|
||||
|
||||
&__ai-result-card {
|
||||
padding: 0.1rem 0.12rem;
|
||||
background: linear-gradient(to bottom, #EDF9FA 0, #fff 0.5rem);
|
||||
border-radius: 0.06rem;
|
||||
}
|
||||
|
||||
&__ai-result-text {
|
||||
font-size: 0.13rem;
|
||||
color: $text-dark;
|
||||
line-height: 1.7;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
// AI结果操作按钮组
|
||||
&__ai-result-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.12rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
// 替换为此内容按钮
|
||||
&__ai-replace-btn {
|
||||
padding: 0.04rem 0.12rem;
|
||||
font-size: 0.12rem;
|
||||
color: #fff;
|
||||
background: $accent;
|
||||
border: 1px solid $accent;
|
||||
border-radius: 0.04rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: $accent;
|
||||
color: $bg-white;
|
||||
}
|
||||
}
|
||||
|
||||
// 重新生成按钮
|
||||
&__ai-regenerate-btn {
|
||||
padding: 0.04rem 0.12rem;
|
||||
font-size: 0.12rem;
|
||||
color: $accent;
|
||||
background: none;
|
||||
border: 1px solid $accent;
|
||||
border-radius: 0.04rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
border-color: $accent;
|
||||
color: $accent;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 技能/证书标签 ====================
|
||||
|
||||
// 技能标签列表容器
|
||||
&__skills-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.08rem;
|
||||
margin-bottom: 0.2rem;
|
||||
margin-bottom: 0.16rem;
|
||||
min-height: 0.4rem;
|
||||
}
|
||||
|
||||
// 单个技能标签
|
||||
&__skill-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.06rem;
|
||||
padding: 0.06rem 0.1rem 0.06rem 0.14rem;
|
||||
padding: 0.04rem 0.1rem 0.04rem 0.12rem;
|
||||
background: $bg-main;
|
||||
border-radius: 0.16rem;
|
||||
font-size: 0.13rem;
|
||||
border-radius: 0.14rem;
|
||||
font-size: 0.12rem;
|
||||
color: $text-dark;
|
||||
transition: all 0.2s;
|
||||
|
||||
@@ -396,12 +402,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 技能标签文本
|
||||
&__skill-text {
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
// 技能标签删除按钮
|
||||
&__skill-remove {
|
||||
background: none;
|
||||
border: none;
|
||||
@@ -424,23 +428,23 @@
|
||||
height: 0.12rem;
|
||||
}
|
||||
|
||||
// 底部保存按钮
|
||||
// ==================== 底部操作按钮 ====================
|
||||
|
||||
&__footer {
|
||||
padding: 0.16rem 0.2rem;
|
||||
border-top: 1px solid $border-color;
|
||||
text-align: center;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.12rem;
|
||||
padding-top: 0.04rem;
|
||||
}
|
||||
|
||||
&__save-btn {
|
||||
width: 2.0rem;
|
||||
padding: 0.1rem 0;
|
||||
font-size: 0.14rem;
|
||||
padding: 0.06rem 0.24rem;
|
||||
font-size: 0.13rem;
|
||||
font-weight: 600;
|
||||
color: $bg-white;
|
||||
background: $btn-dark;
|
||||
border: none;
|
||||
border-radius: 0.24rem;
|
||||
border-radius: 0.08rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
@@ -448,11 +452,26 @@
|
||||
background: $btn-dark-hover;
|
||||
}
|
||||
}
|
||||
|
||||
&__cancel-btn {
|
||||
padding: 0.06rem 0.24rem;
|
||||
font-size: 0.13rem;
|
||||
font-weight: 600;
|
||||
color: $accent;
|
||||
background: transparent;
|
||||
border: 1px solid $accent;
|
||||
border-radius: 0.08rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: $theme-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 过渡动画 ====================
|
||||
// ==================== 日期选择器弹出面板样式覆盖 ====================
|
||||
|
||||
// 日期选择器弹出面板样式覆盖(teleport 到 body,需在全局作用域)
|
||||
.profile-drawer-date-popper {
|
||||
font-size: 14px !important;
|
||||
line-height: 1.5 !important;
|
||||
@@ -474,25 +493,3 @@
|
||||
padding: 8px 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 遮罩层淡入淡出
|
||||
.profile-drawer-overlay-enter-active,
|
||||
.profile-drawer-overlay-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.profile-drawer-overlay-enter-from,
|
||||
.profile-drawer-overlay-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
// 抽屉滑入滑出
|
||||
.profile-drawer-slide-enter-active,
|
||||
.profile-drawer-slide-leave-active {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.profile-drawer-slide-enter-from,
|
||||
.profile-drawer-slide-leave-to {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||