zhengyiming
2 天以前 1d472eb06970c85b0edfb58871956bc2c8d69916
fix: 甲方小程序
已修改9个文件
376 ■■■■ 文件已修改
apps/cStandardMiniApp/src/styles/nut.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/housekeepingMiniApp/project.private.config.json 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/housekeepingMiniApp/src/hooks/enterprise.ts 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/housekeepingMiniApp/src/styles/nut.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/housekeepingMiniApp/src/subpackages/mine/addressManange/InnerPage.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/housekeepingMiniApp/src/subpackages/sercice/addStandardOrder/InnerPage.vue 253 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/housekeepingMiniApp/src/subpackages/sercice/serciceDetail/serciceDetail.vue 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/Card/ServiceDetailAddressCard.vue 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/Input/ChooseInputWithDatePicker.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/cStandardMiniApp/src/styles/nut.scss
@@ -127,6 +127,11 @@
  .bole-input-textarea:not(.nut-input--disabled) {
    color: boleGetCssVar('text-color', 'primary') !important;
    height: 100rpx;
    .textarea-placeholder {
      color: boleGetCssVar('text-color', 'placeholder') !important;
      font-size: 26rpx;
    }
  }
  .bole-input-text-placeholder {
apps/housekeepingMiniApp/project.private.config.json
@@ -23,11 +23,18 @@
        "miniprogram": {
            "list": [
                {
                    "name": "选择地址",
                    "pathName": "subpackages/mine/addressManange/addressManange",
                    "query": "type=select",
                    "scene": null,
                    "launchMode": "default"
                },
                {
                    "name": "预约下单",
                    "pathName": "subpackages/sercice/addStandardOrder/addStandardOrder",
                    "query": "specNumber=1&specId=72ec3beb-90dc-473b-d214-08de429af188&id=53208c5d-a823-40d3-e79e-08de429af17b",
                    "scene": null,
                    "launchMode": "default"
                    "launchMode": "default",
                    "scene": null
                },
                {
                    "name": "新增地址",
apps/housekeepingMiniApp/src/hooks/enterprise.ts
@@ -1,13 +1,15 @@
import { useInfiniteLoading } from '@12333/hooks';
import { BaseData, useInfiniteLoading } from '@12333/hooks';
import Taro from '@tarojs/taro';
import * as enterpriseServices from '@12333/services/apiV2/enterprise';
import { InfiniteData } from '@tanstack/vue-query';
type UseEnterpriseAddressesOptions = {
  rows?: number;
  onSuccess?: (data: InfiniteData<BaseData<API.GetEnterpriseAddressesQueryResultItem>>) => any;
};
export function useEnterpriseAddresses(options: UseEnterpriseAddressesOptions = {}) {
  const { rows = 20 } = options;
  const { rows = 20, onSuccess } = options;
  const { infiniteLoadingProps, invalidateQueries } = useInfiniteLoading(
    ({ pageParam }) => {
@@ -24,6 +26,9 @@
    },
    {
      queryKey: ['enterpriseServices/getEnterpriseAddresses', rows],
      onSuccess(data) {
        onSuccess?.(data);
      },
    }
  );
apps/housekeepingMiniApp/src/styles/nut.scss
@@ -127,6 +127,11 @@
  .bole-input-textarea:not(.nut-input--disabled) {
    color: boleGetCssVar('text-color', 'primary') !important;
    height: 100rpx;
    .textarea-placeholder {
      color: boleGetCssVar('text-color', 'placeholder') !important;
      font-size: 26rpx;
    }
  }
  .bole-input-text-placeholder {
apps/housekeepingMiniApp/src/subpackages/mine/addressManange/InnerPage.vue
@@ -1,6 +1,6 @@
<template>
  <InfiniteLoading
    scrollViewClassName="common-infinite-scroll-list home-list"
    scrollViewClassName="common-page-infinite-scroll-list"
    v-bind="infiniteLoadingProps"
  >
    <nut-address-list
@@ -28,6 +28,11 @@
  name: 'InnerPage',
});
const route = Taro.useRouter();
const id = route.params?.id ?? '';
const mode = route.params?.mode ?? '';
const isSelectMode = mode === 'select';
const dataOptions = reactive({
  id: 'id',
  addressDetail: 'addressDetail',
apps/housekeepingMiniApp/src/subpackages/sercice/addStandardOrder/InnerPage.vue
@@ -2,46 +2,108 @@
  <LoadingLayout :loading="isLoading" :error="isError" :loadError="refetch">
    <ContentScrollView hasPaddingTop>
      <ServiceDetailAddressCard
        :name="defaultAddress?.name ?? ''"
        :contactPhoneNumber="defaultAddress?.contactPhoneNumber ?? ''"
        :addressDetail="defaultAddress?.addressDetail ?? ''"
        :name="selectedAddress?.name ?? ''"
        :contactPhoneNumber="selectedAddress?.contactPhoneNumber ?? ''"
        :addressDetail="selectedAddress?.addressDetail ?? ''"
        showArrow
        @click="goSelectAddress"
      />
      <div class="addStandardOrder-detail-card">
        <nut-card
          :img-url="'//img10.360buyimg.com/n2/s240x240_jfs/t1/210890/22/4728/163829/6163a590Eb7c6f4b5/6390526d49791cb9.jpg!q70.jpg'"
          :title="detail?.name ?? ''"
          :price="toThousand(spec?.price ?? 0)"
          class="service-good-card"
      <ServiceDetailGoodCard
        :name="detail?.name"
        :price="spec?.price"
        :specName="spec?.name"
        :specNumber="specNumber"
        :imgUrl="detail?.files?.[0]"
      />
      <!-- <List>
        <ListItem title="服务时间">
          <template #extra>
            <div class="mine-service-detail-view-list-item">{{ '请选择' }}</div>
          </template>
        </ListItem>
        <ListItem title="服务机构">
          <template #extra>
            <div class="mine-service-detail-view-list-item">{{ '请选择' }}</div>
          </template>
        </ListItem>
      </List> -->
      <nut-form :model-value="form" ref="formRef" :rules="rules" class="addStandardOrder-form">
        <nut-form-item
          label="服务开始时间:"
          class="bole-form-item"
          prop="beginTime"
          label-width="90px"
        >
          <template #prolist>
            <div class="card-tag-list">
              <span class="tag">{{ spec?.name }}</span>
            </div>
          </template>
          <template #origin>
            <div></div>
          </template>
          <template #footer>
            <div class="card-footer">x{{ specNumber }}</div>
          </template>
        </nut-card>
      </div>
          <ChooseInputWithDatePicker
            v-model="form.beginTime"
            :minDate="nowDate"
            placeholder="请选择"
            type="datetime"
            format="YYYY-MM-DD HH:mm:ss"
          ></ChooseInputWithDatePicker>
        </nut-form-item>
        <nut-form-item
          label="服务结束时间:"
          class="bole-form-item"
          prop="endTime"
          label-width="90px"
        >
          <ChooseInputWithDatePicker
            v-model="form.endTime"
            :minDate="endMinTime"
            :maxDate="endMaxTime"
            placeholder="请选择"
            type="datetime"
            format="YYYY-MM-DD HH:mm:ss"
          ></ChooseInputWithDatePicker>
        </nut-form-item>
        <nut-form-item
          label="备注:"
          class="bole-form-item alignTop"
          prop="remark"
          label-width="90px"
        >
          <nut-textarea
            v-model="form.remark"
            class="bole-input-textarea"
            rows="4"
            placeholder="请填写备注信息"
          >
          </nut-textarea>
        </nut-form-item>
      </nut-form>
    </ContentScrollView>
    <PageFooter>
      <PageFooterBtn type="primary" class="business-card-btn" @click="goConfirm"
        >立即下单</PageFooterBtn
      >
    </PageFooter>
    <nut-address
      v-model:visible="form.selectAddressVisible"
      v-model:value="form.addressId"
      type="exist"
      :exist-address="existAddress"
      :is-show-custom-address="false"
      @selected="selected"
      exist-address-title="选择地址"
    ></nut-address>
  </LoadingLayout>
</template>
<script setup lang="ts">
import { ServiceDetailAddressCard } from '@12333/components';
import {
  ServiceDetailAddressCard,
  ServiceDetailGoodCard,
  List,
  ListItem,
  ChooseInputWithDatePicker,
} from '@12333/components';
import Taro from '@tarojs/taro';
import * as standardServiceServices from '@12333/services/apiV2/standardService';
import { RouterPath } from '@/constants';
import { useStandardServiceDetail } from '@12333/hooks';
import { toThousand } from '@12333/utils';
import * as standardOrderServices from '@12333/services/apiV2/standardOrder';
import { FormRules } from '@nutui/nutui-taro/dist/types/__VUE/form/types';
import dayjs from 'dayjs';
defineOptions({
  name: 'InnerPage',
@@ -52,6 +114,37 @@
const specId = route.params?.specId ?? '';
const specNumber = Number(route.params?.specNumber);
const form = reactive({
  addressId: '',
  selectAddressVisible: false,
  beginTime: '',
  endTime: '',
  supplierEnterpriseId: '',
  enterpriseEmployeeIds: [] as string[],
  remark: '',
});
const nowDate = dayjs().toDate();
const endMinTime = computed(() => {
  if (form.beginTime) {
    return dayjs(form.beginTime).add(1, 'minute').toDate();
  } else {
    return dayjs().toDate();
  }
});
const endMaxTime = computed(() => {
  if (form.beginTime) {
    return dayjs(dayjs(form.beginTime).format('YYYY-MM-DD 23:59:59')).toDate();
  } else {
    return undefined;
  }
});
const rules = reactive<FormRules>({
  beginTime: [{ required: true, message: '请选择服务开始时间' }],
  endTime: [{ required: true, message: '请选择服务结束时间' }],
});
const { isLoading, isError, detail, refetch } = useStandardServiceDetail({
  id,
});
@@ -65,26 +158,120 @@
const { infiniteLoadingProps } = useEnterpriseAddresses({
  rows: 100,
  onSuccess(res) {
    const data = res.pages[0].data;
    const address = data.find((item) => item.isDefault);
    if (address) {
      form.addressId = address.id;
    } else {
      form.addressId = data[0].id;
    }
  },
});
const defaultAddress = computed(() => {
  const address = infiniteLoadingProps.value.flattenListData.find((item) => item.isDefault);
const existAddress = computed(() => {
  return infiniteLoadingProps.value.flattenListData.map((x) => ({
    id: x.id,
    addressDetail: x.addressDetail,
    cityName: '',
    countyName: '',
    provinceName: '',
    selectedAddress: x.id === form.addressId,
    townName: '',
    name: x.name,
    phone: x.contactPhoneNumber,
  }));
});
const selectedAddress = computed(() => {
  const address = infiniteLoadingProps.value.flattenListData.find(
    (item) => item.id === form.addressId
  );
  return address || infiniteLoadingProps.value.flattenListData[0];
});
function goCancel() {
  Taro.navigateTo({
    url: `${RouterPath.mineReserveServiceCancel}?id=${id}`,
function goSelectAddress() {
  // Taro.navigateTo({
  //   url: `${RouterPath.addressManange}?mode=select`,
  // });
  form.selectAddressVisible = true;
}
const selected = (prevExistAdd, nowExistAdd, arr) => {
  form.addressId = nowExistAdd.id;
};
const formRef = ref<any>(null);
function goConfirm() {
  if (!formRef.value) return;
  formRef.value.validate().then(({ valid, errors }: any) => {
    if (valid) {
      // addStandardOrder();
    }
  });
}
function goConfirm() {
  Taro.navigateTo({
    url: `${RouterPath.mineReserveServiceConfirm}?id=${id}`,
async function addStandardOrder() {
  try {
    let params: API.AddStandardOrderCommand = {
      serviceId: detail.value.id,
      serviceName: detail.value.name,
      serviceCode: detail.value.code,
      specId: spec.value.id,
      specName: spec.value.name,
      specPrice: spec.value.price ?? 0,
      specNumber: specNumber,
      addressId: '3fa85f64-5717-4562-b3fc-2c963f66afa6',
      name: detail.value.name,
      contactPhoneNumber: 'string',
      provinceCode: 'string',
      provinceContent: 'string',
      cityCode: 'string',
      cityContent: 'string',
      areaCode: 'string',
      areaContent: 'string',
      addressName: 'string',
      addressDetail: 'string',
      longitude: 0,
      latitude: 0,
      beginTime: '2025-12-24T08:25:08.372Z',
      endTime: '2025-12-24T08:25:08.372Z',
      supplierEnterpriseId: '3fa85f64-5717-4562-b3fc-2c963f66afa6',
      enterpriseEmployeeIds: ['3fa85f64-5717-4562-b3fc-2c963f66afa6'],
      remark: 'string',
      payAccess: 1,
    };
    let res = await standardOrderServices.addStandardOrder(params);
  } catch (error) {}
}
async function pay() {
  try {
    let params: API.PayStandardOrderCommand = {
      id: '9e919af2-3d33-4eac-f6dc-08de429676b3',
    };
    let res = await standardOrderServices.payStandardOrder(params);
    if (res) {
      Taro.requestPayment({
        timeStamp: res.timestamp,
        nonceStr: res.nonceStr,
        package: res.package,
        signType: res.signType as any,
        paySign: res.paySign,
  });
}
  } catch (error) {}
}
</script>
<style lang="scss">
@import '@/styles/common.scss';
.addStandardOrder-page-wrapper {
  .addStandardOrder-form {
    .nut-cell-group__wrap {
      box-shadow: none;
    }
  }
}
</style>
apps/housekeepingMiniApp/src/subpackages/sercice/serciceDetail/serciceDetail.vue
@@ -166,59 +166,6 @@
  });
});
async function addStandardOrder(specNumber: number) {
  try {
    const spec = SkuUtils.getCurrentActiveSpec(skuState.sku);
    let params: API.AddStandardOrderCommand = {
      serviceId: detail.value.id,
      serviceName: detail.value.name,
      serviceCode: detail.value.code,
      specId: spec.id,
      specName: spec.name,
      specPrice: detail.value.specs.find((x) => x.id === spec.id)?.price ?? 0,
      specNumber: specNumber,
      addressId: '3fa85f64-5717-4562-b3fc-2c963f66afa6',
      name: detail.value.name,
      contactPhoneNumber: 'string',
      provinceCode: 'string',
      provinceContent: 'string',
      cityCode: 'string',
      cityContent: 'string',
      areaCode: 'string',
      areaContent: 'string',
      addressName: 'string',
      addressDetail: 'string',
      longitude: 0,
      latitude: 0,
      beginTime: '2025-12-24T08:25:08.372Z',
      endTime: '2025-12-24T08:25:08.372Z',
      supplierEnterpriseId: '3fa85f64-5717-4562-b3fc-2c963f66afa6',
      enterpriseEmployeeIds: ['3fa85f64-5717-4562-b3fc-2c963f66afa6'],
      remark: 'string',
      payAccess: 1,
    };
    let res = await standardOrderServices.addStandardOrder(params);
  } catch (error) {}
}
async function pay() {
  try {
    let params: API.PayStandardOrderCommand = {
      id: '9e919af2-3d33-4eac-f6dc-08de429676b3',
    };
    let res = await standardOrderServices.payStandardOrder(params);
    if (res) {
      Taro.requestPayment({
        timeStamp: res.timestamp,
        nonceStr: res.nonceStr,
        package: res.package,
        signType: res.signType as any,
        paySign: res.paySign,
      });
    }
  } catch (error) {}
}
async function handleAttention() {
  try {
    let params: API.CollectionStandardServiceCommand = {
packages/components/src/Card/ServiceDetailAddressCard.vue
@@ -1,14 +1,19 @@
<template>
  <div class="mine-service-detail-view-address">
    <div class="mine-service-detail-view-address-inner">
    <div class="mine-service-detail-view-title-wrapper">
      <div class="mine-service-detail-view-title">服务地址</div>
    </div>
    <div class="mine-service-detail-view-item">{{ addressDetail }}</div>
    <div class="mine-service-detail-view-item">{{ name }} {{ contactPhoneNumber }}</div>
  </div>
    <img v-if="showArrow" :src="IconArrow" class="mine-service-detail-view-arrow" />
  </div>
</template>
<script setup lang="ts">
import IconArrow from '@/assets/setting/icon-arrow.png';
defineOptions({
  name: 'ServiceDetailAddressCard',
});
@@ -19,9 +24,12 @@
  contactPhoneNumber?: string;
  /** 省市区+详细地址+门牌号 */
  addressDetail?: string;
  showArrow?: boolean;
};
const props = withDefaults(defineProps<Props>(), {});
const props = withDefaults(defineProps<Props>(), {
  showArrow: false,
});
</script>
<style lang="scss">
@@ -32,6 +40,13 @@
  margin-bottom: 24px;
  background-color: #fff;
  border-radius: 12px;
  display: flex;
  align-items: center;
  .mine-service-detail-view-address-inner {
    flex: 1;
    min-width: 0;
  }
  .mine-service-detail-view-title-wrapper {
    display: flex;
@@ -59,5 +74,11 @@
      margin-top: 14px;
    }
  }
  .mine-service-detail-view-arrow {
    width: 32px;
    height: 32px;
    margin-left: 12px;
  }
}
</style>
packages/components/src/Input/ChooseInputWithDatePicker.vue
@@ -53,7 +53,15 @@
                  type: props.type,
                  maxDate: props.maxDate,
                  onConfirm: ({ selectedValue }) => {
                    emit('update:modelValue', dayjs(selectedValue.join('-')).format(props.format));
                    let _selectedVale = '';
                    if (selectedValue.length > 3) {
                      _selectedVale = `${selectedValue.slice(0, 3).join('-')} ${selectedValue
                        .slice(3)
                        .join(':')}`;
                    } else {
                      _selectedVale = selectedValue.join('-');
                    }
                    emit('update:modelValue', dayjs(_selectedVale).format(props.format));
                    onClose();
                  },
                  onChange: () => {