From e04675d672d91138bc6eb4e7823f011f0fec6511 Mon Sep 17 00:00:00 2001 From: zhengyiming <540361168@qq.com> Date: 星期五, 08 八月 2025 16:30:41 +0800 Subject: [PATCH] fix: 任务详情 --- apps/cMiniApp/src/subpackages/task/components/CompanyDesc.vue | 10 + apps/cMiniApp/project.private.config.json | 7 + apps/cMiniApp/src/subpackages/task/companyDetail/companyDetail.vue | 36 +---- packages/services/apiV2/auth.ts | 23 +++ types/api.d.ts | 4 apps/cMiniApp/src/subpackages/task/taskDetail/InnerPage.vue | 12 + apps/cMiniApp/src/subpackages/task/components/CompanyTaskList.vue | 4 apps/cMiniApp/src/subpackages/task/components/CompanyInfo.vue | 18 ++ packages/services/apiV2/index.ts | 28 ++-- packages/hooks/index.ts | 1 apps/cMiniApp/src/constants/app.ts | 2 packages/services/apiV2/task.ts | 19 +- packages/services/apiV2/typings.d.ts | 145 +++++++++++++----------- packages/constants/apiEnum.ts | 14 -- packages/hooks/enterprise.ts | 29 ++++ 15 files changed, 204 insertions(+), 148 deletions(-) diff --git a/apps/cMiniApp/project.private.config.json b/apps/cMiniApp/project.private.config.json index c7ac5b7..ca80844 100644 --- a/apps/cMiniApp/project.private.config.json +++ b/apps/cMiniApp/project.private.config.json @@ -9,6 +9,13 @@ "miniprogram": { "list": [ { + "name": "鍏徃璇︽儏", + "pathName": "subpackages/task/companyDetail/companyDetail", + "query": "id=f775538f-985c-4d51-7985-08ddd5c71bbf", + "launchMode": "default", + "scene": null + }, + { "name": "浠诲姟璇︽儏", "pathName": "subpackages/task/taskDetail/taskDetail", "query": "id=04c75425-e783-4dbf-0f16-08ddd626b756", diff --git a/apps/cMiniApp/src/constants/app.ts b/apps/cMiniApp/src/constants/app.ts index bcda41b..cd671f7 100644 --- a/apps/cMiniApp/src/constants/app.ts +++ b/apps/cMiniApp/src/constants/app.ts @@ -1,6 +1,6 @@ import { EnumUserType, EnumClientType } from '@12333/constants'; export const AppLocalConfig = { - userType: EnumUserType.Operation, + userType: EnumUserType.Enterprise, clientType: EnumClientType.PcWeb, }; diff --git a/apps/cMiniApp/src/subpackages/task/companyDetail/companyDetail.vue b/apps/cMiniApp/src/subpackages/task/companyDetail/companyDetail.vue index c501244..5cbc167 100644 --- a/apps/cMiniApp/src/subpackages/task/companyDetail/companyDetail.vue +++ b/apps/cMiniApp/src/subpackages/task/companyDetail/companyDetail.vue @@ -2,7 +2,12 @@ <PageLayoutWithBg class="companyDetail-page-wrapper" title="鍏徃璇︽儏" :need-auth="false"> <LoadingLayout :loading="isLoading" :error="isError" :loadError="refetch"> <ContentView> - <CompanyDesc style="background-color: #fff" :showArrow="false"></CompanyDesc> + <CompanyDesc + style="background-color: #fff" + :showArrow="false" + :enterpriseName="enterpriseDetail?.enterpriseName ?? ''" + :taskCount="enterpriseDetail?.taskCount ?? 0" + ></CompanyDesc> </ContentView> <ProTabs v-model="tab" @@ -17,7 +22,7 @@ <CompanyTaskList /> </ProTabPane> <ProTabPane :title="`浼佷笟淇℃伅`" pane-key="2"> - <CompanyInfo /> + <CompanyInfo :enterpriseId="enterpriseId" /> </ProTabPane> </ProTabs> </LoadingLayout> @@ -26,41 +31,20 @@ <script setup lang="ts"> import Taro from '@tarojs/taro'; -import { useQuery } from '@tanstack/vue-query'; -import * as flexWorkerServices from '@12333/services/api/FlexWorker'; import CompanyDesc from '../components/CompanyDesc.vue'; import CompanyTaskList from '../components/CompanyTaskList.vue'; import CompanyInfo from '../components/CompanyInfo.vue'; import { ProTabs, ProTabPane } from '@12333/components'; +import { useEnterpriseDetail } from '@12333/hooks'; defineOptions({ name: 'companyDetail', }); const router = Taro.useRouter(); -const companyId = router.params?.id ?? ''; +const enterpriseId = router.params?.id ?? ''; const tab = ref('1'); -const { - isLoading, - isError, - data: detail, - refetch, -} = useQuery({ - queryKey: ['flexWorkerServices/getOrdeForDetail', companyId], - queryFn: async () => { - return await flexWorkerServices.getOrdeForDetail( - { id: companyId }, - { - showLoading: false, - } - ); - }, - placeholderData: () => ({} as API.OrderInfoDto), -}); +const { isLoading, isError, enterpriseDetail, refetch } = useEnterpriseDetail({ id: enterpriseId }); </script> - -<style lang="scss"> -@import '@/styles/common.scss'; -</style> diff --git a/apps/cMiniApp/src/subpackages/task/components/CompanyDesc.vue b/apps/cMiniApp/src/subpackages/task/components/CompanyDesc.vue index f3641da..36f3e1b 100644 --- a/apps/cMiniApp/src/subpackages/task/components/CompanyDesc.vue +++ b/apps/cMiniApp/src/subpackages/task/components/CompanyDesc.vue @@ -4,9 +4,12 @@ <div class="taskDetail-company-title">{{ enterpriseName }}</div> <RectRight v-if="showArrow" :size="8" class="taskDetail-company-arrow" /> </div> - <div class="taskDetail-company-info"> + <div class="taskDetail-company-info" v-if="isCertified"> <img :src="IconSafe" class="safe-company-info-icon" /> <div class="taskDetail-company-info-text">宸茶璇� | {{ taskCount }}涓矖浣嶅湪鎷�</div> + </div> + <div class="taskDetail-company-info" v-else> + <div class="taskDetail-company-info-text danger">鏈璇�</div> </div> </div> </template> @@ -21,6 +24,7 @@ type Props = { showArrow?: boolean; + isCertified?: boolean; enterpriseName?: string; taskCount?: number; /** @@ -80,6 +84,10 @@ flex: 1; min-width: 0; @include ellipsis; + + &.danger { + color: boleGetCssVar('color', 'danger'); + } } } } diff --git a/apps/cMiniApp/src/subpackages/task/components/CompanyInfo.vue b/apps/cMiniApp/src/subpackages/task/components/CompanyInfo.vue index bd9390f..39fc6a2 100644 --- a/apps/cMiniApp/src/subpackages/task/components/CompanyInfo.vue +++ b/apps/cMiniApp/src/subpackages/task/components/CompanyInfo.vue @@ -3,11 +3,11 @@ <div v-if="isCertified" class="companyInfo-info-wrapper"> <div class="companyInfo-info-item"> <div class="companyInfo-info-item-label">浼佷笟鍚嶇О</div> - <div class="companyInfo-info-item-content">姹熻タ鍚涙鼎鍟嗗姟鏈嶅姟鏈夐檺鍏徃</div> + <div class="companyInfo-info-item-content">{{ enterpriseDetail.enterpriseName }}</div> </div> <div class="companyInfo-info-item"> <div class="companyInfo-info-item-label">缁熶竴绀句細淇$敤浠g爜</div> - <div class="companyInfo-info-item-content">420902197910211010</div> + <div class="companyInfo-info-item-content">{{ enterpriseDetail.societyCreditCode }}</div> </div> <div class="companyInfo-info-item"> <div class="companyInfo-info-item-label">娉ㄥ唽璧勬湰</div> @@ -43,12 +43,24 @@ <script setup lang="ts"> import IconNoCertified from '@/assets/task/icon-no-certified.png'; +import { useEnterpriseDetail } from '@12333/hooks'; defineOptions({ name: 'CompanyInfo', }); -const isCertified = ref(true); +type Props = { + enterpriseId?: string; +}; + +const props = withDefaults(defineProps<Props>(), {}); + +/** + * TODO 浼佷笟鏄惁璁よ瘉 娉ㄥ唽璧勬湰 + */ +const isCertified = ref(false); + +const { enterpriseDetail } = useEnterpriseDetail({ id: toRef(props, 'enterpriseId') }); </script> <style lang="scss"> diff --git a/apps/cMiniApp/src/subpackages/task/components/CompanyTaskList.vue b/apps/cMiniApp/src/subpackages/task/components/CompanyTaskList.vue index fcbfcfe..f61648b 100644 --- a/apps/cMiniApp/src/subpackages/task/components/CompanyTaskList.vue +++ b/apps/cMiniApp/src/subpackages/task/components/CompanyTaskList.vue @@ -1,7 +1,7 @@ <template> <InfiniteLoading scrollViewClassName="common-infinite-scroll-list" v-bind="infiniteLoadingProps"> <template #renderItem="{ item }"> - <TaskCard @click="goTaskDetail(item)" /> + <TaskCard @click="goTaskDetail(item)" v-bind="item" /> </template> </InfiniteLoading> </template> @@ -17,7 +17,7 @@ const { queryState, infiniteLoadingProps } = useTaskList(); -function goTaskDetail(item: API.GetFlexTaskListOutput) { +function goTaskDetail(item: API.GetTaskInfosQueryResultItem) { Taro.navigateTo({ url: `${RouterPath.taskDetail}?id=${item.id}`, }); diff --git a/apps/cMiniApp/src/subpackages/task/taskDetail/InnerPage.vue b/apps/cMiniApp/src/subpackages/task/taskDetail/InnerPage.vue index ce816ca..6a0d918 100644 --- a/apps/cMiniApp/src/subpackages/task/taskDetail/InnerPage.vue +++ b/apps/cMiniApp/src/subpackages/task/taskDetail/InnerPage.vue @@ -43,7 +43,7 @@ <TaskDetailWelfareItem v-for="benefit in detail.benefits" :key="benefit.benefitCode" - :icon="IconAttentioActive" + :icon="setOSSLink(benefit.benefitField2)" :text="benefit.benefitContent" /> </div> @@ -127,7 +127,7 @@ import './taskDetail.scss'; import CompanyDesc from '../components/CompanyDesc.vue'; import dayjs from 'dayjs'; -import { TaskUtils, toThousand } from '@12333/utils'; +import { TaskUtils, toThousand, setOSSLink } from '@12333/utils'; import { EnumSettlementCycleText, BillingMethodEnumUnit, @@ -176,8 +176,10 @@ }); const goCompanyDetail = useAccessLogin(() => { - Taro.navigateTo({ - url: `${RouterPath.companyDetail}?id=${taskId}`, - }); + if (detail.value.enterpriseId) { + Taro.navigateTo({ + url: `${RouterPath.companyDetail}?id=${detail.value.enterpriseId}`, + }); + } }); </script> diff --git a/packages/constants/apiEnum.ts b/packages/constants/apiEnum.ts index d4ebf8b..f260f44 100644 --- a/packages/constants/apiEnum.ts +++ b/packages/constants/apiEnum.ts @@ -125,20 +125,6 @@ AliyunSms = 10, } -/** 鐭俊妯℃澘绫诲瀷 */ -export enum EnumSmsTemplateType { - /**鐧诲綍 */ - Login = 0, - /**娉ㄥ唽 */ - Register = 1, - /**淇敼瀵嗙爜 */ - UpdatePassword = 2, - /**缁戝畾鎵嬫満鍙风爜 */ - BindPhoneNumber = 3, - /**淇敼鎵嬫満鍙风爜 */ - UpdatePhoneNumber = 4, -} - /** 浠诲姟缁撶畻鐘舵�� */ export enum EnumTaskCheckReceiveStatus { /**寰呴獙鏀� */ diff --git a/packages/hooks/enterprise.ts b/packages/hooks/enterprise.ts new file mode 100644 index 0000000..3217a6b --- /dev/null +++ b/packages/hooks/enterprise.ts @@ -0,0 +1,29 @@ +import { useQuery, useQueryClient } from '@tanstack/vue-query'; +import * as enterpriseServices from '@12333/services/apiV2/enterprise'; +import { MaybeRef, unref } from 'vue'; + +type UseEnterpriseDetailOptions = { + id: MaybeRef<string>; +}; + +export function useEnterpriseDetail({ id }: UseEnterpriseDetailOptions) { + const { data, refetch, isLoading, isError } = useQuery({ + queryKey: ['enterpriseServices/getEnterprise', id], + queryFn: async () => { + return await enterpriseServices.getEnterprise( + { id: unref(id) }, + { + showLoading: false, + } + ); + }, + placeholderData: () => ({} as API.GetEnterpriseQueryResult), + }); + + return { + enterpriseDetail: data, + refetch, + isLoading, + isError, + }; +} diff --git a/packages/hooks/index.ts b/packages/hooks/index.ts index 20402e6..9f10388 100644 --- a/packages/hooks/index.ts +++ b/packages/hooks/index.ts @@ -4,3 +4,4 @@ export * from './dic'; export * from './setting'; export * from './identify'; +export * from './enterprise'; diff --git a/packages/services/apiV2/auth.ts b/packages/services/apiV2/auth.ts index 00b5ddb..f783319 100644 --- a/packages/services/apiV2/auth.ts +++ b/packages/services/apiV2/auth.ts @@ -53,7 +53,7 @@ /** 瀵嗙爜鐧诲綍 POST /api/user/auth/passwordLogin */ export async function passwordLogin(body: API.PasswordLoginCommand, options?: API.RequestConfig) { - return request<API.PasswordLoginCommandCallback>('/api/user/auth/passwordLogin', { + return request<API.LoginCommandCallback>('/api/user/auth/passwordLogin', { method: 'POST', headers: { 'Content-Type': 'application/json-patch+json', @@ -63,9 +63,24 @@ }); } -/** 鍙戦�侀獙璇佺爜 POST /api/user/auth/sendVerifyCode */ -export async function sendVerifyCode(body: API.SendVerifyCodeCommand, options?: API.RequestConfig) { - return request<string>('/api/user/auth/sendVerifyCode', { +/** 鍙戦�佺櫥褰曟垨娉ㄥ唽鐭俊 POST /api/user/auth/sendLoginOrRegisterVerifyCode */ +export async function sendLoginOrRegisterVerifyCode( + body: API.SendLoginOrRegisterVerifyCodeCommand, + options?: API.RequestConfig +) { + return request<string>('/api/user/auth/sendLoginOrRegisterVerifyCode', { + method: 'POST', + headers: { + 'Content-Type': 'application/json-patch+json', + }, + data: body, + ...(options || {}), + }); +} + +/** 鐭俊鐧诲綍 POST /api/user/auth/smsLogin */ +export async function smsLogin(body: API.SmsLoginCommand, options?: API.RequestConfig) { + return request<API.LoginCommandCallback>('/api/user/auth/smsLogin', { method: 'POST', headers: { 'Content-Type': 'application/json-patch+json', diff --git a/packages/services/apiV2/index.ts b/packages/services/apiV2/index.ts index dcda25c..3671cc8 100644 --- a/packages/services/apiV2/index.ts +++ b/packages/services/apiV2/index.ts @@ -2,21 +2,21 @@ /* eslint-disable */ // API 鏇存柊鏃堕棿锛� // API 鍞竴鏍囪瘑锛� -import * as dictionary from './dictionary'; -import * as menu from './menu'; -import * as enterprise from './enterprise'; -import * as task from './task'; -import * as auth from './auth'; -import * as user from './user'; -import * as role from './role'; import * as resource from './resource'; +import * as user from './user'; +import * as dictionary from './dictionary'; +import * as auth from './auth'; +import * as task from './task'; +import * as enterprise from './enterprise'; +import * as role from './role'; +import * as menu from './menu'; export default { - dictionary, - menu, - enterprise, - task, - auth, - user, - role, resource, + user, + dictionary, + auth, + task, + enterprise, + role, + menu, }; diff --git a/packages/services/apiV2/task.ts b/packages/services/apiV2/task.ts index 23c1be7..19ade89 100644 --- a/packages/services/apiV2/task.ts +++ b/packages/services/apiV2/task.ts @@ -19,17 +19,14 @@ /** 鏌ヨ浠诲姟鍒嗛〉鍒楄〃 POST /api/flexjob/task/getTaskInfos */ export async function getTaskInfos(body: API.GetTaskInfosQuery, options?: API.RequestConfig) { - return request<API.PagedListQueryResultGetTaskInfosQueryResultItem>( - '/api/flexjob/task/getTaskInfos', - { - method: 'POST', - headers: { - 'Content-Type': 'application/json-patch+json', - }, - data: body, - ...(options || {}), - } - ); + return request<API.GetTaskInfosQueryResult>('/api/flexjob/task/getTaskInfos', { + method: 'POST', + headers: { + 'Content-Type': 'application/json-patch+json', + }, + data: body, + ...(options || {}), + }); } /** 淇濆瓨浠诲姟 POST /api/flexjob/task/saveTaskInfo */ diff --git a/packages/services/apiV2/typings.d.ts b/packages/services/apiV2/typings.d.ts index dc7dd0d..972a3e8 100644 --- a/packages/services/apiV2/typings.d.ts +++ b/packages/services/apiV2/typings.d.ts @@ -235,19 +235,6 @@ AliyunSms = 10, } - enum EnumSmsTemplateType { - /**鐧诲綍 */ - Login = 0, - /**娉ㄥ唽 */ - Register = 1, - /**淇敼瀵嗙爜 */ - UpdatePassword = 2, - /**缁戝畾鎵嬫満鍙风爜 */ - BindPhoneNumber = 3, - /**淇敼鎵嬫満鍙风爜 */ - UpdatePhoneNumber = 4, - } - enum EnumTaskCheckReceiveStatus { /**寰呴獙鏀� */ Wait = 10, @@ -422,6 +409,24 @@ /** 閿欒鐮� */ errorCode?: string; data?: GetTaskInfoQueryResult; + /** 鎵ц鎴愬姛 */ + success?: boolean; + /** 閿欒淇℃伅 */ + msg?: any; + /** 闄勫姞鏁版嵁 */ + extras?: any; + /** 鏃堕棿鎴� */ + timestamp?: number; + } + + interface FriendlyResultGetTaskInfosQueryResult { + /** 璺熻釜Id */ + traceId?: string; + /** 鐘舵�佺爜 */ + code?: number; + /** 閿欒鐮� */ + errorCode?: string; + data?: GetTaskInfosQueryResult; /** 鎵ц鎴愬姛 */ success?: boolean; /** 閿欒淇℃伅 */ @@ -621,6 +626,24 @@ timestamp?: number; } + interface FriendlyResultLoginCommandCallback { + /** 璺熻釜Id */ + traceId?: string; + /** 鐘舵�佺爜 */ + code?: number; + /** 閿欒鐮� */ + errorCode?: string; + data?: LoginCommandCallback; + /** 鎵ц鎴愬姛 */ + success?: boolean; + /** 閿欒淇℃伅 */ + msg?: any; + /** 闄勫姞鏁版嵁 */ + extras?: any; + /** 鏃堕棿鎴� */ + timestamp?: number; + } + interface FriendlyResultPagedListQueryResultGetDictionaryCategoriesQueryResultItem { /** 璺熻釜Id */ traceId?: string; @@ -701,42 +724,6 @@ /** 閿欒鐮� */ errorCode?: string; data?: PagedListQueryResultGetRolesQueryResultItem; - /** 鎵ц鎴愬姛 */ - success?: boolean; - /** 閿欒淇℃伅 */ - msg?: any; - /** 闄勫姞鏁版嵁 */ - extras?: any; - /** 鏃堕棿鎴� */ - timestamp?: number; - } - - interface FriendlyResultPagedListQueryResultGetTaskInfosQueryResultItem { - /** 璺熻釜Id */ - traceId?: string; - /** 鐘舵�佺爜 */ - code?: number; - /** 閿欒鐮� */ - errorCode?: string; - data?: PagedListQueryResultGetTaskInfosQueryResultItem; - /** 鎵ц鎴愬姛 */ - success?: boolean; - /** 閿欒淇℃伅 */ - msg?: any; - /** 闄勫姞鏁版嵁 */ - extras?: any; - /** 鏃堕棿鎴� */ - timestamp?: number; - } - - interface FriendlyResultPasswordLoginCommandCallback { - /** 璺熻釜Id */ - traceId?: string; - /** 鐘舵�佺爜 */ - code?: number; - /** 閿欒鐮� */ - errorCode?: string; - data?: PasswordLoginCommandCallback; /** 鎵ц鎴愬姛 */ success?: boolean; /** 閿欒淇℃伅 */ @@ -1155,7 +1142,7 @@ /** 浼佷笟Id */ enterpriseId?: string; /** 浼佷笟鍏ㄧО */ - enterpriseName?: string; + enterpriseEnterpriseName?: string; /** 鍦ㄦ嫑宀椾綅鏁伴噺 */ taskCount?: number; /** 浠诲姟鍚嶇О */ @@ -1204,7 +1191,9 @@ interface GetTaskInfoQueryResultBenefit { /** 绂忓埄缂栧彿 */ benefitCode?: string; - /** 绂忓埄 */ + /** 绂忓埄鍥炬爣 */ + benefitField2?: string; + /** 绂忓埄鍚嶇О */ benefitContent?: string; } @@ -1219,6 +1208,8 @@ pageModel?: PagedListQueryPageModel; /** 鍏抽敭瀛楋紙浠诲姟鍚嶇О锛� */ keywords?: string; + /** 浼佷笟Id */ + enterpriseId?: string; /** 鍙戝竷鏃堕棿-寮�濮� */ beginTime?: string; /** 鍙戝竷鏃堕棿-缁撴潫 */ @@ -1232,6 +1223,24 @@ status?: EnumTaskStatus; releaseStatus?: EnumTaskReleaseStatus; recommendStatus?: EnumTaskRecommendStatus; + } + + interface GetTaskInfosQueryResult { + pageModel?: PagedListQueryResultPageModel; + /** 鏁版嵁 */ + data?: GetTaskInfosQueryResultItem[]; + count?: GetTaskInfosQueryResultCount; + } + + interface GetTaskInfosQueryResultCount { + /** 寰呭畨鎺掓暟閲� */ + waitAssignCount?: number; + /** 宸插畨鎺掓暟閲� */ + completedAssignCount?: number; + /** 鍙戝竷涓暟閲� */ + inProcessReleaseCount?: number; + /** 宸插仠姝㈡暟閲� */ + stoppedReleaseCount?: number; } interface GetTaskInfosQueryResultItem { @@ -1294,6 +1303,13 @@ type GetUserResumeQueryResult = Record<string, any>; + interface LoginCommandCallback { + /** 鐢ㄦ埛璁块棶浠ょ墝 */ + accessToken?: string; + /** 鍒锋柊浠ょ墝 */ + refreshToken?: string; + } + interface PagedListQueryPageModel { /** 琛屾暟 */ rows?: number; @@ -1339,12 +1355,6 @@ data?: GetRolesQueryResultItem[]; } - interface PagedListQueryResultGetTaskInfosQueryResultItem { - pageModel?: PagedListQueryResultPageModel; - /** 鏁版嵁 */ - data?: GetTaskInfosQueryResultItem[]; - } - interface PagedListQueryResultPageModel { /** 琛屾暟 */ rows?: number; @@ -1365,13 +1375,6 @@ password: string; type?: EnumUserType; clientType?: EnumClientType; - } - - interface PasswordLoginCommandCallback { - /** 鐢ㄦ埛璁块棶浠ょ墝 */ - accessToken?: string; - /** 鍒锋柊浠ょ墝 */ - refreshToken?: string; } interface SaveDictionaryCategoryCommand { @@ -1642,10 +1645,9 @@ data?: any; } - interface SendVerifyCodeCommand { + interface SendLoginOrRegisterVerifyCodeCommand { /** 鎵嬫満鍙风爜 */ - phoneNumber?: string; - templateCode?: EnumSmsTemplateType; + phoneNumber: string; } interface SetDictionaryDataIsDisabledCommand { @@ -1722,5 +1724,14 @@ status?: EnumUserStatus; } + interface SmsLoginCommand { + /** 鎵嬫満鍙风爜 */ + phoneNumber: string; + /** 楠岃瘉鐮� */ + verifyCode: string; + type?: EnumUserType; + clientType?: EnumClientType; + } + type SyncHumanResourcesAreaDictionaryDataCommand = Record<string, any>; } diff --git a/types/api.d.ts b/types/api.d.ts index ac80dc0..98ee682 100644 --- a/types/api.d.ts +++ b/types/api.d.ts @@ -49,4 +49,8 @@ id?: string quickQuery?: string } + + interface GetTaskInfoQueryResult{ + enterpriseName?:string + } } -- Gitblit v1.9.1