新版交互调整
This commit is contained in:
+309
-252
@@ -31,183 +31,226 @@
|
||||
<div class="agent-page__main">
|
||||
<!-- ========== 第1步:确认个人资料 ========== -->
|
||||
<template v-if="currentStep === 1">
|
||||
<div class="agent-page__left">
|
||||
<div class="agent-page__intro-card">
|
||||
<div class="agent-page__intro-header">
|
||||
<div class="agent-page__intro-icon">
|
||||
<svg viewBox="0 0 24 24" fill="none"><path d="M12 12c2.7 0 5-2.3 5-5s-2.3-5-5-5-5 2.3-5 5 2.3 5 5 5zm0 2c-3.3 0-10 1.7-10 5v2h20v-2c0-3.3-6.7-5-10-5z" fill="currentColor"/></svg>
|
||||
</div>
|
||||
<h2 class="agent-page__intro-title">在开始之前请先确认你的个人资料是否无误</h2>
|
||||
</div>
|
||||
<p class="agent-page__intro-desc">请仔细对你的资料评估(包括个人信息、教育背景、工作履历及技能),确保资料齐全,让我能顺利为你开启求职之旅。</p>
|
||||
<div class="agent-page__import-row">
|
||||
<div class="agent-page__import-icon">
|
||||
<svg viewBox="0 0 24 24" fill="none"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8l-6-6z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M14 2v6h6M16 13H8M16 17H8M10 9H8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</div>
|
||||
<span class="agent-page__import-text">{{ profile.name }}的个人资料</span>
|
||||
</div>
|
||||
<div class="dflex-center aliite-c">
|
||||
<button class="agent-page__confirm-btn" @click="handleNext">确认并进入</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="agent-page__right">
|
||||
<div class="agent-page__profile-wrapper">
|
||||
<div class="agent-page__profile-title">个人档案</div>
|
||||
<ProfilePageContent :profile="profile" @edit="handleEdit" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="agent-page__left">
|
||||
<div class="agent-page__intro-card">
|
||||
<div class="agent-page__intro-header por">
|
||||
<div v-if="false" class="agent-page__intro-icon poa l-22 t0">
|
||||
<svg viewBox="0 0 24 24" fill="none"><path d="M12 12c2.7 0 5-2.3 5-5s-2.3-5-5-5-5 2.3-5 5 2.3 5 5 5zm0 2c-3.3 0-10 1.7-10 5v2h20v-2c0-3.3-6.7-5-10-5z" fill="currentColor"/></svg>
|
||||
</div>
|
||||
<h2 class="agent-page__intro-title">请先确认你的个人资料是否无误</h2>
|
||||
</div>
|
||||
<p class="agent-page__intro-desc mb50 ">请仔细对你的资料评估(包括个人信息、教育背景、工作履历及技能),确保资料齐全,让我能顺利为你开启求职之旅。</p>
|
||||
<div class="">
|
||||
<div class="tac"><button class="agent-page__confirm-btn dib" @click="handleNext">确认并进入</button></div>
|
||||
<div v-if="false" class="tac color-9 mt30 cursor-po" @click="handleBack">返回上一步</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<!-- ========== 第2步:确认目标 ========== -->
|
||||
<template v-if="currentStep === 2">
|
||||
<div class="agent-page__step2">
|
||||
<!-- 返回上一步按钮 -->
|
||||
<button class="agent-page__back-btn" @click="handleBack">
|
||||
<svg viewBox="0 0 24 24" fill="none" width="16" height="16"><path d="M15 18l-6-6 6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
<span>返回上一步</span>
|
||||
</button>
|
||||
<div class="agent-page__chat">
|
||||
<div class="agent-page__chat-row">
|
||||
<div class="agent-page__chat-avatar"><svg viewBox="0 0 24 24" fill="none"><path d="M12 12c2.7 0 5-2.3 5-5s-2.3-5-5-5-5 2.3-5 5 2.3 5 5 5zm0 2c-3.3 0-10 1.7-10 5v2h20v-2c0-3.3-6.7-5-10-5z" fill="currentColor"/></svg></div>
|
||||
<span class="agent-page__chat-text">接下来,我想确认一下我为你搜寻的职位方向是否准确。</span>
|
||||
</div>
|
||||
<div class="p20 bg-f border-ra10">
|
||||
<div class="agent-page__pref-card">
|
||||
<p class="agent-page__pref-desc">这些是你之前设定的求职偏好。如有需要,请随时修改。</p>
|
||||
<div class="agent-page__pref-tags">
|
||||
<span v-for="name in intentionCategoryNames" :key="'cat-' + name" class="agent-page__pref-tag">{{ name }}</span>
|
||||
<span v-for="name in intentionIndustryNames" :key="'ind-' + name" class="agent-page__pref-tag">{{ name }}</span>
|
||||
<span v-for="name in intentionRegionNames" :key="'reg-' + name" class="agent-page__pref-tag">{{ name }}</span>
|
||||
<span class="agent-page__pref-tag">{{ intentionEmploymentLabel }}</span>
|
||||
</div>
|
||||
<div class="agent-page__pref-actions">
|
||||
<button class="agent-page__pref-btn agent-page__pref-btn--edit" @click="showJobGoalDialog = true">编辑</button>
|
||||
<button class="agent-page__pref-btn agent-page__pref-btn--confirm" @click="handleNext">确认并继续</button>
|
||||
<!-- 左侧:求职偏好 + 简历设置 -->
|
||||
<div class="agent-page__right">
|
||||
<div class="agent-page__profile-wrapper">
|
||||
<!-- 求职偏好区域 -->
|
||||
<div class="agent-page__pref-section">
|
||||
<h3 class="agent-page__pref-section-title">求职偏好</h3>
|
||||
<p class="agent-page__pref-section-desc">这些是你之前设定的求职偏好。如有需要,请随时修改。</p>
|
||||
<div class="agent-page__pref-filters">
|
||||
<!-- 城市选择 -->
|
||||
<RegionSelector
|
||||
:regionCodes="step2RegionCodes"
|
||||
:level="2"
|
||||
:maxSelect="3"
|
||||
:triggerStyle="prefFilterTriggerStyle"
|
||||
:displayStyle="prefFilterDisplayStyle"
|
||||
@update:regionCodes="onStep2RegionChange"
|
||||
/>
|
||||
<!-- 岗位选择 -->
|
||||
<JobCategorySelector
|
||||
:categoryIds="step2CategoryIds"
|
||||
:maxSelect="3"
|
||||
:level="3"
|
||||
:allowParentSelect="true"
|
||||
:triggerStyle="prefFilterTriggerStyle"
|
||||
:displayStyle="prefFilterDisplayStyle"
|
||||
@update:categoryIds="onStep2CategoryChange"
|
||||
/>
|
||||
<!-- 行业选择 -->
|
||||
<IndustrySelector
|
||||
:industryIds="step2IndustryIds"
|
||||
:maxSelect="3"
|
||||
:level="2"
|
||||
:allowParentSelect="true"
|
||||
:triggerStyle="prefFilterTriggerStyle"
|
||||
:displayStyle="prefFilterDisplayStyle"
|
||||
@update:industryIds="onStep2IndustryChange"
|
||||
/>
|
||||
<!-- 招聘分类下拉选择 -->
|
||||
<div class="agent-page__pref-type-dropdown" @click.stop="showJobTypeDropdown = !showJobTypeDropdown">
|
||||
<span>{{ intentionEmploymentLabel || '类型' }}</span>
|
||||
<svg class="agent-page__pref-type-arrow" viewBox="0 0 12 12" fill="none">
|
||||
<path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
<!-- 下拉菜单 -->
|
||||
<div v-if="showJobTypeDropdown" class="agent-page__pref-type-menu" @click.stop>
|
||||
<div
|
||||
v-for="option in jobTypeOptions"
|
||||
:key="option.value"
|
||||
class="agent-page__pref-type-menu-item"
|
||||
:class="{ 'agent-page__pref-type-menu-item--active': store.state.jobIntention.recruitCategory === option.value }"
|
||||
@click.stop="selectJobType(option)"
|
||||
>{{ option.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="loadingMatchJobs" class="agent-page__chat-row">
|
||||
<div class="agent-page__chat-avatar"><svg viewBox="0 0 24 24" fill="none"><path d="M12 12c2.7 0 5-2.3 5-5s-2.3-5-5-5-5 2.3-5 5 2.3 5 5 5zm0 2c-3.3 0-10 1.7-10 5v2h20v-2c0-3.3-6.7-5-10-5z" fill="currentColor"/></svg></div>
|
||||
<div class="agent-page__chat-typing"><span></span><span></span><span></span></div>
|
||||
</div>
|
||||
<div v-if="matchedJobs.length > 0" class="p20 bg-f border-ra10">
|
||||
<div class="agent-page__match-card">
|
||||
<p class="agent-page__match-desc">这些是为你匹配的岗位,请选择你想投递的岗位,如对某个岗位不满意请告诉我。</p>
|
||||
<div v-for="(job, i) in matchedJobs" :key="i" class="agent-page__match-item">
|
||||
<div class="agent-page__match-info">
|
||||
<div class="agent-page__match-icon"><svg viewBox="0 0 24 24" fill="none"><path d="M3 21h18M3 7v14M9 3v4M15 3v4M9 3h6M5 7h14a2 2 0 012 2v10H3V9a2 2 0 012-2z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
<div class="agent-page__match-detail">
|
||||
<div class="agent-page__match-company">{{ job.companyShortName || job.companyName }}</div>
|
||||
<div class="agent-page__match-position">{{ job.title }}</div>
|
||||
<div class="agent-page__match-tags"><span v-for="(t, j) in job.tags" :key="j" class="agent-page__match-tag">{{ t }}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="agent-page__match-score">
|
||||
<svg viewBox="0 0 40 40" class="agent-page__match-ring"><circle cx="20" cy="20" r="16" fill="none" stroke="#E8E8E8" stroke-width="3"/><circle cx="20" cy="20" r="16" fill="none" stroke="#000" stroke-width="3" :stroke-dasharray="100.53" :stroke-dashoffset="100.53 * (1 - job.matchScore / 100)" stroke-linecap="round" transform="rotate(-90 20 20)"/></svg>
|
||||
<span class="agent-page__match-score-text">{{ job.matchScore }}%</span>
|
||||
</div>
|
||||
<div class="agent-page__match-feedback">
|
||||
<button class="agent-page__match-fb-btn" :class="{ 'agent-page__match-fb-btn--active': job.feedback === 'like' }" @click="job.feedback = job.feedback === 'like' ? '' : 'like'"><svg viewBox="0 0 24 24" fill="none"><path d="M7 22V11l5-9 1.5 1 -1 5h6.5a2 2 0 012 2.2l-1.5 8A2 2 0 0117.6 20H7z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/><path d="M4 11H2v11h2a1 1 0 001-1V12a1 1 0 00-1-1z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/></svg></button>
|
||||
<button class="agent-page__match-fb-btn" :class="{ 'agent-page__match-fb-btn--active': job.feedback === 'dislike' }" @click="handleDislike(i)"><svg viewBox="0 0 24 24" fill="none"><path d="M17 2v11l-5 9-1.5-1 1-5H5a2 2 0 01-2-2.2l1.5-8A2 2 0 016.4 4H17z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/><path d="M20 13h2V2h-2a1 1 0 00-1 1v9a1 1 0 001 1z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showDislikeInput" class="agent-page__dislike-input"><input v-model="dislikeReason" type="text" placeholder="你为什么对这个岗位不满意?" /></div>
|
||||
<!-- 简历设置区域 -->
|
||||
<div class="agent-page__resume-section">
|
||||
<h3 class="agent-page__pref-section-title">简历设置</h3>
|
||||
<div class="agent-page__resume-sub-label">设置默认简历</div>
|
||||
<div class="agent-page__resume-select-row">
|
||||
<span class="agent-page__resume-check-icon">
|
||||
<svg viewBox="0 0 16 16" fill="none"><rect x="2" y="2" width="12" height="12" rx="2" stroke="currentColor" stroke-width="1.2"/></svg>
|
||||
</span>
|
||||
<el-select v-model="selectedResumeId" placeholder="请选择简历" class="agent-page__resume-select">
|
||||
<el-option v-for="r in resumeList" :key="r.id" :label="r.resumeName" :value="r.id || ''" />
|
||||
</el-select>
|
||||
</div>
|
||||
<!-- 自动优化简历开关 -->
|
||||
<div class="agent-page__resume-switch-row">
|
||||
<span class="agent-page__resume-switch-text">在投递时帮我针对岗位自动优化简历。</span>
|
||||
<el-switch v-model="autoOptimizeSwitch" :active-color="'#4FC2C9'" />
|
||||
</div>
|
||||
<!-- 岗位匹配分析开关 -->
|
||||
<div class="agent-page__resume-switch-row">
|
||||
<span class="agent-page__resume-switch-text">在投递时帮我进行岗位匹配分析</span>
|
||||
<el-switch v-model="autoMatchAnalysisSwitch" :active-color="'#4FC2C9'" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="matchedJobs.length > 0" class="agent-page__step2-footer"><button class="agent-page__optimize-btn" @click="loadMatchedJobs">优化我的岗位匹配</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧:确认卡片 -->
|
||||
<div class="agent-page__left">
|
||||
<div class="agent-page__intro-card">
|
||||
<div class="agent-page__intro-header por">
|
||||
<div class="agent-page__intro-icon poa l-22 t0">
|
||||
<svg viewBox="0 0 24 24" fill="none"><path d="M12 12c2.7 0 5-2.3 5-5s-2.3-5-5-5-5 2.3-5 5 2.3 5 5 5zm0 2c-3.3 0-10 1.7-10 5v2h20v-2c0-3.3-6.7-5-10-5z" fill="currentColor"/></svg>
|
||||
</div>
|
||||
<h2 class="agent-page__intro-title">接下来,我想确认一下我为你搜寻的职位方向是否准确。</h2>
|
||||
</div>
|
||||
<p class="agent-page__intro-desc mb50">请仔细对你的资料评估(包括个人信息、教育背景、工作履历及技能),确保资料齐全,让我能顺利为你开启求职之旅。</p>
|
||||
<div class="">
|
||||
<div class="tac"><button class="agent-page__confirm-btn dib" @click="handleNext">确认并进入</button></div>
|
||||
<div class="tac color-9 mt30 cursor-po" @click="handleBack">返回上一步</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ========== 第3步:网申常见问题 + 插件安装 ========== -->
|
||||
<!-- ========== 第3步:安装插件 ========== -->
|
||||
<template v-if="currentStep === 3">
|
||||
<!-- 上半部分:网申常见问题 -->
|
||||
<div v-if="step3Sub === 1" class="agent-page__step3">
|
||||
<!-- 返回上一步按钮 -->
|
||||
<button class="agent-page__back-btn" @click="handleBack">
|
||||
<svg viewBox="0 0 24 24" fill="none" width="16" height="16"><path d="M15 18l-6-6 6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
<span>返回上一步</span>
|
||||
</button>
|
||||
<div class="agent-page__left">
|
||||
<div class="agent-page__intro-card">
|
||||
<div class="agent-page__intro-header"><div class="agent-page__intro-icon"><svg viewBox="0 0 24 24" fill="none"><path d="M12 12c2.7 0 5-2.3 5-5s-2.3-5-5-5-5 2.3-5 5 2.3 5 5 5zm0 2c-3.3 0-10 1.7-10 5v2h20v-2c0-3.3-6.7-5-10-5z" fill="currentColor"/></svg></div><h2 class="agent-page__intro-title">现在我们来开启自动投递吧</h2></div>
|
||||
<p class="agent-page__intro-desc">以下是校招网申常见填写信息。<br/>现在填写一次,我即可在自动申请时帮你填写信息。</p>
|
||||
<div class="dflex-center aliite-c"><button class="agent-page__confirm-btn" @click="step3Sub = 2">确认并继续</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="agent-page__right">
|
||||
<div class="agent-page__form-wrapper">
|
||||
<div class="agent-page__form-title">网申常见问题</div>
|
||||
<div class="agent-page__form-group"><div class="agent-page__form-label">是否愿意接受部门调剂?</div><div class="agent-page__form-options"><button class="agent-page__form-option" :class="{ 'agent-page__form-option--active': step3Form.acceptDeptTransfer === '是,服从调剂' }" @click="step3Form.acceptDeptTransfer = '是,服从调剂'">是,服从调剂</button><button class="agent-page__form-option" :class="{ 'agent-page__form-option--active': step3Form.acceptDeptTransfer === '否,不调剂' }" @click="step3Form.acceptDeptTransfer = '否,不调剂'">否,不调剂</button></div></div>
|
||||
<div class="agent-page__form-group"><div class="agent-page__form-label">是否接受地点调剂?</div><div class="agent-page__form-options"><button class="agent-page__form-option" :class="{ 'agent-page__form-option--active': step3Form.acceptLocationTransfer === '是' }" @click="step3Form.acceptLocationTransfer = '是'">是</button><button class="agent-page__form-option" :class="{ 'agent-page__form-option--active': step3Form.acceptLocationTransfer === '否' }" @click="step3Form.acceptLocationTransfer = '否'">否</button></div></div>
|
||||
<div class="agent-page__form-group"><div class="agent-page__form-label">可以参加面试的方式?</div><div class="agent-page__form-options"><button class="agent-page__form-option" :class="{ 'agent-page__form-option--active': step3Form.interviewType.includes('线下面试') }" @click="toggleInterviewType('线下面试')">线下面试</button><button class="agent-page__form-option" :class="{ 'agent-page__form-option--active': step3Form.interviewType.includes('线上远程') }" @click="toggleInterviewType('线上远程')">线上远程</button></div></div>
|
||||
<div class="agent-page__form-group"><div class="agent-page__form-label">你的语言能力?</div><div class="agent-page__form-selects"><el-select v-model="step3Form.languages[0].language" placeholder="语种" class="agent-page__form-select"><el-option v-for="lang in languageOptions" :key="lang" :label="lang" :value="lang" /></el-select><el-select v-model="step3Form.languages[0].proficiency" placeholder="掌握程度" class="agent-page__form-select"><el-option v-for="p in proficiencyOptions" :key="p" :label="p" :value="p" /></el-select></div></div>
|
||||
<div class="agent-page__form-group"><div class="agent-page__form-label">预计到岗时间?</div><div class="agent-page__form-selects"><el-select v-model="step3Form.availableDate" placeholder="请选择" class="agent-page__form-select"><el-option v-for="d in availableDateOptions" :key="d" :label="d" :value="d" /></el-select></div></div>
|
||||
<template v-if="isInternship">
|
||||
<div class="agent-page__form-group"><div class="agent-page__form-label">每周可实习天数?</div><div class="agent-page__form-selects"><el-select v-model="step3Form.internDaysPerWeek" placeholder="请选择" class="agent-page__form-select"><el-option v-for="d in internDaysOptions" :key="d" :label="d" :value="d" /></el-select></div></div>
|
||||
<div class="agent-page__form-group"><div class="agent-page__form-label">预计实习时长?</div><div class="agent-page__form-selects"><el-select v-model="step3Form.internDuration" placeholder="请选择" class="agent-page__form-select"><el-option v-for="d in internDurationOptions" :key="d" :label="d" :value="d" /></el-select></div></div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 下半部分:插件安装 -->
|
||||
<div v-if="step3Sub === 2" class="agent-page__step3">
|
||||
<!-- 返回上一阶段按钮 -->
|
||||
<button class="agent-page__back-btn" @click="handleBack">
|
||||
<svg viewBox="0 0 24 24" fill="none" width="16" height="16"><path d="M15 18l-6-6 6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
<span>返回上一步</span>
|
||||
</button>
|
||||
<div class="agent-page__left">
|
||||
<div class="agent-page__intro-card">
|
||||
<div class="agent-page__intro-header"><div class="agent-page__intro-icon"><svg viewBox="0 0 24 24" fill="none"><path d="M12 12c2.7 0 5-2.3 5-5s-2.3-5-5-5-5 2.3-5 5 2.3 5 5 5zm0 2c-3.3 0-10 1.7-10 5v2h20v-2c0-3.3-6.7-5-10-5z" fill="currentColor"/></svg></div><h2 class="agent-page__intro-title">现在我们来开启自动投递吧</h2></div>
|
||||
<p class="agent-page__intro-desc">简单三步安装 Chrome 扩展程序<br/>实现自动填表,并一站式追踪所有申请进度。</p>
|
||||
<div class="agent-page__install-steps"><p>1. 点击 [ 安装扩展程序 ],前往 Chrome 应用商店。</p><p>2. 点击 "添加至 Chrome" 并完成安装。</p><p>3. 刷新本页,然后点击下方按钮完成同步。</p></div>
|
||||
<div class="dflex-center aliite-c"><button class="agent-page__confirm-btn" @click="handleNext">我已安装</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="agent-page__right">
|
||||
<div class="agent-page__form-wrapper">
|
||||
<div class="agent-page__form-title">自动填写插件</div>
|
||||
<div class="agent-page__plugin-section">
|
||||
<h3 class="agent-page__plugin-title">自动填写插件</h3>
|
||||
<div class="agent-page__browser-btns"><button v-for="b in browserList" :key="b.key" class="agent-page__browser-btn" @click="openBrowserGuide(b.key)">{{ b.label }}</button></div>
|
||||
<div class="dflex-center aliite-c" style="margin-top: 0.24rem;"><button class="agent-page__confirm-btn" @click="downloadExtension">下载插件</button></div>
|
||||
<!-- 左侧:安装教程内容 -->
|
||||
<div class="agent-page__right">
|
||||
<div class="agent-page__profile-wrapper">
|
||||
<div class="agent-page__install-guide">
|
||||
<h3 class="agent-page__install-guide-title">安装自动填写插件</h3>
|
||||
|
||||
<!-- 步骤1:下载插件包 -->
|
||||
<div class="agent-page__install-step">
|
||||
<p class="agent-page__install-step-text">1、下载下方的插件包</p>
|
||||
<div class="agent-page__install-download">
|
||||
<button class="agent-page__install-download-btn" @click="downloadExtension">
|
||||
<span>Offer派自动投递助手.crx</span>
|
||||
<svg viewBox="0 0 16 16" fill="none" width="14" height="14"><path d="M8 2v8M8 10L5 7M8 10l3-3M3 13h10" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 步骤2:复制地址进入扩展程序页面 -->
|
||||
<div class="agent-page__install-step">
|
||||
<p class="agent-page__install-step-text">2、复制右下方的蓝色地址,在浏览器地址栏粘贴并进入浏览器的扩展程序页面</p>
|
||||
<div class="agent-page__install-step-content">
|
||||
<div class="agent-page__install-step-img">
|
||||
<img src="@/assets/images/agent-setting/2-1.png" alt="地址栏示例" />
|
||||
</div>
|
||||
<div class="agent-page__install-browser-links">
|
||||
<div class="agent-page__install-browser-item">
|
||||
<img src="@/assets/images/agent-setting/2-2.png" style="width: 3rem;height: 0.3rem;" alt="Chrome" class="agent-page__install-browser-icon" />
|
||||
|
||||
</div>
|
||||
<a class="agent-page__install-browser-url" href="javascript:void(0)" @click="copyToClipboard('chrome://extensions')">
|
||||
chrome://extensions
|
||||
<svg viewBox="0 0 14 14" fill="none" width="12" height="12"><rect x="4" y="4" width="8" height="8" rx="1" stroke="currentColor" stroke-width="1"/><path d="M10 4V3a1 1 0 00-1-1H3a1 1 0 00-1 1v6a1 1 0 001 1h1" stroke="currentColor" stroke-width="1"/></svg>
|
||||
</a>
|
||||
<div class="agent-page__install-browser-item mt16">
|
||||
<img src="@/assets/images/agent-setting/2-3.png" style="width: 3rem;height: 0.3rem;" alt="Edge" class="agent-page__install-browser-icon" />
|
||||
|
||||
</div>
|
||||
<a class="agent-page__install-browser-url" href="javascript:void(0)" @click="copyToClipboard('edge://extensions/')">
|
||||
edge://extensions/
|
||||
<svg viewBox="0 0 14 14" fill="none" width="12" height="12"><rect x="4" y="4" width="8" height="8" rx="1" stroke="currentColor" stroke-width="1"/><path d="M10 4V3a1 1 0 00-1-1H3a1 1 0 00-1 1v6a1 1 0 001 1h1" stroke="currentColor" stroke-width="1"/></svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 步骤3:打开开发人员模式 -->
|
||||
<div class="agent-page__install-step">
|
||||
<p class="agent-page__install-step-text">3、在浏览器拓展页面中打开「开发人员模式」</p>
|
||||
<div class="agent-page__install-step-img-row">
|
||||
<div class="agent-page__install-step-img-item">
|
||||
<img src="@/assets/images/agent-setting/3-1.png" alt="打开开发人员模式" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 步骤4:拖入插件包 -->
|
||||
<div class="agent-page__install-step">
|
||||
<p class="agent-page__install-step-text">4、将下载好的「离线插件包」使用鼠标拖入到浏览器的扩展程序页面</p>
|
||||
<div class="agent-page__install-step-img-row">
|
||||
<div class="agent-page__install-step-img-item">
|
||||
<img src="@/assets/images/agent-setting/4-1.png" alt="拖入插件包" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 浏览器安装指引弹窗 -->
|
||||
<el-dialog v-model="showBrowserGuide" :title="currentBrowserLabel + ' 安装指引'" width="80%" top="5vh" destroy-on-close>
|
||||
<el-carousel :autoplay="false" indicator-position="outside" height="70vh" arrow="always">
|
||||
<el-carousel-item v-for="(img, i) in currentBrowserImages" :key="i"><div class="agent-page__guide-slide"><img :src="img" :alt="currentBrowserLabel + ' 安装步骤 ' + (i + 1)" /></div></el-carousel-item>
|
||||
</el-carousel>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<!-- ========== 第4步:配置求职助手 ========== -->
|
||||
<template v-if="currentStep === 4">
|
||||
<div v-if="!setupComplete" class="agent-page__step3">
|
||||
<!-- 返回上一步按钮 -->
|
||||
<button class="agent-page__back-btn" @click="handleBack">
|
||||
<svg viewBox="0 0 24 24" fill="none" width="16" height="16"><path d="M15 18l-6-6 6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
<span>返回上一步</span>
|
||||
</button>
|
||||
<div class="agent-page__left">
|
||||
<div class="agent-page__intro-card">
|
||||
<div class="agent-page__intro-header"><div class="agent-page__intro-icon"><svg viewBox="0 0 24 24" fill="none"><path d="M12 12c2.7 0 5-2.3 5-5s-2.3-5-5-5-5 2.3-5 5 2.3 5 5 5zm0 2c-3.3 0-10 1.7-10 5v2h20v-2c0-3.3-6.7-5-10-5z" fill="currentColor"/></svg></div><h2 class="agent-page__intro-title">马上就好啦!请选择你想要的投递模式</h2></div>
|
||||
<p class="agent-page__intro-desc">我已为你准备了关于自动化程度、简历生成及求职目标的灵活选项。请完成配置并确认。</p>
|
||||
<div class="dflex-center aliite-c"><button class="agent-page__confirm-btn" @click="handleStep4Complete">设置完成</button></div>
|
||||
<!-- 右侧:确认卡片 -->
|
||||
<div class="agent-page__left">
|
||||
<div class="agent-page__intro-card">
|
||||
<div class="agent-page__intro-header por">
|
||||
<div class="agent-page__intro-icon poa l-22 t0">
|
||||
<svg viewBox="0 0 24 24" fill="none"><path d="M12 12c2.7 0 5-2.3 5-5s-2.3-5-5-5-5 2.3-5 5 2.3 5 5 5zm0 2c-3.3 0-10 1.7-10 5v2h20v-2c0-3.3-6.7-5-10-5z" fill="currentColor"/></svg>
|
||||
</div>
|
||||
<h2 class="agent-page__intro-title">现在我们来开启自动投递吧</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="agent-page__right">
|
||||
<div class="agent-page__form-wrapper">
|
||||
<div class="agent-page__form-title">Agent设置</div>
|
||||
<AgentSettingsPanel ref="settingsPanelRef" :initial-config="initialConfig" />
|
||||
<p class="agent-page__intro-desc mb20">简单四步安装 Chrome 扩展程序<br/>实现自动填表,并一站式追踪所有申请进度。</p>
|
||||
<div class="agent-page__install-steps-list">
|
||||
<p>1. 下载offer派自动投递助手插件包</p>
|
||||
<p>2. 进入浏览器扩展程序界面</p>
|
||||
<p>3. 打开扩展程序开发人员模式</p>
|
||||
<p>4.拖入安装包,完成安装!</p>
|
||||
</div>
|
||||
<div class="mt30">
|
||||
<div class="tac"><button class="agent-page__confirm-btn dib" @click="handleNext">我已安装</button></div>
|
||||
<div class="tac color-9 mt30 cursor-po" @click="handleBack">返回上一步</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="agent-page__complete">
|
||||
</template>
|
||||
|
||||
<!-- ========== 第4步:完成配置 ========== -->
|
||||
<template v-if="currentStep === 4">
|
||||
<div class="agent-page__complete">
|
||||
<div class="agent-page__complete-icon"><svg viewBox="0 0 80 80" fill="none"><rect x="8" y="8" width="64" height="64" rx="8" fill="#E8E8E8"/><circle cx="40" cy="32" r="8" fill="#BFBFBF"/><path d="M20 60 L32 44 L44 52 L56 36 L64 44 L64 64 L20 64Z" fill="#BFBFBF"/></svg></div>
|
||||
<h2 class="agent-page__complete-title">恭喜你!你的求职助手已经准备好。</h2>
|
||||
<p class="agent-page__complete-desc">启用求职助手后你可以随时调整求职偏好及简历信息。</p>
|
||||
@@ -222,20 +265,19 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, watch, onMounted } from 'vue'
|
||||
import { ref, computed, watch, onMounted } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { formatEmploymentType } from '@/stores/index'
|
||||
import { formatEmploymentType, JOB_TYPE_OPTIONS } from '@/stores/index'
|
||||
import ProfilePageContent from '@/components/ProfilePageContent.vue'
|
||||
import ProfileEditDrawer from '@/components/ProfileEditDrawer.vue'
|
||||
import JobGoalDialog from '@/components/JobGoalDialog.vue'
|
||||
import AgentSettingsPanel from '@/components/AgentSettingsPanel.vue'
|
||||
import RegionSelector from '@/components/tools/RegionSelector.vue'
|
||||
import JobCategorySelector from '@/components/tools/JobCategorySelector.vue'
|
||||
import IndustrySelector from '@/components/tools/IndustrySelector.vue'
|
||||
import { saveProfile, saveEducation, saveWork, saveInternship, saveProject, saveCompetition, fetchProfile, fetchEducation, fetchWork, fetchInternship, fetchProject, fetchCompetition } from '@/api/profile'
|
||||
import type { SaveEducationItem, SaveWorkItem, SaveProjectItem, SaveCompetitionItem } from '@/api/profile'
|
||||
import { fetchJobList } from '@/api/jobs'
|
||||
import type { JobListItem } from '@/api/jobs'
|
||||
import { resolveRegionName } from '@/utils/region'
|
||||
import { resolveIndustryName } from '@/utils/industry'
|
||||
import { resolveJobCategoryName } from '@/utils/jobCategory'
|
||||
import { fetchResumeList, setDefaultResume } from '@/api/resume'
|
||||
import type { ResumeListItem } from '@/api/resume'
|
||||
import type { AgentConfig } from '@/api/agent'
|
||||
|
||||
const store = useStore()
|
||||
@@ -253,7 +295,7 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
// ==================== 步骤导航 ====================
|
||||
const steps = ['确认个人资料', '确认目标', '开启自动申请', '配置求职助手']
|
||||
const steps = ['确认个人资料', '确认目标', '安装插件', '配置求职助手']
|
||||
const currentStep = ref(1)
|
||||
|
||||
/** 进入下一步 */
|
||||
@@ -261,16 +303,9 @@ function handleNext() {
|
||||
if (currentStep.value < steps.length) currentStep.value++
|
||||
}
|
||||
|
||||
/** 返回上一步(含子阶段判断) */
|
||||
/** 返回上一步 */
|
||||
function handleBack() {
|
||||
if (currentStep.value === 3 && step3Sub.value === 2) {
|
||||
// 第3步的第2阶段 → 回到第3步第1阶段
|
||||
step3Sub.value = 1
|
||||
} else if (currentStep.value === 4) {
|
||||
// 第4步 → 回到第3步第2阶段(插件安装)
|
||||
currentStep.value = 3
|
||||
step3Sub.value = 2
|
||||
} else if (currentStep.value > 1) {
|
||||
if (currentStep.value > 1) {
|
||||
currentStep.value--
|
||||
}
|
||||
}
|
||||
@@ -400,106 +435,128 @@ async function handleSaveEdit(data: Record<string, any>) {
|
||||
|
||||
// ==================== 第2步:确认目标 ====================
|
||||
const showJobGoalDialog = ref(false)
|
||||
const intentionCategoryNames = computed(() => (store.state.jobIntention.categoryIds || []).map((id: number) => resolveJobCategoryName(id)))
|
||||
const intentionIndustryNames = computed(() => (store.state.jobIntention.industryIds || []).map((id: number) => resolveIndustryName(id)))
|
||||
const intentionRegionNames = computed(() => (store.state.jobIntention.regionCodes || []).map((code: string) => resolveRegionName(code)))
|
||||
const intentionEmploymentLabel = computed(() => formatEmploymentType(store.state.jobIntention.recruitCategory))
|
||||
|
||||
interface MatchedJobItem extends JobListItem { feedback: string }
|
||||
const matchedJobs = ref<MatchedJobItem[]>([])
|
||||
const loadingMatchJobs = ref(false)
|
||||
const showDislikeInput = ref(false)
|
||||
const dislikeReason = ref('')
|
||||
/** 招聘分类选项 */
|
||||
const jobTypeOptions = JOB_TYPE_OPTIONS
|
||||
/** 招聘分类下拉是否展开 */
|
||||
const showJobTypeDropdown = ref(false)
|
||||
|
||||
watch(showJobGoalDialog, (n, o) => { if (o === true && n === false) loadMatchedJobs() })
|
||||
watch(currentStep, (val) => { if (val === 2) loadMatchedJobs() })
|
||||
/** 选中招聘分类 */
|
||||
function selectJobType(option: { label: string; value: number }) {
|
||||
showJobTypeDropdown.value = false
|
||||
store.dispatch('saveJobIntention', {
|
||||
...store.state.jobIntention,
|
||||
recruitCategory: option.value,
|
||||
})
|
||||
}
|
||||
|
||||
async function loadMatchedJobs() {
|
||||
loadingMatchJobs.value = true; matchedJobs.value = []
|
||||
/** 第2步:求职偏好筛选组件 — 读写 store.jobIntention */
|
||||
const step2RegionCodes = computed<string[]>(() => store.state.jobIntention.regionCodes || [])
|
||||
const step2CategoryIds = computed<number[]>(() => store.state.jobIntention.categoryIds || [])
|
||||
const step2IndustryIds = computed<number[]>(() => store.state.jobIntention.industryIds || [])
|
||||
|
||||
/** 第2步:筛选组件统一触发按钮样式 — 大圆角胶囊按钮 */
|
||||
const prefFilterTriggerStyle = {
|
||||
padding: '0.1rem 0.28rem',
|
||||
borderRadius: '0.24rem',
|
||||
fontSize: '0.14rem',
|
||||
background: '#F5FAF9',
|
||||
border: '1px solid #e0e0e0',
|
||||
minWidth: '0.9rem',
|
||||
justifyContent: 'center',
|
||||
height: '0.38rem',
|
||||
boxSizing: 'border-box',
|
||||
}
|
||||
/** 第2步:筛选组件显示文字样式 */
|
||||
const prefFilterDisplayStyle = {
|
||||
maxWidth: 'none',
|
||||
}
|
||||
|
||||
/** 第2步:地区选择变更 */
|
||||
function onStep2RegionChange(codes: string[]) {
|
||||
store.dispatch('saveJobIntention', { ...store.state.jobIntention, regionCodes: codes })
|
||||
}
|
||||
|
||||
/** 第2步:岗位选择变更 */
|
||||
function onStep2CategoryChange(ids: number[]) {
|
||||
store.dispatch('saveJobIntention', { ...store.state.jobIntention, categoryIds: ids })
|
||||
}
|
||||
|
||||
/** 第2步:行业选择变更 */
|
||||
function onStep2IndustryChange(ids: number[]) {
|
||||
store.dispatch('saveJobIntention', { ...store.state.jobIntention, industryIds: ids })
|
||||
}
|
||||
|
||||
/** 第2步:简历列表 */
|
||||
const resumeList = ref<ResumeListItem[]>([])
|
||||
/** 选中的简历 ID */
|
||||
const selectedResumeId = ref('')
|
||||
/** 自动优化简历开关 */
|
||||
const autoOptimizeSwitch = ref(true)
|
||||
/** 岗位匹配分析开关 */
|
||||
const autoMatchAnalysisSwitch = ref(true)
|
||||
|
||||
/** 加载简历列表 */
|
||||
async function loadResumeList() {
|
||||
try {
|
||||
const intention = store.state.jobIntention
|
||||
const res = await fetchJobList({ pageNum: 1, pageSize: 30, regionCodes: intention.regionCodes?.length ? intention.regionCodes : undefined, categoryIds: intention.categoryIds?.length ? intention.categoryIds : undefined, industryIds: intention.industryIds?.length ? intention.industryIds : undefined, recruitCategory: intention.recruitCategory ?? undefined })
|
||||
if (res.code === '0' && res.data && res.data.list.length > 0) {
|
||||
const shuffled = [...res.data.list].sort(() => Math.random() - 0.5)
|
||||
matchedJobs.value = shuffled.slice(0, 3).map(item => ({ ...item, feedback: '' }))
|
||||
const res = await fetchResumeList()
|
||||
if (res.code === '0' && res.data) {
|
||||
resumeList.value = res.data
|
||||
const defaultResume = res.data.find(r => r.isDefault === 1)
|
||||
if (defaultResume && defaultResume.id) {
|
||||
selectedResumeId.value = defaultResume.id
|
||||
} else if (res.data.length > 0 && res.data[0].id) {
|
||||
selectedResumeId.value = res.data[0].id
|
||||
}
|
||||
}
|
||||
} catch (e) { console.error('[AgentSetupWizard] 加载匹配岗位失败', e) }
|
||||
finally { loadingMatchJobs.value = false }
|
||||
} catch { console.error('[AgentSetupWizard] 加载简历列表失败') }
|
||||
}
|
||||
|
||||
function handleDislike(index: number) {
|
||||
const job = matchedJobs.value[index]
|
||||
if (job.feedback === 'dislike') { job.feedback = ''; showDislikeInput.value = false }
|
||||
else { job.feedback = 'dislike'; showDislikeInput.value = true }
|
||||
}
|
||||
/** 进入第2步时加载简历列表 */
|
||||
watch(currentStep, (val) => { if (val === 2) loadResumeList() })
|
||||
|
||||
// ==================== 第3步:网申常见问题 ====================
|
||||
const isInternship = computed(() => store.state.jobIntention.recruitCategory === 2)
|
||||
const step3Sub = ref(1)
|
||||
const step3Form = reactive({
|
||||
acceptDeptTransfer: '', acceptLocationTransfer: '',
|
||||
interviewType: [] as string[],
|
||||
languages: [{ language: '', proficiency: '' }] as Array<{ language: string; proficiency: string }>,
|
||||
availableDate: '', internDaysPerWeek: '', internDuration: '',
|
||||
/** 选择简历后设为默认简历 */
|
||||
watch(selectedResumeId, async (newId, oldId) => {
|
||||
// 仅在用户主动切换时调用接口(非初始化加载)
|
||||
if (!newId || !oldId) return
|
||||
try {
|
||||
await setDefaultResume(newId)
|
||||
} catch { console.error('[AgentSetupWizard] 设置默认简历失败') }
|
||||
})
|
||||
|
||||
/** 监听初始配置数据 — 填充第3步表单 */
|
||||
watch(() => props.initialConfig, (cfg) => {
|
||||
if (!cfg) return
|
||||
step3Form.acceptDeptTransfer = cfg.acceptDeptTransfer || ''
|
||||
step3Form.acceptLocationTransfer = cfg.acceptLocationTransfer || ''
|
||||
step3Form.interviewType = cfg.interviewType ? [...cfg.interviewType] : []
|
||||
step3Form.languages = cfg.languages?.length ? cfg.languages.map(l => ({ language: l.language || '', proficiency: l.proficiency || '' })) : [{ language: '', proficiency: '' }]
|
||||
step3Form.availableDate = cfg.availableDate || ''
|
||||
step3Form.internDaysPerWeek = cfg.internDaysPerWeek || ''
|
||||
step3Form.internDuration = cfg.internDuration || ''
|
||||
}, { immediate: true })
|
||||
const languageOptions = ['英语', '日语', '法语', '德语', '韩语', '西班牙语', '俄语']
|
||||
const proficiencyOptions = ['入门', '日常会话', '商务会话', '无障碍沟通', '母语']
|
||||
const availableDateOptions = ['一周以内', '两周以内', '一个月以内', '一个月以上']
|
||||
const internDaysOptions = ['3天及以上', '4天及以上', '5天及以上']
|
||||
const internDurationOptions = ['3个月', '4个月', '5个月', '6个月及以上']
|
||||
function toggleInterviewType(type: string) { const idx = step3Form.interviewType.indexOf(type); idx >= 0 ? step3Form.interviewType.splice(idx, 1) : step3Form.interviewType.push(type) }
|
||||
|
||||
// ==================== 第3步下半部分:插件安装 ====================
|
||||
// ==================== 第3步:安装插件 ====================
|
||||
/** 插件下载地址 */
|
||||
const extensionDownloadUrl = 'https://offerpie.oss-cn-guangzhou.aliyuncs.com/extension/chrome-mv3-prod.rar'
|
||||
const browserList = [{ key: 'chrome', label: 'Chrome浏览器' }, { key: 'edge', label: 'Edge浏览器' }, { key: 'safari', label: 'Safari浏览器' }, { key: '360', label: '360浏览器' }, { key: 'qq', label: 'QQ浏览器' }]
|
||||
const browserImageCount: Record<string, number> = { chrome: 3, edge: 3, safari: 3, '360': 3, qq: 3 }
|
||||
const guidanceImageBase = 'http://offerpie.oss-cn-guangzhou.aliyuncs.com/extension/guidance_image'
|
||||
const showBrowserGuide = ref(false)
|
||||
const currentBrowserKey = ref('')
|
||||
const currentBrowserLabel = computed(() => browserList.find(b => b.key === currentBrowserKey.value)?.label || '')
|
||||
const currentBrowserImages = computed(() => { const key = currentBrowserKey.value; if (!key) return []; const count = browserImageCount[key] || 3; return Array.from({ length: count }, (_, i) => `${guidanceImageBase}/guidance-image-${key}-${String(i + 1).padStart(2, '0')}.png`) })
|
||||
function openBrowserGuide(key: string) { currentBrowserKey.value = key; showBrowserGuide.value = true }
|
||||
|
||||
/** 下载插件 */
|
||||
function downloadExtension() { window.open(extensionDownloadUrl, '_blank') }
|
||||
|
||||
// ==================== 第4步:配置求职助手 ====================
|
||||
const settingsPanelRef = ref<InstanceType<typeof AgentSettingsPanel> | null>(null)
|
||||
const setupComplete = ref(false)
|
||||
|
||||
/** 设置完成 — 收集第3步+第4步数据,通过 emit 传回父组件 */
|
||||
function handleStep4Complete() {
|
||||
const step4Data = settingsPanelRef.value?.getData()
|
||||
const allSettings = {
|
||||
jobType: store.state.jobIntention.recruitCategory === 2 ? 1 : 2,
|
||||
agentMode: step4Data?.agentMode ?? 1,
|
||||
weeklyTarget: step4Data?.weeklyTarget ?? 2,
|
||||
autoOptimizeResume: step4Data?.autoOptimizeResume ?? 1,
|
||||
acceptDeptTransfer: step3Form.acceptDeptTransfer,
|
||||
acceptLocationTransfer: step3Form.acceptLocationTransfer,
|
||||
interviewType: [...step3Form.interviewType],
|
||||
languages: step3Form.languages.filter(l => l.language),
|
||||
availableDate: step3Form.availableDate,
|
||||
internDaysPerWeek: step3Form.internDaysPerWeek,
|
||||
internDuration: step3Form.internDuration,
|
||||
status:1,
|
||||
}
|
||||
emit('complete', allSettings)
|
||||
setupComplete.value = true
|
||||
/** 复制文本到剪贴板 */
|
||||
function copyToClipboard(text: string) {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
ElMessage.success('已复制到剪贴板')
|
||||
}).catch(() => {
|
||||
ElMessage.error('复制失败,请手动复制')
|
||||
})
|
||||
}
|
||||
|
||||
/** 启用求职助手 */
|
||||
function handleLaunchAgent() { emit('launch') }
|
||||
// ==================== 第4步:配置求职助手 ====================
|
||||
|
||||
/** 启用求职助手 — 收集第2步数据,通过 emit 传回父组件并触发 launch */
|
||||
function handleLaunchAgent() {
|
||||
const allSettings = {
|
||||
jobType: store.state.jobIntention.recruitCategory === 2 ? 1 : 2,
|
||||
agentMode: 1,
|
||||
weeklyTarget: 2,
|
||||
autoOptimizeResume: autoOptimizeSwitch.value ? 1 : 0,
|
||||
autoMatchAnalysis: autoMatchAnalysisSwitch.value ? 1 : 0,
|
||||
defaultResumeId: selectedResumeId.value,
|
||||
status: 1,
|
||||
}
|
||||
emit('complete', allSettings)
|
||||
emit('launch')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
Reference in New Issue
Block a user