From 4d146fb1e4d646759bbe1a6d2ba912de21c8c95b Mon Sep 17 00:00:00 2001 From: chashaobao Date: Thu, 6 Nov 2025 00:06:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BB=A3=E6=8B=9B=E4=BB=A3=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/job-manage-card/index.less | 34 ++++- src/components/job-manage-card/index.tsx | 28 +++++ src/components/user-batch-publish/index.less | 43 ++++++- src/components/user-batch-publish/index.tsx | 117 ++++++++++-------- src/fragments/profile/view/index.tsx | 4 +- src/hooks/use-config.tsx | 2 +- src/hooks/use-publish-job.ts | 56 +++++++++ .../group-delegate-publish/index.config.ts | 2 +- src/pages/group-delegate-publish/index.tsx | 15 ++- src/pages/group-owner-certification/index.tsx | 24 ++-- src/pages/job-detail/index.tsx | 45 +------ src/pages/user-batch-publish/index.tsx | 86 ++++++------- src/pages/user/index.less | 4 + src/types/job.ts | 2 +- 14 files changed, 300 insertions(+), 162 deletions(-) create mode 100644 src/hooks/use-publish-job.ts diff --git a/src/components/job-manage-card/index.less b/src/components/job-manage-card/index.less index 235e1a4..7b5f004 100644 --- a/src/components/job-manage-card/index.less +++ b/src/components/job-manage-card/index.less @@ -6,12 +6,12 @@ height: 152px; .flex-row(); padding: 24px 32px; - background: #FFF; + background: #fff; box-sizing: border-box; position: relative; &::after { - content: ""; + content: ''; height: 2px; background: #00000026; position: absolute; @@ -52,7 +52,11 @@ &__status { height: 100%; - .flex-row(); + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-end; + gap: 24px; font-size: 28px; line-height: 32px; font-weight: 400; @@ -63,7 +67,27 @@ } &.error { - color: #FF5051; + color: #ff5051; } } -} \ No newline at end of file + + &__buy-tag { + padding: 8px; + background: rgba(255, 80, 81, 0.12); + border-radius: 4px; + font-size: 24px; + line-height: 24px; + color: #ff5051; + .flex-row(); + + &-wrapper { + padding-top: 8px; + } + + &-icon { + width: 13px; + height: 18px; + margin-right: 5px; + } + } +} diff --git a/src/components/job-manage-card/index.tsx b/src/components/job-manage-card/index.tsx index 476f545..eb36204 100644 --- a/src/components/job-manage-card/index.tsx +++ b/src/components/job-manage-card/index.tsx @@ -1,6 +1,10 @@ +import { Image } from '@tarojs/components'; + +import { Arrow } from '@taroify/icons'; import classNames from 'classnames'; import React, { useCallback } from 'react'; +import { cityValues } from '@/components/user-batch-publish'; import { PageUrl } from '@/constants/app'; import { JOB_MANAGE_STATUS_TITLE_MAP, JobManageStatus } from '@/constants/job'; import { JobManageInfo } from '@/types/job'; @@ -25,6 +29,29 @@ const STATUS_CLASS_MAP = { [JobManageStatus.Expire]: 'close', }; +function GoBatchTag({ cityCode, jobId }: { cityCode: string; jobId: JobManageInfo['id'] }) { + const handleClick = useCallback( + e => { + e.preventDefault(); + e.stopPropagation(); + navigateTo(PageUrl.GroupDelegatePublish, { cityCode, jobId }); + }, + [cityCode, jobId] + ); + if (!cityValues.find(c => c.cityCode === cityCode)) { + return null; + } + return ( +
+
+ +
加速招聘
+ +
+
+ ); +} + function JobManageCard(props: IProps) { const { data = {} } = props; const { id, title, status } = data as JobManageInfo; @@ -41,6 +68,7 @@ function JobManageCard(props: IProps) {
{JOB_MANAGE_STATUS_TITLE_MAP[status]}
+
); diff --git a/src/components/user-batch-publish/index.less b/src/components/user-batch-publish/index.less index f43a4df..bc02306 100644 --- a/src/components/user-batch-publish/index.less +++ b/src/components/user-batch-publish/index.less @@ -13,9 +13,9 @@ &__title { font-size: 32px; line-height: 48px; - font-weight: 500; - color: @blColor; - margin-top: 24px; + margin-top: 32px; + font-weight: 400; + color: #1d2129; &:first-child { margin-top: 0; @@ -30,13 +30,21 @@ margin-top: 24px; } + &__extra { + margin-top: 24px; + font-weight: 400; + font-size: 24px; + line-height: 40px; + color: @blHighlightColor; + } + &__cost-describe { height: 100px; padding: 0 32px; border-radius: 16px; .flex-row(); justify-content: space-between; - background: #FFFFFF; + background: #ffffff; margin-top: 24px; &__price { @@ -64,9 +72,22 @@ line-height: 48px; font-weight: 400; color: @blColorG2; - background: #FFFFFF; + background: #ffffff; border-radius: 16px; + .underline { + display: inline; + font-weight: 500; + font-size: 32px; + line-height: 48px; + color: @blColor; + position: relative; + background-image: linear-gradient(to bottom, rgba(109, 61, 245, 0.6) 0%, rgba(109, 61, 245, 0.6) 100%); + background-repeat: no-repeat; + background-size: 100% 12px; + background-position: bottom; + } + &__describe { .flex-row(); font-size: 28px; @@ -86,4 +107,16 @@ .button(@width: 100%; @height: 80px; @fontSize: 32px); margin-top: 40px; } + + &__publish-title { + font-size: 36px; + font-weight: 500; + line-height: 56px; + color: @blColor; + } + + &__publish-button { + .button(@width: 360px, @height: 72px, @fontSize: 28px, @fontWeight: 400, @borderRadius: 44px); + margin: 40px auto auto; + } } diff --git a/src/components/user-batch-publish/index.tsx b/src/components/user-batch-publish/index.tsx index 999bbd5..b8db202 100644 --- a/src/components/user-batch-publish/index.tsx +++ b/src/components/user-batch-publish/index.tsx @@ -1,17 +1,21 @@ -import { Button, Text } from '@tarojs/components'; +import { Button } from '@tarojs/components'; import Taro from '@tarojs/taro'; -import { Cell } from '@taroify/core'; -import { useCallback, useState, useEffect } from 'react'; +import { Cell, Dialog } from '@taroify/core'; +import { Fragment, useCallback, useEffect, useState } from 'react'; import PageLoading from '@/components/page-loading'; import { PublishJobQrCodeDialog } from '@/components/product-dialog/publish-job'; +import CompanyPublishJobBuy from '@/components/product-dialog/steps-ui/company-publish-job-buy'; import SafeBottomPadding from '@/components/safe-bottom-padding'; -import { ISelectOption, PopupSelect } from '@/components/select'; +import { ISelectOption } from '@/components/select'; import { PageUrl } from '@/constants/app'; +import { JobManageStatus } from '@/constants/job'; import { OrderStatus, OrderType, ProductSpecId, ProductType } from '@/constants/product'; +import { usePublishJob } from '@/hooks/use-publish-job'; import { BatchPublishGroup } from '@/types/group'; import { logWithPrefix } from '@/utils/common'; +import { requestJobDetail } from '@/utils/job'; import { getOrderPrice, isCancelPay, @@ -22,7 +26,6 @@ import { } from '@/utils/product'; import { navigateTo } from '@/utils/route'; import Toast from '@/utils/toast'; - import './index.less'; interface CityValue extends BatchPublishGroup { @@ -35,11 +38,7 @@ interface CityOption extends ISelectOption { const PREFIX = 'user-batch-publish'; const log = logWithPrefix(PREFIX); -const SERVICE_ILLUSTRATE = `服务方式:帮您把招聘需求发到众多同城合作主播群 -群发次数:杭州、广州发3次,其他城市1次 -内容要求:仅限带货主播招聘需求,其他不发 -主播联系:内容中留招聘方联系方式,主播直接联系`; -const cityValues: CityValue[] = [ +export const cityValues: CityValue[] = [ { cityCode: '440100', cityName: '广州', count: 800 }, { cityCode: '440300', cityName: '深圳', count: 100 }, { cityCode: '330100', cityName: '杭州', count: 750 }, @@ -79,20 +78,14 @@ const calcPrice = (city: CityValue | null) => { return { price, originalPrice, productSpecId }; }; -export default function UserBatchPublish() { +export default function UserBatchPublish({ cityCode, jobId }: { cityCode: string; jobId: string }) { const [loading, setLoading] = useState(true); - const [showCitySelect, setShowCitySelect] = useState(false); const [showQrCode, setShowQrCode] = useState(false); const [city, setCity] = useState(null); - const [cityOptions, setCityOptions] = useState([]); const { price, originalPrice, productSpecId } = calcPrice(city); + const [showPublishJob, setShowPublishJob] = useState(false); - const handleClickCity = useCallback(() => setShowCitySelect(true), []); - - const handleSelectCity = useCallback(value => { - setCity(value); - setShowCitySelect(false); - }, []); + const [showBuy, setShowBuy, handlePublishJob] = usePublishJob(jobId); const handleClickViewGroup = useCallback(() => navigateTo(PageUrl.GroupList, { city: city?.cityCode }), [city]); @@ -114,6 +107,14 @@ export default function UserBatchPublish() { setShowQrCode(true); return; } + + const jobDetail = await requestJobDetail(jobId); + + if (jobDetail.status !== JobManageStatus.Open) { + setShowPublishJob(true); + return; + } + const { payOrderNo, createPayInfo } = await requestCreatePayInfo({ type: OrderType.GroupBatchPublish, amt: getOrderPrice(price), @@ -141,21 +142,25 @@ export default function UserBatchPublish() { Toast.error(isCancelPay(e) ? '取消购买' : '购买失败请重试'); log('handleBuy error', e); } - }, [price, productSpecId]); + }, [jobId, price, productSpecId]); useEffect(() => { + if (!cityCode) { + return; + } try { - const cOptions: CityOption[] = cityValues.map(value => ({ value, label: value.cityName })); - const initCity = (cOptions.find(o => o.label === '重庆') || cOptions[0]).value; + const initCity = cityValues.find(o => o.cityCode === cityCode); setLoading(false); - setCity(initCity); - setCityOptions(cOptions); - log('init data done', cOptions); + if (initCity) { + setCity(initCity); + } else { + Toast.info('当前城市不支持代发'); + } } catch (e) { Toast.error('加载失败请重试'); } - }, []); + }, [cityCode]); if (loading) { return ; @@ -164,38 +169,46 @@ export default function UserBatchPublish() { return (
{/**/} -
请选择城市
- -
可购买群数
- -
服务费用
-
-
{`${price}元`}
-
{`原价:${originalPrice}元`}
-
服务说明
- {SERVICE_ILLUSTRATE} -
-
附:
-
- 播络合作群列表 -
-
+ 服务方式:帮您把招聘需求
发到本地主播群,投递量大幅增加
- +
当前通告城市
+ + {city && ( + +
+ 查看该城市合作群列表 +
+
可购买群数
+ +
服务费用
+
+
{`${price}元`}
+
{`原价:${originalPrice}元`}
+
+ + +
+ )}
- setShowCitySelect(false)} - /> setShowQrCode(false)} open={showQrCode} /> + setShowBuy(false)}> + + + + + setShowPublishJob(false)}> + +
请先发布通告
+ +
+
); diff --git a/src/fragments/profile/view/index.tsx b/src/fragments/profile/view/index.tsx index 088f33e..cbc42b2 100644 --- a/src/fragments/profile/view/index.tsx +++ b/src/fragments/profile/view/index.tsx @@ -254,9 +254,9 @@ export default function ProfileViewFragment(props: IProps) { )} -
+
{getBasicInfo(profile)}
-
+
{dataGroup.map((data, index: number) => ( diff --git a/src/hooks/use-config.tsx b/src/hooks/use-config.tsx index 33e8984..95a3329 100644 --- a/src/hooks/use-config.tsx +++ b/src/hooks/use-config.tsx @@ -48,7 +48,7 @@ const CompanyTabs: TabItemType[] = [ { type: PageType.BatchPublish, pagePath: PageUrl.UserBatchPublish, - text: '代招代发', + text: '代招', }, ]; diff --git a/src/hooks/use-publish-job.ts b/src/hooks/use-publish-job.ts new file mode 100644 index 0000000..de5806d --- /dev/null +++ b/src/hooks/use-publish-job.ts @@ -0,0 +1,56 @@ +import Taro from '@tarojs/taro'; + +import { Dispatch, SetStateAction, useCallback, useState } from 'react'; + +import { EventName, PageUrl } from '@/constants/app'; +import { CertificationStatusType } from '@/constants/company'; +import { CollectEventName } from '@/constants/event'; +import useUserInfo from '@/hooks/use-user-info'; +import { RESPONSE_ERROR_CODE } from '@/http/constant'; +import { HttpError } from '@/http/error'; +import store from '@/store'; +import { cacheJobId } from '@/store/actions'; +import { collectEvent } from '@/utils/event'; +import { postPublishJob } from '@/utils/job'; +import { navigateTo } from '@/utils/route'; +import Toast from '@/utils/toast'; + +export const usePublishJob = (jobId: string): [boolean, Dispatch>, () => Promise] => { + const userInfo = useUserInfo(); + const [showBuy, setShowBuy] = useState(false); + + const handlePublishJob = useCallback(async () => { + try { + if (userInfo.bossAuthStatus !== CertificationStatusType.Success) { + store.dispatch(cacheJobId(jobId)); + navigateTo(PageUrl.CertificationStart); + return; + } + Taro.showLoading(); + await postPublishJob(jobId); + Taro.eventCenter.trigger(EventName.COMPANY_JOB_PUBLISH_CHANGED); + setShowBuy(false); + Toast.success('发布成功'); + Taro.hideLoading(); + } catch (error) { + Taro.hideLoading(); + const e = error as HttpError; + const errorCode = e.errorCode; + const errorMsg = e.info?.() || e.message; + collectEvent(CollectEventName.PUBLISH_OPEN_JOB_FAILED, { jobId, error: e.info?.() || e.message }); + if (errorCode === RESPONSE_ERROR_CODE.INSUFFICIENT_FREE_BALANCE) { + setShowBuy(true); + } else if (errorCode === RESPONSE_ERROR_CODE.INSUFFICIENT_BALANCE) { + Toast.info('您购买的产品已耗尽使用次数'); + setShowBuy(true); + } else if (errorCode === RESPONSE_ERROR_CODE.BOSS_VIP_EXPIRED) { + Toast.info('该通告已到期,请创建新通告', 3000); + } else { + Toast.error(errorMsg || '发布失败请重试', 3000); + } + console.error(e); + } + }, [jobId, userInfo.bossAuthStatus]); + + return [showBuy, setShowBuy, handlePublishJob]; +}; diff --git a/src/pages/group-delegate-publish/index.config.ts b/src/pages/group-delegate-publish/index.config.ts index 643b0e4..872bdc9 100644 --- a/src/pages/group-delegate-publish/index.config.ts +++ b/src/pages/group-delegate-publish/index.config.ts @@ -1,3 +1,3 @@ export default definePageConfig({ - navigationBarTitleText: '群代发', + navigationBarTitleText: '加速招聘', }); diff --git a/src/pages/group-delegate-publish/index.tsx b/src/pages/group-delegate-publish/index.tsx index 58fdbb8..acc0446 100644 --- a/src/pages/group-delegate-publish/index.tsx +++ b/src/pages/group-delegate-publish/index.tsx @@ -1,12 +1,25 @@ +import { useLoad } from '@tarojs/taro'; + +import { useState } from 'react'; + import UserBatchPublish from '@/components/user-batch-publish'; +import { getPageQuery } from '@/utils/route'; import './index.less'; const PREFIX = 'group-delegate-publish'; export default function Partner() { + const [cityCode, setCityCode] = useState(''); + const [jobId, setJobId] = useState(''); + + useLoad(() => { + const query = getPageQuery<{ cityCode: string; jobId: string }>(); + setCityCode(query.cityCode); + setJobId(query.jobId); + }); return (
- +
); } diff --git a/src/pages/group-owner-certification/index.tsx b/src/pages/group-owner-certification/index.tsx index e9777e9..24e4f9e 100644 --- a/src/pages/group-owner-certification/index.tsx +++ b/src/pages/group-owner-certification/index.tsx @@ -3,7 +3,7 @@ import Taro, { useShareAppMessage } from '@tarojs/taro'; import { Tabs } from '@taroify/core'; import { Arrow } from '@taroify/icons'; -import { useCallback, useEffect, useRef, useState } from 'react'; +import { Fragment, useCallback, useEffect, useRef, useState } from 'react'; import GroupCertificationList from '@/components/group-certification-list'; import { EventName, OpenSource, PageUrl } from '@/constants/app'; @@ -92,19 +92,21 @@ export default function GroupOwnerCertification() {
选择城市,添加运营
- {CITY_CODE_TO_NAME_MAP.get(cityCode)} + {CITY_CODE_TO_NAME_MAP.get(cityCode) || '请选择城市'}
-
-
长按并识别二维码添加运营
-
{staffInfo && ( - + +
+
长按并识别二维码添加运营
+
+ +
)}
第二步
diff --git a/src/pages/job-detail/index.tsx b/src/pages/job-detail/index.tsx index c44679b..35d61a0 100644 --- a/src/pages/job-detail/index.tsx +++ b/src/pages/job-detail/index.tsx @@ -16,22 +16,21 @@ import ProductJobDialog from '@/components/product-dialog/job'; import CompanyPublishJobBuy from '@/components/product-dialog/steps-ui/company-publish-job-buy'; import { EventName, PageUrl, RoleType } from '@/constants/app'; import { CertificationStatusType } from '@/constants/company'; -import { CollectEventName, ReportEventId } from '@/constants/event'; +import { ReportEventId } from '@/constants/event'; import { EMPLOY_TYPE_TITLE_MAP, GET_CONTACT_TYPE, JobManageStatus } from '@/constants/job'; import { ProductType } from '@/constants/product'; import useInviteCode from '@/hooks/use-invite-code'; +import { usePublishJob } from '@/hooks/use-publish-job'; import useUserInfo from '@/hooks/use-user-info'; import useRoleType from '@/hooks/user-role-type'; import { RESPONSE_ERROR_CODE } from '@/http/constant'; import { HttpError } from '@/http/error'; -import store from '@/store'; -import { cacheJobId } from '@/store/actions'; import { JobDetails } from '@/types/job'; import { IMaterialMessage } from '@/types/message'; import { switchRoleType } from '@/utils/app'; import { copy, logWithPrefix } from '@/utils/common'; -import { collectEvent, reportEvent } from '@/utils/event'; -import { getJobSalary, getJobTitle, postPublishJob, requestJobDetail } from '@/utils/job'; +import { reportEvent } from '@/utils/event'; +import { getJobSalary, getJobTitle, requestJobDetail } from '@/utils/job'; import { calcDistance, isValidLocation } from '@/utils/location'; import { requestProfileDetail } from '@/utils/material'; import { isChatWithSelf, postCreateChat } from '@/utils/message'; @@ -176,44 +175,10 @@ const AnchorFooter = (props: { data: JobDetails }) => { const CompanyFooter = (props: { data: JobDetails }) => { const { data } = props; - const [showBuy, setShowBuy] = useState(false); - const userInfo = useUserInfo(); + const [showBuy, setShowBuy, handlePublishJob] = usePublishJob(data.id); const handleClickEdit = useCallback(() => navigateTo(PageUrl.JobPublish, { jobId: data.id }), [data]); - const handlePublishJob = useCallback(async () => { - try { - if (userInfo.bossAuthStatus !== CertificationStatusType.Success) { - store.dispatch(cacheJobId(data.id)); - navigateTo(PageUrl.CertificationStart); - return; - } - Taro.showLoading(); - await postPublishJob(data.id); - Taro.eventCenter.trigger(EventName.COMPANY_JOB_PUBLISH_CHANGED); - setShowBuy(false); - Toast.success('发布成功'); - Taro.hideLoading(); - } catch (error) { - Taro.hideLoading(); - const e = error as HttpError; - const errorCode = e.errorCode; - const errorMsg = e.info?.() || e.message; - collectEvent(CollectEventName.PUBLISH_OPEN_JOB_FAILED, { jobId: data.id, error: e.info?.() || e.message }); - if (errorCode === RESPONSE_ERROR_CODE.INSUFFICIENT_FREE_BALANCE) { - setShowBuy(true); - } else if (errorCode === RESPONSE_ERROR_CODE.INSUFFICIENT_BALANCE) { - Toast.info('您购买的产品已耗尽使用次数'); - setShowBuy(true); - } else if (errorCode === RESPONSE_ERROR_CODE.BOSS_VIP_EXPIRED) { - Toast.info('该通告已到期,请创建新通告', 3000); - } else { - Toast.error(errorMsg || '发布失败请重试', 3000); - } - console.error(e); - } - }, [data]); - return ( <>
diff --git a/src/pages/user-batch-publish/index.tsx b/src/pages/user-batch-publish/index.tsx index e39e0df..9b83330 100644 --- a/src/pages/user-batch-publish/index.tsx +++ b/src/pages/user-batch-publish/index.tsx @@ -1,4 +1,4 @@ -import { Image } from '@tarojs/components'; +// import { Image } from '@tarojs/components'; import Taro, { useLoad, useShareAppMessage } from '@tarojs/taro'; import { Button, Tabs } from '@taroify/core'; @@ -12,29 +12,29 @@ import useInviteCode from '@/hooks/use-invite-code'; import { switchRoleType } from '@/utils/app'; import { openCustomerServiceChat } from '@/utils/common'; import { getCurrentCityCode } from '@/utils/location'; -import { getPageQuery, navigateTo } from '@/utils/route'; +import { getPageQuery } from '@/utils/route'; import { getCommonShareMessage } from '@/utils/share'; import { checkCityCode } from '@/utils/user'; import './index.less'; const PREFIX = 'page-biz-service'; -const EXAMPLE_IMAGE = 'https://publiccdn.neighbourhood.com.cn/img/delegate-example.png'; -const COMMENT_IMAGE = 'https://publiccdn.neighbourhood.com.cn/img/delegate-comments.png'; +// const EXAMPLE_IMAGE = 'https://publiccdn.neighbourhood.com.cn/img/delegate-example.png'; +// const COMMENT_IMAGE = 'https://publiccdn.neighbourhood.com.cn/img/delegate-comments.png'; export default function BizService() { const inviteCode = useInviteCode(); const cityOperators = useCityOperators(); - const [value, setValue] = useState('0'); + const [value, setValue] = useState('2'); - const handleClickDelegate = useCallback(() => { - navigateTo(PageUrl.GroupDelegatePublish); - }, []); - const handlePreview = (current: string) => { - Taro.previewImage({ - current, - urls: [EXAMPLE_IMAGE, COMMENT_IMAGE], - }); - }; + // const handleClickDelegate = useCallback(() => { + // navigateTo(PageUrl.GroupDelegatePublish); + // }, []); + // const handlePreview = (current: string) => { + // Taro.previewImage({ + // current, + // urls: [EXAMPLE_IMAGE, COMMENT_IMAGE], + // }); + // }; const handleOpenService = useCallback(() => { openCustomerServiceChat('https://work.weixin.qq.com/kfid/kfcd60708731367168d'); }, []); @@ -80,35 +80,35 @@ export default function BizService() {
- -
- -
服务说明
-
-
服务方式:帮您把招聘需求发到众多同城合作主播群
-
群发次数:杭州、广州发3次,其他城市1次
-
内容要求:仅限带货主播招聘需求,其他不发
-
主播联系:内容中留招聘方联系方式,主播直接联系
-
-
代发示例
-
handlePreview(EXAMPLE_IMAGE)}> - -
-
部分客户评价
-
handlePreview(COMMENT_IMAGE)}> - -
-
- -
-
-
+ {/**/} + {/*
*/} + {/* */} + {/*
服务说明
*/} + {/*
*/} + {/*
服务方式:帮您把招聘需求发到众多同城合作主播群
*/} + {/*
群发次数:杭州、广州发3次,其他城市1次
*/} + {/*
内容要求:仅限带货主播招聘需求,其他不发
*/} + {/*
主播联系:内容中留招聘方联系方式,主播直接联系
*/} + {/*
*/} + {/*
代发示例
*/} + {/*
handlePreview(EXAMPLE_IMAGE)}>*/} + {/* */} + {/*
*/} + {/*
部分客户评价
*/} + {/*
handlePreview(COMMENT_IMAGE)}>*/} + {/* */} + {/*
*/} + {/*
*/} + {/* */} + {/*
*/} + {/*
*/} + {/*
*/}