41个文件已修改
52个文件已添加
45659 ■■■■ 已修改文件
apps/taro/config/staging.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/app.config.ts 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/constants/router.ts 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/pages/home/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/pages/mine/index.vue 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/order/order/InnerPage.vue 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/order/orderApplyRefund/InnerPage.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/order/orderApplyRefund/orderApplyRefund.config.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/order/orderApplyRefund/orderApplyRefund.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/order/orderRefundResult/InnerPage.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/order/orderRefundResult/orderRefundResult.config.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/order/orderRefundResult/orderRefundResult.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/recharge/gasBillRecharge/InnerPage.vue 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/recharge/gasBillRecharge/gasBillRecharge.config.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/recharge/gasBillRecharge/gasBillRecharge.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/recharge/rechargeGasResult/rechargeGasResult.config.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/recharge/rechargeGasResult/rechargeGasResult.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/recharge/rechargeResult/rechargeResult.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/recharge/selectPayType/InnerPage.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/recharge/selectPayType/selectPayType.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/userAccount/editElectricUserAccount/InnerPage.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/userAccount/editElectricUserAccount/editElectricUserAccount.config.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/userAccount/editElectricUserAccount/editElectricUserAccount.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/userAccount/editGasUserAccount/InnerPage.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/userAccount/editGasUserAccount/editGasUserAccount.confg.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/userAccount/editGasUserAccount/editGasUserAccount.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/userAccount/editPhoneUserAccount/InnerPage.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/userAccount/editPhoneUserAccount/editPhoneUserAccount.config.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/userAccount/editPhoneUserAccount/editPhoneUserAccount.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/userAccount/userAccountList/InnerPage.vue 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/userAccount/userAccountList/userAccountList.config.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/subpackages/userAccount/userAccountList/userAccountList.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/src/utils/blLifeRecharge.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/package.json 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/components/Card/AccountAddCard.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/components/Card/AccountCard.vue 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/components/Card/AccountList.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/components/Card/OrderCard.vue 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/components/Dialog/ConfirmDialogInfoItem.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/components/Input/ChooseInputWithAreaPicker.vue 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/components/RechargeTipsView/RechargeTipsView.vue 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/constants/index.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/hooks/area.ts 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/hooks/index.ts 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/index.ts 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/styles/card.scss 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/styles/components.scss 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/styles/gas.scss 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/styles/index.scss 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/styles/nut.scss 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/styles/orderCard.scss 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/styles/rechargeGrid.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/utils/common.ts 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/utils/validator.ts 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/GasBillRecharge/GasBillRecharge.vue 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/GasBillRecharge/GasBillRechargeBaseForm.vue 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/GasBillRecharge/GasBillRechargeStep1.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/GasBillRecharge/GasBillRechargeStep2.vue 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/GasBillRecharge/GasBillRechargeStep3.vue 242 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/GasBillRecharge/GasOrgTypeCard.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/GasBillRecharge/context.ts 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/Order/OrderApplyRefundView.vue 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/Order/OrderRefundResultView.vue 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/Order/components/ElectricOrder.vue 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/Order/components/GasOrder.vue 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/Order/components/PhoneOrder.vue 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/PhoneBillRecharge/PhoneBillRecharge.vue 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/PhoneBillRecharge/PhoneBillRechargeBaseForm.vue 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/PhoneBillRecharge/PhoneBillRechargeStep1.vue 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/PhoneBillRecharge/PhoneBillRechargeStep2.vue 230 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/PhoneBillRecharge/context.ts 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/RechargeResultView/RechargeResultView.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/electricBillRecharge/ElectricBillRechargeBaseForm.vue 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/electricBillRecharge/ElectricBillRechargeStep1.vue 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/electricBillRecharge/ElectricBillRechargeStep2.vue 250 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/electricBillRecharge/context.ts 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/electricBillRecharge/electricBillRecharge.vue 256 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/userAccount/EditElectricUserAccount.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/userAccount/EditGasUserAccount.vue 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/userAccount/EditPhoneUserAccount.vue 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/views/userAccount/UserAccountListView.vue 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/core-vue/package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/core/CHANGELOG.md 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/core/package.json 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/core/src/lifeRecharge.ts 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/core/src/lifeRechargeAccountModel.ts 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/core/src/lifeRechargeConstants.ts 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/core/src/lifeRechargeServices.ts 356 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/core/src/types.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/services/api/LifePay.ts 324 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/services/api/typings.d.ts 247 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/utils/common.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pnpm-lock.yaml 40873 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/taro/config/staging.js
@@ -4,7 +4,7 @@
  env: {
    // BASE_URL: '"https://testrlywx.boleyuma.com"',
    BASE_URL: '"https://api.81812333.com"',
    BASE_URL_H5: '"http://118.178.252.28:8742"',
    BASE_URL_H5: '"https://testrlywx.boleyuma.com"',
    BASE_URL_JX: '"https://api.jx818.com"',
    OSS_URL: '"https://waterdroptest2.oss-cn-hangzhou.aliyuncs.com/"',
apps/taro/src/app.config.ts
@@ -56,14 +56,29 @@
      pages: [
        'phoneBillRecharge/phoneBillRecharge',
        'electricBillRecharge/electricBillRecharge',
        'gasBillRecharge/gasBillRecharge',
        'selectPayType/selectPayType',
        'rechargeResult/rechargeResult',
        'rechargeElectricResult/rechargeElectricResult',
        'rechargeGasResult/rechargeGasResult',
      ],
    },
    {
      root: 'subpackages/order',
      pages: ['order/order'],
      pages: [
        'order/order',
        'orderApplyRefund/orderApplyRefund',
        'orderRefundResult/orderRefundResult',
      ],
    },
    {
      root: 'subpackages/userAccount',
      pages: [
        'userAccountList/userAccountList',
        'editGasUserAccount/editGasUserAccount',
        'editPhoneUserAccount/editPhoneUserAccount',
        'editElectricUserAccount/editElectricUserAccount',
      ],
    },
  ],
  // preloadRule: {
apps/taro/src/constants/router.ts
@@ -10,8 +10,17 @@
  phoneBillRecharge = '/subpackages/recharge/phoneBillRecharge/phoneBillRecharge',
  electricBillRecharge = '/subpackages/recharge/electricBillRecharge/electricBillRecharge',
  order = '/subpackages/order/order/order',
  gasBillRecharge = '/subpackages/recharge/gasBillRecharge/gasBillRecharge',
  selectPayType = '/subpackages/recharge/selectPayType/selectPayType',
  rechargeResult = '/subpackages/recharge/rechargeResult/rechargeResult',
  rechargeElectricResult = '/subpackages/recharge/rechargeElectricResult/rechargeElectricResult',
  rechargeGasResult = '/subpackages/recharge/rechargeGasResult/rechargeGasResult',
  order = '/subpackages/order/order/order',
  orderApplyRefund = '/subpackages/order/orderApplyRefund/orderApplyRefund',
  orderRefundResult = '/subpackages/order/orderRefundResult/orderRefundResult',
  userAccountList = '/subpackages/userAccount/userAccountList/userAccountList',
  editGasUserAccount = '/subpackages/userAccount/editGasUserAccount/editGasUserAccount',
  editPhoneUserAccount = '/subpackages/userAccount/editPhoneUserAccount/editPhoneUserAccount',
  editElectricUserAccount = '/subpackages/userAccount/editElectricUserAccount/editElectricUserAccount',
}
apps/taro/src/pages/home/index.vue
@@ -33,7 +33,7 @@
});
const goGasBillRecharge = useAccessLogin(() => {
  Taro.navigateTo({
    url: `${RouterPath.electricBillRecharge}`,
    url: `${RouterPath.gasBillRecharge}`,
  });
});
</script>
apps/taro/src/pages/mine/index.vue
@@ -13,13 +13,14 @@
    <div class="mine-page-top-view" @click="goLogin">
      <img class="mine-avatar" :src="DefaultAvatar" alt="" />
      <div class="user-info">
        <div class="user-info-name" v-if="isLogin">{{ virtualPhoneNumber }}</div>
        <div class="user-info-name" v-if="isLogin">{{ hiddenPhoneNumber(virtualPhoneNumber) }}</div>
        <div class="mine-go-login" v-else>登录</div>
      </div>
    </div>
    <ContentScrollView>
      <List class="mine-list-wrapper">
        <ListItem title="订单管理" @click="goOrderManage"></ListItem>
        <ListItem title="户号管理" @click="goUserAccountList"></ListItem>
        <ListItem v-if="isLogin" title="退出登录" @click="goLogout"></ListItem>
      </List>
    </ContentScrollView>
@@ -37,6 +38,7 @@
import { useUserStore } from '@/stores/modules/user';
import { Message } from '@/utils';
import { useLifeRechargeContext } from '@life-payment/core-vue';
import { hiddenPhoneNumber } from '@life-payment/utils';
const { userDetail, virtualPhoneNumber } = useUser();
const isLogin = useIsLogin();
@@ -72,6 +74,7 @@
});
const goOrderManage = useAccessLogin(() => goPage(RouterPath.order));
const goUserAccountList = useAccessLogin(() => goPage(RouterPath.userAccountList));
async function goLogout() {
  try {
apps/taro/src/subpackages/order/order/InnerPage.vue
@@ -1,16 +1,19 @@
<template>
  <ProTabs v-model="orderType" name="user-home-tabs" class="user-home-tabs" flexTitle fullHeight>
    <ProTabPane title="话费订单" pane-key="1">
      <PhoneOrder />
      <PhoneOrder @goApplyRefund="goApplyRefund" @goRefundDetail="goRefundDetail" />
    </ProTabPane>
    <ProTabPane title="电费订单" pane-key="2">
      <ElectricOrder />
      <ElectricOrder @goApplyRefund="goApplyRefund" @goRefundDetail="goRefundDetail" />
    </ProTabPane>
    <ProTabPane title="燃气订单" pane-key="3">
      <GasOrder @goApplyRefund="goApplyRefund" @goRefundDetail="goRefundDetail" />
    </ProTabPane>
  </ProTabs>
</template>
<script setup lang="ts">
import { PhoneOrder, ElectricOrder } from '@life-payment/components';
import { PhoneOrder, ElectricOrder, GasOrder } from '@life-payment/components';
import Taro from '@tarojs/taro';
defineOptions({
@@ -19,9 +22,17 @@
const orderType = ref('1');
function goPay() {
function goApplyRefund(id: string) {
  Taro.navigateTo({
    url: RouterPath.selectPayType,
    url: `${RouterPath.orderApplyRefund}?id=${id}`,
    // events: {
    //   submitApplyRefund: function () {},
    // },
  });
}
function goRefundDetail(orderNo: string) {
  Taro.navigateTo({
    url: `${RouterPath.orderRefundResult}?orderNo=${orderNo}`,
  });
}
</script>
apps/taro/src/subpackages/order/orderApplyRefund/InnerPage.vue
New file
@@ -0,0 +1,22 @@
<template>
  <ContentScrollView :paddingH="false">
    <OrderApplyRefundView :id="id" @submitApplyRefund="submitApplyRefund" />
  </ContentScrollView>
</template>
<script setup lang="ts">
import Taro from '@tarojs/taro';
import { OrderApplyRefundView } from '@life-payment/components';
import { goBack } from '@/utils';
defineOptions({
  name: 'InnerPage',
});
const router = Taro.useRouter();
const id = router.params?.id ?? '';
function submitApplyRefund() {
  goBack();
}
</script>
apps/taro/src/subpackages/order/orderApplyRefund/orderApplyRefund.config.ts
New file
@@ -0,0 +1,3 @@
export default definePageConfig({
  disableScroll: true,
});
apps/taro/src/subpackages/order/orderApplyRefund/orderApplyRefund.vue
New file
@@ -0,0 +1,14 @@
<template>
  <PageLayout title="申请退款" class="orderApplyRefund-page-wrapper" hasBorder>
    <InnerPage />
  </PageLayout>
</template>
<script setup lang="ts">
import { PageLayout } from '@/components';
import InnerPage from './InnerPage.vue';
defineOptions({
  name: 'orderApplyRefund',
});
</script>
apps/taro/src/subpackages/order/orderRefundResult/InnerPage.vue
New file
@@ -0,0 +1,22 @@
<template>
  <ContentScrollView>
    <OrderRefundResultView
      style="margin-top: 40px"
      @go-back-home="goHome()"
      :orderNo="orderNo"
    ></OrderRefundResultView>
  </ContentScrollView>
</template>
<script setup lang="ts">
import { OrderRefundResultView } from '@life-payment/components';
import { goHome } from '@/utils';
import Taro from '@tarojs/taro';
defineOptions({
  name: 'InnerPage',
});
const router = Taro.useRouter();
const orderNo = router.params?.orderNo ?? '';
</script>
apps/taro/src/subpackages/order/orderRefundResult/orderRefundResult.config.ts
New file
@@ -0,0 +1,3 @@
export default definePageConfig({
  disableScroll: true,
});
apps/taro/src/subpackages/order/orderRefundResult/orderRefundResult.vue
New file
@@ -0,0 +1,14 @@
<template>
  <PageLayout title="申请退款" class="orderRefundResult-page-wrapper" hasBorder>
    <InnerPage />
  </PageLayout>
</template>
<script setup lang="ts">
import { PageLayout } from '@/components';
import InnerPage from './InnerPage.vue';
defineOptions({
  name: 'orderRefundResult',
});
</script>
apps/taro/src/subpackages/recharge/gasBillRecharge/InnerPage.vue
New file
@@ -0,0 +1,23 @@
<template>
  <ContentScrollView :paddingH="false" style="background-color: #fff">
    <GasBillRecharge @goPay="goPay" :isDev="isDev" />
  </ContentScrollView>
</template>
<script setup lang="ts">
import { GasBillRecharge } from '@life-payment/components';
import { BlLifeRecharge } from '@life-payment/core-vue';
import Taro from '@tarojs/taro';
defineOptions({
  name: 'InnerPage',
});
const isDev = process.env.NODE_ENV === 'development';
function goPay(orderNo: string) {
  Taro.navigateTo({
    url: `${RouterPath.selectPayType}?orderNo=${orderNo}&lifePayOrderType=${BlLifeRecharge.constants.LifePayOrderTypeEnum.燃气订单}`,
  });
}
</script>
apps/taro/src/subpackages/recharge/gasBillRecharge/gasBillRecharge.config.ts
New file
@@ -0,0 +1,3 @@
export default definePageConfig({
  disableScroll: true,
});
apps/taro/src/subpackages/recharge/gasBillRecharge/gasBillRecharge.vue
New file
@@ -0,0 +1,14 @@
<template>
  <PageLayout title="燃气充值" class="gasBillRecharge-page-wrapper" hasBorder>
    <InnerPage />
  </PageLayout>
</template>
<script setup lang="ts">
import { PageLayout } from '@/components';
import InnerPage from './InnerPage.vue';
defineOptions({
  name: 'gasBillRecharge',
});
</script>
apps/taro/src/subpackages/recharge/rechargeGasResult/rechargeGasResult.config.ts
New file
@@ -0,0 +1,3 @@
export default definePageConfig({
  disableScroll: true,
});
apps/taro/src/subpackages/recharge/rechargeGasResult/rechargeGasResult.vue
New file
@@ -0,0 +1,25 @@
<template>
  <PageLayout title="充值成功" class="rechargeGasResult-page-wrapper" hasBorder>
    <ContentScrollView>
      <RechargeResultView
        style="margin-top: 40px"
        @go-back-home="goHome()"
        title="支付成功,充值款将在0-72小时内到账"
      >
        <template #tips>
          同一燃气费账户在充值期间,未到账前切勿在其他任何平台再次充值。因此造成的资金损失须用户自行承担!!!
        </template>
      </RechargeResultView>
    </ContentScrollView>
  </PageLayout>
</template>
<script setup lang="ts">
import { PageLayout } from '@/components';
import { goHome } from '@/utils';
import { RechargeResultView } from '@life-payment/components';
defineOptions({
  name: 'rechargeGasResult',
});
</script>
apps/taro/src/subpackages/recharge/rechargeResult/rechargeResult.vue
@@ -1,7 +1,7 @@
<template>
  <PageLayout title="充值成功" class="rechargeResult-page-wrapper" hasBorder>
    <ContentScrollView>
      <RechargeResultView style="margin-top: 40px" @go-back-home="goHome()" />
      <RechargeResultView style="margin-top: 40px" @go-back-home="goHome()" :orderNo="orderNo" />
    </ContentScrollView>
  </PageLayout>
</template>
@@ -10,8 +10,12 @@
import { PageLayout } from '@/components';
import { goHome } from '@/utils';
import { RechargeResultView } from '@life-payment/components';
import Taro from '@tarojs/taro';
defineOptions({
  name: 'rechargeResult',
});
const router = Taro.useRouter();
const orderNo = router.params?.orderNo ?? '';
</script>
apps/taro/src/subpackages/recharge/selectPayType/InnerPage.vue
@@ -48,6 +48,10 @@
    Taro.navigateTo({
      url: `${RouterPath.rechargeElectricResult}?orderNo=${orderNo}&lifePayOrderType=${lifePayOrderType}`,
    });
  } else if (lifePayOrderType === LifeRechargeConstants.LifePayOrderTypeEnum.燃气订单) {
    Taro.navigateTo({
      url: `${RouterPath.rechargeGasResult}?orderNo=${orderNo}&lifePayOrderType=${lifePayOrderType}`,
    });
  }
}
</script>
apps/taro/src/subpackages/recharge/selectPayType/selectPayType.vue
@@ -19,5 +19,6 @@
const TitleText = {
  [LifeRechargeConstants.LifePayOrderTypeEnum.话费订单]: '话费充值',
  [LifeRechargeConstants.LifePayOrderTypeEnum.电费订单]: '电费充值',
  [LifeRechargeConstants.LifePayOrderTypeEnum.燃气订单]: '燃气充值',
};
</script>
apps/taro/src/subpackages/userAccount/editElectricUserAccount/InnerPage.vue
New file
@@ -0,0 +1,22 @@
<template>
  <ContentScrollView :paddingH="false">
    <EditElectricUserAccount :id="id" @success="handleSuccess" />
  </ContentScrollView>
</template>
<script setup lang="ts">
import Taro from '@tarojs/taro';
import { EditElectricUserAccount } from '@life-payment/components';
import { goBack } from '@/utils';
defineOptions({
  name: 'InnerPage',
});
const router = Taro.useRouter();
const id = router.params?.id ?? '';
function handleSuccess() {
  goBack();
}
</script>
apps/taro/src/subpackages/userAccount/editElectricUserAccount/editElectricUserAccount.config.ts
New file
@@ -0,0 +1,3 @@
export default definePageConfig({
  disableScroll: true,
});
apps/taro/src/subpackages/userAccount/editElectricUserAccount/editElectricUserAccount.vue
New file
@@ -0,0 +1,14 @@
<template>
  <PageLayout title="编辑" class="editElectricUserAccount-page-wrapper" hasBorder>
    <InnerPage />
  </PageLayout>
</template>
<script setup lang="ts">
import { PageLayout } from '@/components';
import InnerPage from './InnerPage.vue';
defineOptions({
  name: 'editElectricUserAccount',
});
</script>
apps/taro/src/subpackages/userAccount/editGasUserAccount/InnerPage.vue
New file
@@ -0,0 +1,22 @@
<template>
  <ContentScrollView :paddingH="false">
    <EditGasUserAccount :id="id" @success="handleSuccess" />
  </ContentScrollView>
</template>
<script setup lang="ts">
import Taro from '@tarojs/taro';
import { EditGasUserAccount } from '@life-payment/components';
import { goBack } from '@/utils';
defineOptions({
  name: 'InnerPage',
});
const router = Taro.useRouter();
const id = router.params?.id ?? '';
function handleSuccess() {
  goBack();
}
</script>
apps/taro/src/subpackages/userAccount/editGasUserAccount/editGasUserAccount.confg.ts
New file
@@ -0,0 +1,3 @@
export default definePageConfig({
  disableScroll: true,
});
apps/taro/src/subpackages/userAccount/editGasUserAccount/editGasUserAccount.vue
New file
@@ -0,0 +1,14 @@
<template>
  <PageLayout title="编辑" class="editGasUserAccount-page-wrapper" hasBorder>
    <InnerPage />
  </PageLayout>
</template>
<script setup lang="ts">
import { PageLayout } from '@/components';
import InnerPage from './InnerPage.vue';
defineOptions({
  name: 'editGasUserAccount',
});
</script>
apps/taro/src/subpackages/userAccount/editPhoneUserAccount/InnerPage.vue
New file
@@ -0,0 +1,22 @@
<template>
  <ContentScrollView :paddingH="false">
    <EditPhoneUserAccount :id="id" @success="handleSuccess" />
  </ContentScrollView>
</template>
<script setup lang="ts">
import Taro from '@tarojs/taro';
import { EditPhoneUserAccount } from '@life-payment/components';
import { goBack } from '@/utils';
defineOptions({
  name: 'InnerPage',
});
const router = Taro.useRouter();
const id = router.params?.id ?? '';
function handleSuccess() {
  goBack();
}
</script>
apps/taro/src/subpackages/userAccount/editPhoneUserAccount/editPhoneUserAccount.config.ts
New file
@@ -0,0 +1,3 @@
export default definePageConfig({
  disableScroll: true,
});
apps/taro/src/subpackages/userAccount/editPhoneUserAccount/editPhoneUserAccount.vue
New file
@@ -0,0 +1,14 @@
<template>
  <PageLayout title="编辑" class="editPhoneUserAccount-page-wrapper" hasBorder>
    <InnerPage />
  </PageLayout>
</template>
<script setup lang="ts">
import { PageLayout } from '@/components';
import InnerPage from './InnerPage.vue';
defineOptions({
  name: 'editPhoneUserAccount',
});
</script>
apps/taro/src/subpackages/userAccount/userAccountList/InnerPage.vue
New file
@@ -0,0 +1,29 @@
<template>
  <UserAccountListView @go-edit="handleGoEdit" />
</template>
<script setup lang="ts">
import { UserAccountListView } from '@life-payment/components';
import { UserAccountListOutput, LifeRechargeConstants } from '@life-payment/core-vue';
import Taro from '@tarojs/taro';
defineOptions({
  name: 'InnerPage',
});
function handleGoEdit(row: UserAccountListOutput) {
  if (row.lifePayType === LifeRechargeConstants.LifePayOrderTypeEnum.话费订单) {
    Taro.navigateTo({
      url: `${RouterPath.editPhoneUserAccount}?id=${row.id}`,
    });
  } else if (row.lifePayType === LifeRechargeConstants.LifePayOrderTypeEnum.电费订单) {
    Taro.navigateTo({
      url: `${RouterPath.editElectricUserAccount}?id=${row.id}`,
    });
  } else if (row.lifePayType === LifeRechargeConstants.LifePayOrderTypeEnum.燃气订单) {
    Taro.navigateTo({
      url: `${RouterPath.editGasUserAccount}?id=${row.id}`,
    });
  }
}
</script>
apps/taro/src/subpackages/userAccount/userAccountList/userAccountList.config.ts
New file
@@ -0,0 +1,3 @@
export default definePageConfig({
  disableScroll: true,
});
apps/taro/src/subpackages/userAccount/userAccountList/userAccountList.vue
New file
@@ -0,0 +1,14 @@
<template>
  <PageLayout title="户号管理" class="userAccountList-page-wrapper" hasBorder>
    <InnerPage> </InnerPage>
  </PageLayout>
</template>
<script setup lang="ts">
import { PageLayout } from '@/components';
import InnerPage from './InnerPage.vue';
defineOptions({
  name: 'userAccountList',
});
</script>
apps/taro/src/utils/blLifeRecharge.ts
@@ -7,4 +7,5 @@
  axiosConfig: config,
  userId: getStorageVirtualUserId()?.virtualUserId ?? '',
  phoneNumber: getStorageVirtualUserId()?.virtualPhoneNumber ?? '',
  channlesNum: '818',
});
packages/components/package.json
@@ -45,6 +45,7 @@
    "@life-payment/core-vue": "workspace:^",
    "@nutui/icons-vue-taro": "0.0.9",
    "@nutui/nutui-taro": "4.3.13",
    "@tanstack/vue-query": "4.35.3",
    "@tarojs/components": "3.6.20",
    "@tarojs/taro": "3.6.20",
    "@vitejs/plugin-vue": "^5.1.4",
@@ -57,6 +58,7 @@
  "peerDependencies": {
    "@life-payment/core-vue": "*",
    "@nutui/nutui-taro": "*",
    "@tanstack/vue-query": "4.35.3",
    "@tarojs/components": "*",
    "@tarojs/taro": "*",
    "vue": "*"
packages/components/src/components/Card/AccountAddCard.vue
New file
@@ -0,0 +1,19 @@
<template>
  <div class="account-add-card"><Uploader /> {{ text }}</div>
</template>
<script setup lang="ts">
import { Uploader } from '@nutui/icons-vue-taro';
defineOptions({
  name: 'AccountAddCard',
});
type Props = {
  text?: string;
};
const props = withDefaults(defineProps<Props>(), {
  text: '新增手机号',
});
</script>
packages/components/src/components/Card/AccountCard.vue
New file
@@ -0,0 +1,26 @@
<template>
  <div class="account-card">
    <div class="account-card-top">
      <div class="account-card-title">{{ title }}</div>
      <div class="account-card-actions">
        <slot name="action" />
      </div>
    </div>
    <div class="account-card-content">{{ content }}</div>
    <div class="account-card-remark">{{ remark }}</div>
  </div>
</template>
<script setup lang="ts">
defineOptions({
  name: 'AccountCard',
});
type Props = {
  title?: string;
  content?: string;
  remark?: string;
};
const props = withDefaults(defineProps<Props>(), {});
</script>
packages/components/src/components/Card/AccountList.vue
New file
@@ -0,0 +1,9 @@
<template>
  <div class="par-account-list"></div>
</template>
<script setup lang="ts">
defineOptions({
  name: 'AccountList',
});
</script>
packages/components/src/components/Card/OrderCard.vue
@@ -3,10 +3,30 @@
    <div class="order-card-title">
      <div class="order-card-title-top">
        <div class="order-card-title-text">{{ title }}</div>
        <div class="order-card-title-status">{{ status }}</div>
        <div class="order-card-title-status">
          {{ LifeRechargeConstants.LifePayOrderFrontStatusEnumText[status] }}
        </div>
      </div>
      <div class="order-card-title-ordernum">
        {{ `订单编号:${orderNo}` }}
      <div class="order-card-title-ordernum-wrapper">
        <div class="order-card-title-ordernum">
          {{ `订单编号:${orderNo}` }}
        </div>
        <slot name="actions">
          <div
            class="order-card-action"
            v-if="status === LifeRechargeConstants.LifePayOrderFrontStatusEnum.支付成功"
            @click="emit('goApplyRefund', id)"
          >
            申请退款
          </div>
          <div
            class="order-card-action"
            v-if="status === LifeRechargeConstants.LifePayOrderFrontStatusEnum.退款失败"
            @click="emit('goRefundDetail', orderNo)"
          >
            详情
          </div>
        </slot>
      </div>
    </div>
    <div class="order-card-content">
@@ -16,15 +36,23 @@
</template>
<script setup lang="ts">
import { LifeRechargeConstants } from '@life-payment/core-vue';
defineOptions({
  name: 'OrderCard',
});
type Props = {
  title: string;
  status: string;
  status: LifeRechargeConstants.LifePayOrderFrontStatusEnum;
  orderNo: string;
  id: string;
};
const props = withDefaults(defineProps<Props>(), {});
const emit = defineEmits<{
  (e: 'goApplyRefund', id: string): void;
  (e: 'goRefundDetail', orderNo: string): void;
}>();
</script>
packages/components/src/components/Dialog/ConfirmDialogInfoItem.vue
@@ -1,11 +1,16 @@
<template>
  <div class="confirm-dialog-content-info-item" :class="{ danger }">
    <div class="confirm-dialog-content-info-item-label">{{ label }}</div>
    <div class="confirm-dialog-content-info-item-label" :style="{ width: _labelWidth }">
      {{ label }}
    </div>
    <div class="confirm-dialog-content-info-item-content">{{ content }}</div>
  </div>
</template>
<script setup lang="ts">
import Taro from '@tarojs/taro';
import { computed } from 'vue';
defineOptions({
  name: 'ConfirmDialogInfoItem',
});
@@ -14,7 +19,18 @@
  label?: string;
  content?: string | number;
  danger?: boolean;
  labelWidth?: string | number;
};
const props = withDefaults(defineProps<Props>(), {});
const props = withDefaults(defineProps<Props>(), {
  labelWidth: 'auto',
});
const _labelWidth = computed(() => {
  if (typeof props.labelWidth === 'string') {
    return props.labelWidth;
  }
  return Taro.pxTransform(props.labelWidth);
});
</script>
packages/components/src/components/Input/ChooseInputWithAreaPicker.vue
New file
@@ -0,0 +1,62 @@
<template>
  <ChooseInput :modelValue="inputValue" @click="handleOpen()" v-bind="$attrs"></ChooseInput>
  <NutPopup v-model:visible="visible" position="bottom">
    <NutPicker
      :modelValue="modelValue"
      :columns="columns"
      :fieldNames="fieldNames"
      :title="title"
      @cancel="visible = false"
      @confirm="handleConfirm"
    >
    </NutPicker>
  </NutPopup>
</template>
<script setup lang="ts">
// import { useAllAreaList } from '../../hooks/area';
import ChooseInput from './ChooseInput.vue';
import { Popup as NutPopup, Picker as NutPicker } from '@nutui/nutui-taro';
import { computed, ref } from 'vue';
defineOptions({
  name: 'ChooseInputWithAreaPicker',
});
// const { findAreaNameFromCode } = useAllAreaList();
type Props = {
  fieldNames?: object;
  columns: API.AreaTreeNode[];
  modelValue: Array<string | number>;
  title?: string;
};
const props = withDefaults(defineProps<Props>(), {
  title: '选择地址',
  fieldNames: () => ({
    text: 'areaName',
    value: 'areaName',
    children: 'children',
  }),
});
const inputValue = computed(() => props.modelValue.join(','));
const emit = defineEmits<{
  (e: 'update:modelValue', val: Array<string | number>): void;
}>();
const visible = ref(false);
function handleOpen() {
  visible.value = true;
}
function handleConfirm({ selectedValue, selectedOptions }) {
  emit(
    'update:modelValue',
    selectedOptions.map((x) => x.areaName)
  );
  visible.value = false;
}
</script>
packages/components/src/components/RechargeTipsView/RechargeTipsView.vue
@@ -3,7 +3,9 @@
    <div class="recharge-tips-title">充值须知</div>
    <div class="recharge-tips-content">
      <div class="recharge-tips-top">
        *同一号码充值期间【切勿多平台重复充值】!!!在下单前,请务必仔细阅读公告内容!!!若接到陌生来电,请勿轻信!!!
        <slot name="tips-top">
          *同一号码充值期间【切勿多平台重复充值】!!!在下单前,请务必仔细阅读公告内容!!!若接到陌生来电,请勿轻信!!!
        </slot>
      </div>
      <div class="recharge-tips-list">
        <div class="recharge-tips-item" v-for="(item, index) in props.tips" :key="index">
packages/components/src/constants/index.ts
@@ -23,3 +23,6 @@
   */
  Desc,
}
export const CustomerServicePhone = '16505012333';
export const CustomerServiceTips = `如充值过程中遇到问题,请联系客服 ${CustomerServicePhone}(周一到周五 9:00-17:30)`;
packages/components/src/hooks/area.ts
New file
@@ -0,0 +1,103 @@
import { useQuery } from '@tanstack/vue-query';
import { computed } from 'vue';
import { useLifeRechargeContext, AreaInfo } from '@life-payment/core-vue';
// import { AreaType } from '@12333/constants';
export function flattenAreaTree(tree: AreaInfo[]) {
  let result = [] as AreaInfo[];
  // 递归函数,用于遍历子节点
  function flatten(node: AreaInfo) {
    result.push(node);
    if (node.children && node.children.length > 0) {
      node.children.forEach(flatten);
    }
  }
  // 遍历树的根节点
  tree.forEach(flatten);
  return result;
}
export function useArea() {
  const { blLifeRecharge } = useLifeRechargeContext();
  const { data: areaStore } = useQuery({
    queryKey: ['blLifeRecharge/getRegionalManagementList'],
    queryFn: async () => {
      return await blLifeRecharge.services.getRegionalManagementList({ showLoading: false });
    },
    placeholderData: () => [] as AreaInfo[],
    staleTime: Infinity,
    select(data) {
      const areaItemMap: Record<AreaInfo['areaCode'], AreaInfo> = {};
      data.forEach((item) => {
        areaItemMap[item.areaCode] = item;
      });
      const completeAreaList = flattenAreaTree([...data]);
      return {
        completeAreaList: completeAreaList,
        completeAreaTree: [...data],
        // cityAreaTree: formatAreaListToTree(completeAreaList, 0, AreaType.City),
        provinceList: [...data],
        areaItemMap: areaItemMap,
      };
    },
  });
  function getAreaFromCompleteAreaList(areaCode: number) {
    return areaStore.value.completeAreaList.find((x) => x.areaCode === areaCode);
  }
  function getAreaByAreaCode(areaCode: number) {
    return areaStore.value.areaItemMap[areaCode];
  }
  return {
    completeAreaList: computed(() => areaStore.value.completeAreaList),
    completeAreaTree: computed(() => areaStore.value.completeAreaTree),
    cityAreaTree: computed(() =>
      areaStore.value.completeAreaTree.map((x) => ({
        ...x,
        children: x.children.map((y) => ({
          ...y,
          children: undefined,
        })),
      }))
    ),
    provinceList: computed(() => areaStore.value.provinceList),
    areaItemMap: computed(() => areaStore.value.areaItemMap),
    getAreaFromCompleteAreaList,
    getAreaByAreaCode,
  };
}
export function useAllAreaList() {
  const { completeAreaTree, provinceList, completeAreaList, cityAreaTree } = useArea();
  const findAreaCodeFromName = (areaName: string) => {
    const areaItem = completeAreaList.value.find((x) => x.areaName === areaName);
    return areaItem?.areaCode ?? 0;
  };
  const findAreaNameFromCode = (areaCode: number) => {
    const areaItem = completeAreaList.value.find((x) => x.areaCode === areaCode);
    return areaItem?.areaName ?? '';
  };
  const findAreaItemFromCode = (areaCode: number) => {
    const areaItem = completeAreaList.value.find((x) => x.areaCode === areaCode);
    return areaItem;
  };
  return {
    findAreaCodeFromName,
    findAreaNameFromCode,
    findAreaItemFromCode,
    areaTreeList: completeAreaTree,
    provinceList,
    cityAreaTree,
  };
}
packages/components/src/hooks/index.ts
@@ -7,8 +7,13 @@
  LifeRechargeConstants,
  ElectricParValueResponse,
  ElectricSupportAreaResponse,
  QueryUserAccountAllListInput,
  UserAccountListOutput,
  AddUpdateUserAccountInput,
  GasParValueResponse,
  GasParValueOutput,
} from '@life-payment/core-vue';
import { useQuery } from '@tanstack/vue-query';
import { useQuery, useQueryClient } from '@tanstack/vue-query';
import { computed, MaybeRef, reactive, unref } from 'vue';
import { useInfiniteLoading } from './infiniteLoading';
import { OrderInputType } from '../constants';
@@ -28,20 +33,28 @@
    () =>
      lifePayRateList.value.find(
        (x) => x.rateType === blLifeRecharge.constants.LifePayRateTypeEnum.默认话费折扣
      )?.rate ?? 1
      )?.rate ?? 100
  );
  const lifePayElectricRate = computed(
    () =>
      lifePayRateList.value.find(
        (x) => x.rateType === blLifeRecharge.constants.LifePayRateTypeEnum.默认电费折扣
      )?.rate ?? 1
      )?.rate ?? 100
  );
  const lifePayGasRate = computed(
    () =>
      lifePayRateList.value.find(
        (x) => x.rateType === blLifeRecharge.constants.LifePayRateTypeEnum.默认燃气折扣
      )?.rate ?? 100
  );
  return {
    lifePayRateList,
    lifePayPhoneRate,
    lifePayElectricRate,
    lifePayGasRate,
  };
}
@@ -51,7 +64,7 @@
  const { data: phoneParValueList, isLoading } = useQuery({
    queryKey: ['blLifeRecharge/getPhoneParValue'],
    queryFn: async () => {
      return await blLifeRecharge.services.getPhoneParValue({ showLoading: false });
      return await blLifeRecharge.services.getPhoneParValue({}, { showLoading: false });
    },
    select(data) {
      return data?.phoneParValue ?? [];
@@ -70,7 +83,7 @@
  const { data: electricParValueList, isLoading } = useQuery({
    queryKey: ['blLifeRecharge/getElectricSupportArea'],
    queryFn: async () => {
      return await blLifeRecharge.services.getElectricSupportArea({ showLoading: false });
      return await blLifeRecharge.services.getElectricSupportArea({}, { showLoading: false });
    },
    select(data) {
      return data.electricAreaList ?? [];
@@ -127,3 +140,127 @@
    infiniteLoadingProps,
  };
}
type UseUserAccountAllListOptions = {
  lifePayOrderType: MaybeRef<LifeRechargeConstants.LifePayOrderTypeEnum>;
  onSuccess?: (data: UserAccountListOutput[]) => any;
};
export function useUserAccountAllList({
  lifePayOrderType,
  onSuccess,
}: UseUserAccountAllListOptions) {
  const { blLifeRecharge } = useLifeRechargeContext();
  const { data: userAccountAllList, isLoading } = useQuery({
    queryKey: [
      'blLifeRecharge/getUserAccountAllList',
      blLifeRecharge.accountModel.userId,
      lifePayOrderType,
    ],
    queryFn: async () => {
      let params: QueryUserAccountAllListInput = {
        userId: blLifeRecharge.accountModel.userId,
        lifePayOrderType: unref(lifePayOrderType),
      };
      return await blLifeRecharge.services.getUserAccountAllList(params, { showLoading: false });
    },
    placeholderData: () => [] as UserAccountListOutput[],
    onSuccess(data) {
      onSuccess?.(data);
    },
  });
  const queryClient = useQueryClient();
  function invalidateQueries() {
    return queryClient.invalidateQueries({
      queryKey: [
        'blLifeRecharge/getUserAccountAllList',
        blLifeRecharge.accountModel.userId,
        lifePayOrderType,
      ],
    });
  }
  return {
    userAccountAllList,
    isLoading,
    invalidateQueries,
  };
}
export function useAddUpdateUserAccount() {
  const { blLifeRecharge } = useLifeRechargeContext();
  const queryClient = useQueryClient();
  function invalidateQueries(lifePayOrderType: LifeRechargeConstants.LifePayOrderTypeEnum) {
    return queryClient.invalidateQueries({
      queryKey: [
        'blLifeRecharge/getUserAccountAllList',
        blLifeRecharge.accountModel.userId,
        lifePayOrderType,
      ],
    });
  }
  async function addUpdateUserAccount(params: AddUpdateUserAccountInput) {
    let res = await blLifeRecharge.services.addUpdateUserAccount(params);
    if (res) {
      invalidateQueries(params.lifePayType);
    }
    return res;
  }
  return { addUpdateUserAccount };
}
type UseSetUserAccountBySelectOptions = {
  lifePayOrderType: MaybeRef<LifeRechargeConstants.LifePayOrderTypeEnum>;
  onSetUserAccount: (currentUserAccount: UserAccountListOutput) => any;
};
export function useSetUserAccountBySelect({
  lifePayOrderType,
  onSetUserAccount,
}: UseSetUserAccountBySelectOptions) {
  const { userAccountAllList } = useUserAccountAllList({
    lifePayOrderType: lifePayOrderType,
    onSuccess(data) {
      if (data.length > 0) {
        const currentUserAccount = data[0];
        onSetUserAccount?.(currentUserAccount);
      }
    },
  });
  function handleUserAccountChange(val: string) {
    const currentUserAccount = userAccountAllList.value.find((x) => x.id === val);
    onSetUserAccount?.(currentUserAccount);
  }
  return {
    handleUserAccountChange,
    userAccountAllList,
  };
}
export function useGetGasParValue() {
  const { blLifeRecharge } = useLifeRechargeContext();
  const { data: gasParValueList, isLoading } = useQuery({
    queryKey: ['blLifeRecharge/getGasParValue'],
    queryFn: async () => {
      return await blLifeRecharge.services.getGasParValue({}, { showLoading: false });
    },
    select(data) {
      return data?.gasParValue ?? [];
    },
    placeholderData: () => ({} as GasParValueResponse),
  });
  return {
    gasParValueList,
  };
}
packages/components/src/index.ts
@@ -1,8 +1,16 @@
export { default as RechargeGrid } from './views/RechargeGrid/RechargeGrid.vue';
export { default as PhoneBillRecharge } from './views/PhoneBillRecharge/PhoneBillRecharge.vue';
export { default as electricBillRecharge } from './views/electricBillRecharge/electricBillRecharge.vue';
export { default as GasBillRecharge } from './views/GasBillRecharge/GasBillRecharge.vue';
export { default as SelectPayTypeView } from './views/SelectPayTypeView/SelectPayTypeView.vue';
export { default as RechargeResultView } from './views/RechargeResultView/RechargeResultView.vue';
export { default as PhoneOrder } from './views/Order/components/PhoneOrder.vue';
export { default as ElectricOrder } from './views/Order/components/ElectricOrder.vue';
export { default as GasOrder } from './views/Order/components/GasOrder.vue';
export { default as OrderApplyRefundView } from './views/Order/OrderApplyRefundView.vue';
export { default as OrderRefundResultView } from './views/Order/OrderRefundResultView.vue';
export { default as UserAccountListView } from './views/userAccount/UserAccountListView.vue';
export { default as EditPhoneUserAccount } from './views/userAccount/EditPhoneUserAccount.vue';
export { default as EditElectricUserAccount } from './views/userAccount/EditElectricUserAccount.vue';
export { default as EditGasUserAccount } from './views/userAccount/EditGasUserAccount.vue';
export * from './utils';
packages/components/src/styles/card.scss
New file
@@ -0,0 +1,74 @@
@use './common.scss' as *;
.account-add-card {
  border-radius: 16px;
  min-height: 120px;
  border: 1px solid #e8e8e8;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 32px;
  color: boleGetCssVar('color', 'primary');
}
.account-card {
  border-radius: 16px;
  border: 1px solid #e8e8e8;
  padding: 28px;
  .account-card-top {
    display: flex;
    font-size: 28px;
    line-height: 32px;
    align-items: center;
    margin-bottom: 32px;
    .account-card-title {
      flex: 1;
      min-width: 0;
      @include ellipsis;
      color: boleGetCssVar('text-color', 'primary');
    }
    .account-card-actions {
      display: flex;
      align-items: center;
      .account-card-action {
        color: boleGetCssVar('color', 'primary');
      }
      .account-card-action + .account-card-action {
        margin-left: 10px;
      }
    }
  }
  .account-card-content {
    font-size: 36px;
    font-weight: bold;
    line-height: 48px;
    align-items: center;
    margin-bottom: 32px;
    color: boleGetCssVar('text-color', 'primary');
    @include ellipsis;
  }
  .account-card-remark {
    font-size: 28px;
    line-height: 32px;
    color: boleGetCssVar('text-color', 'secondary');
    @include ellipsis;
  }
}
.par-account-list {
  .nut-radio--button {
    margin-bottom: 20px !important;
    &:last-child {
      margin-right: 20px !important;
      margin-bottom: 20px !important;
    }
  }
}
packages/components/src/styles/components.scss
@@ -50,6 +50,7 @@
      .confirm-dialog-content-info-item-label {
        color: boleGetCssVar('text-color', 'regular');
        margin-right: 12px;
        text-align: left;
      }
      .confirm-dialog-content-info-item-content {
@@ -110,6 +111,14 @@
    line-height: 48px;
  }
  .recharge-result-view-subtitle {
    font-size: 28px;
    color: boleGetCssVar('text-color', 'primary');
    margin-bottom: 24px;
    text-align: center;
    line-height: 32px;
  }
  .recharge-result-view-tips {
    margin-bottom: 24px;
    font-size: 32px;
@@ -118,12 +127,26 @@
  }
  .recharge-result-view-warning {
    margin-bottom: 40px;
    margin-bottom: 24px;
    font-size: 24px;
    color: boleGetCssVar('color', 'warning');
    line-height: 32px;
  }
  .recharge-result-view-customerService {
    margin-bottom: 40px;
    font-size: 24px;
    color: boleGetCssVar('text-color', 'primary');
    line-height: 32px;
  }
  .recharge-result-view-remark {
    margin-bottom: 40px;
    font-size: 24px;
    color: boleGetCssVar('text-color', 'primary');
    line-height: 32px;
  }
  .recharge-result-view-btn-wrapper {
    display: flex;
    justify-content: center;
packages/components/src/styles/gas.scss
New file
@@ -0,0 +1,24 @@
@use './common.scss' as *;
.gas-bill-recharge-wrapper {
  .gasOrgType-card {
    border-radius: 16px;
    border: 1px solid #e8e8e8;
    padding: 28px;
    min-height: 120px;
    margin-bottom: 30px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    &:last-child {
      margin-bottom: 0;
    }
    .gasOrgType-card-title {
      font-size: 36px;
      line-height: 48px;
      color: boleGetCssVar('text-color', 'primary');
    }
  }
}
packages/components/src/styles/index.scss
@@ -2,6 +2,8 @@
@use './var.scss' as *;
@use './function.scss' as *;
@use './orderCard.scss' as *;
@use './card.scss' as *;
@use './gas.scss' as *;
@use './nut.scss' as *;
@use './layout.scss' as *;
@use './rechargeGrid.scss' as *;
packages/components/src/styles/nut.scss
@@ -127,7 +127,7 @@
  .bole-input-textarea:not(.nut-input--disabled) {
    color: boleGetCssVar('text-color', 'primary') !important;
    height: 100rpx;
    height: 200px;
  }
  .bole-input-text-placeholder {
@@ -168,4 +168,14 @@
  .pro-form-item-tips {
    word-break: break-all;
  }
  .nut-dialog__header {
    height: 44px;
  }
  .nut-dialog__footer {
    .nut-button--plain {
      border-width: 1px;
    }
  }
}
packages/components/src/styles/orderCard.scss
@@ -31,6 +31,19 @@
    .order-card-title-ordernum {
      font-size: 24px;
      color: #999999;
      flex: 1;
      min-width: 0;
      @include ellipsis;
    }
    .order-card-title-ordernum-wrapper {
      display: flex;
      align-items: center;
      .order-card-action {
        font-size: 24px;
        color: boleGetCssVar('color', 'primary');
      }
    }
  }
}
packages/components/src/styles/rechargeGrid.scss
@@ -128,6 +128,10 @@
        margin-left: 20px;
      }
    }
    &.nut-button--plain {
      border-width: 1px;
    }
  }
  &.electric {
packages/components/src/utils/common.ts
@@ -149,3 +149,32 @@
  }
  return '';
}
export function convertOrderFrontStatus(
  payStatus?: LifeRechargeConstants.LifePayStatusEnum,
  lifePayOrderStatus?: LifeRechargeConstants.LifePayOrderStatusEnum
) {
  if (
    (lifePayOrderStatus === LifeRechargeConstants.LifePayOrderStatusEnum.待确认 &&
      payStatus === LifeRechargeConstants.LifePayStatusEnum.已支付) ||
    payStatus === LifeRechargeConstants.LifePayStatusEnum.待退款
  ) {
    return LifeRechargeConstants.LifePayOrderFrontStatusEnum.支付成功;
  }
  if (lifePayOrderStatus === LifeRechargeConstants.LifePayOrderStatusEnum.已退款) {
    return LifeRechargeConstants.LifePayOrderFrontStatusEnum.已退款;
  }
  if (lifePayOrderStatus === LifeRechargeConstants.LifePayOrderStatusEnum.退款待审核) {
    return LifeRechargeConstants.LifePayOrderFrontStatusEnum.退款待审核;
  }
  if (lifePayOrderStatus === LifeRechargeConstants.LifePayOrderStatusEnum.退款失败) {
    return LifeRechargeConstants.LifePayOrderFrontStatusEnum.退款失败;
  }
  if (
    lifePayOrderStatus === LifeRechargeConstants.LifePayOrderStatusEnum.已完成 &&
    payStatus === LifeRechargeConstants.LifePayStatusEnum.已支付
  ) {
    return LifeRechargeConstants.LifePayOrderFrontStatusEnum.充值成功;
  }
  return;
}
packages/components/src/utils/validator.ts
@@ -13,12 +13,12 @@
    return Promise.resolve(true);
  }
  // static validatorArray(value: any, ruleCfg: FormItemRuleWithoutValidator) {
  //   if (!_.isArray(value) || !value?.length) {
  //     return Promise.reject(ruleCfg.message);
  //   }
  //   return Promise.resolve(true);
  // }
  static validatorArray(value: any, ruleCfg: FormItemRuleWithoutValidator) {
    if (!Array.isArray(value) || !value?.length) {
      return Promise.reject(ruleCfg.message);
    }
    return Promise.resolve(true);
  }
  // 身份证后六位
  static validatorIDNumberSix(value: string, ruleCfg: FormItemRuleWithoutValidator) {
packages/components/src/views/GasBillRecharge/GasBillRecharge.vue
New file
@@ -0,0 +1,52 @@
<template>
  <GasBillRechargeStep1 v-if="current === 'step1'" />
  <GasBillRechargeStep2 v-else-if="current === 'step2'" />
  <GasBillRechargeStep3
    v-else-if="current === 'step3'"
    v-bind="props"
    @go-pay="emit('goPay', $event)"
  />
</template>
<script setup lang="ts">
import { computed, provide, reactive } from 'vue';
import { useStepper } from 'senin-mini/hooks';
import { GasBillRechargeContextKey } from './context';
import GasBillRechargeStep1 from './GasBillRechargeStep1.vue';
import GasBillRechargeStep2 from './GasBillRechargeStep2.vue';
import GasBillRechargeStep3 from './GasBillRechargeStep3.vue';
import { LifeRechargeConstants } from '@life-payment/core-vue';
defineOptions({
  name: 'GasBillRecharge',
});
type Props = {
  isDev?: boolean;
};
const props = withDefaults(defineProps<Props>(), {
  isDev: false,
});
const stepperInfo = useStepper(['step1', 'step2', 'step3'], 'step3');
const current = computed(() => stepperInfo.current.value);
const emit = defineEmits<{
  (e: 'goPay', orderNo: string): void;
}>();
const preSetForm = reactive({
  gasOrgType: '',
  // province: '',
  // city: '',
  gasAccount: '',
  remark: '',
  areaList: [] as string[],
});
provide(GasBillRechargeContextKey, {
  ...stepperInfo,
  preSetForm,
});
</script>
packages/components/src/views/GasBillRecharge/GasBillRechargeBaseForm.vue
New file
@@ -0,0 +1,65 @@
<template>
  <NutForm
    :model-value="form"
    ref="formRef"
    :rules="rules"
    label-position="top"
    class="order-bill-recharge electric"
  >
    <slot name="top"></slot>
    <NutFormItem label="所在城市" class="bole-form-item" prop="areaList" required>
      <ChooseInputWithAreaPicker
        :columns="cityAreaTree"
        v-model="form.areaList"
        placeholder="请选择所在城市"
      ></ChooseInputWithAreaPicker>
    </NutFormItem>
    <NutFormItem label="缴费户号" class="bole-form-item" prop="gasAccount" required>
      <NutInput
        v-model.trim="form.gasAccount"
        class="bole-input-text"
        placeholder="请输入缴费户号"
        type="text"
        max-length="13"
      />
    </NutFormItem>
    <slot></slot>
  </NutForm>
</template>
<script setup lang="ts">
import { Form as NutForm, FormItem as NutFormItem, Input as NutInput } from '@nutui/nutui-taro';
import { FormRules } from '@nutui/nutui-taro/dist/types/__VUE/form/types';
import { reactive, ref, computed, watch } from 'vue';
import ChooseInputWithAreaPicker from '../../components/Input/ChooseInputWithAreaPicker.vue';
import { useAllAreaList } from '../../hooks/area';
import { FormValidator } from '../../utils';
defineOptions({
  name: 'GasBillRechargeBaseForm',
});
const { findAreaNameFromCode, cityAreaTree } = useAllAreaList();
const form = defineModel<{
  // province: string;
  // city: string;
  gasAccount: string;
  areaList: string[];
}>('form');
const rules = reactive<FormRules>({
  province: [{ required: true, message: '请选择所在区域' }],
  city: [{ required: true, message: '请选择所在城市' }],
  gasAccount: [{ required: true, message: '请输入缴费户号', regex: /^\d{13}$/ }],
  areaList: [
    { required: true, message: '请选择所在城市', validator: FormValidator.validatorArray },
  ],
});
const formRef = ref<any>(null);
defineExpose({
  validate: computed(() => formRef.value.validate),
});
</script>
packages/components/src/views/GasBillRecharge/GasBillRechargeStep1.vue
New file
@@ -0,0 +1,40 @@
<template>
  <NutForm label-position="top" class="order-bill-recharge gas-bill-recharge-wrapper phone">
    <NutFormItem class="bole-form-item">
      <GasOrgTypeCard
        :title="item.gasOrgName"
        v-for="item in gasParValueList"
        :key="item.gasOrgCode"
        @click="goNext(item.gasOrgCode)"
      ></GasOrgTypeCard>
    </NutFormItem>
    <div class="common-content">
      <NutButton class="recharge-button" type="primary" plain @click="goTo('step3')">
        <div class="recharge-button-inner">
          <div class="recharge-button-text">返回</div>
        </div>
      </NutButton>
    </div>
  </NutForm>
</template>
<script setup lang="ts">
import { Form as NutForm, FormItem as NutFormItem, Button as NutButton } from '@nutui/nutui-taro';
import GasOrgTypeCard from './GasOrgTypeCard.vue';
import { BlLifeRecharge, LifeRechargeConstants } from '@life-payment/core-vue';
import { useGasBillRechargeContext } from './context';
import { useGetGasParValue } from '../../hooks';
defineOptions({
  name: 'GasBillRechargeStep1',
});
const { preSetForm, goToNext, goTo } = useGasBillRechargeContext();
const { gasParValueList } = useGetGasParValue();
function goNext(gasOrgType: string) {
  preSetForm.gasOrgType = gasOrgType;
  goToNext();
}
</script>
packages/components/src/views/GasBillRecharge/GasBillRechargeStep2.vue
New file
@@ -0,0 +1,86 @@
<template>
  <GasBillRechargeBaseForm ref="formRef" v-model:form="preSetForm">
    <NutFormItem label="备注信息" class="bole-form-item" prop="remark">
      <NutTextarea
        placeholder="请输入备注信息"
        placeholderClass="bole-input-text-placeholder"
        autoSize
        class="bole-input-textarea"
        v-model="preSetForm.remark"
        :max-length="30"
        limit-show
      >
      </NutTextarea>
    </NutFormItem>
    <div class="common-content">
      <NutButton class="recharge-button" type="primary" @click="handleNext">
        <div class="recharge-button-inner">
          <div class="recharge-button-text">保存</div>
        </div>
      </NutButton>
      <NutButton class="recharge-button" type="primary" plain @click="goToPrevious">
        <div class="recharge-button-inner">
          <div class="recharge-button-text">返回</div>
        </div>
      </NutButton>
    </div>
  </GasBillRechargeBaseForm>
</template>
<script setup lang="ts">
import {
  Button as NutButton,
  FormItem as NutFormItem,
  Textarea as NutTextarea,
} from '@nutui/nutui-taro';
import { reactive, ref, computed, watch } from 'vue';
import GasBillRechargeBaseForm from './GasBillRechargeBaseForm.vue';
import { useGasBillRechargeContext } from './context';
import {
  useLifeRechargeContext,
  LifeRechargeConstants,
  AddUpdateUserAccountInput,
} from '@life-payment/core-vue';
import { useAddUpdateUserAccount } from '../../hooks';
defineOptions({
  name: 'GasBillRechargeStep2',
});
const { preSetForm, goToPrevious, goToNext } = useGasBillRechargeContext();
const formRef = ref<any>(null);
function handleNext() {
  if (!formRef.value) return;
  formRef.value.validate().then(({ valid, errors }: any) => {
    if (valid) {
      handleAddUpdateUserAccount();
    }
  });
}
const { addUpdateUserAccount } = useAddUpdateUserAccount();
const { blLifeRecharge } = useLifeRechargeContext();
async function handleAddUpdateUserAccount() {
  try {
    let params: AddUpdateUserAccountInput = {
      userId: blLifeRecharge.accountModel.userId,
      lifePayType: LifeRechargeConstants.LifePayOrderTypeEnum.燃气订单,
      content: preSetForm.gasAccount,
      province: preSetForm.areaList?.[0] ?? '',
      city: preSetForm.areaList?.[1] ?? '',
      extraProperties: JSON.stringify(preSetForm),
      operators: preSetForm.gasOrgType,
      remark: preSetForm.remark,
    };
    await addUpdateUserAccount(params);
    preSetForm.areaList = [];
    preSetForm.gasAccount = '';
    preSetForm.remark = '';
    preSetForm.gasOrgType = '' as any;
    goToNext();
  } catch (error) {}
}
</script>
packages/components/src/views/GasBillRecharge/GasBillRechargeStep3.vue
New file
@@ -0,0 +1,242 @@
<template>
  <NutForm
    :model-value="form"
    ref="formRef"
    :rules="rules"
    label-position="top"
    class="order-bill-recharge electric"
  >
    <NutFormItem class="bole-form-item" prop="currentUserAccountId">
      <NutRadioGroup
        v-model="form.currentUserAccountId"
        direction="horizontal"
        class="par-account-list"
        v-if="userAccountAllList.length > 0"
        @change="handleUserAccountChange"
      >
        <NutRadio :label="item.id" shape="button" v-for="item in userAccountAllList" :key="item.id"
          >{{ item.city }}-{{ item.content }}</NutRadio
        >
      </NutRadioGroup>
      <AccountCard
        v-if="userAccountAllList.length > 0"
        title="充值户号"
        :content="`${form.areaList?.[1] ?? ''} ${form.gasAccount}`"
        :remark="form.remark"
      >
        <template #action>
          <div class="account-card-action" @click="handleAddUserAccount">新增</div>
        </template>
      </AccountCard>
      <AccountAddCard text="新增户号" v-else @click="handleAddUserAccount" />
    </NutFormItem>
    <NutFormItem label="选择充值金额" class="bole-form-item" prop="parValue" required>
      <NutRadioGroup v-model="form.parValue" direction="horizontal" class="parValue-radio-group">
        <NutRadio
          :label="Number(item)"
          :key="item"
          shape="button"
          v-for="item in gasValueList"
          class="parValue-item"
        >
          <div class="parValue-item-inner">
            <div class="amount-wrapper">
              <div class="amount">{{ item }}</div>
              <div class="unit">元</div>
            </div>
            <div class="price-wrapper">
              <div class="price-text">折后</div>
              <div class="price">
                {{ blLifeRecharge.getRechargeParValue(item, lifePayGasRate) }}元
              </div>
            </div>
            <div class="discountTag">{{ lifePayGasRate }}折</div>
          </div>
        </NutRadio>
      </NutRadioGroup>
    </NutFormItem>
    <div class="common-content">
      <nut-button class="recharge-button" type="primary" @click="handleSubmit">
        <div class="recharge-button-inner">
          <div>¥{{ realParValue }}</div>
          <div class="recharge-button-text">立即充值</div>
        </div>
      </nut-button>
      <RechargeTipsView :tips="tips">
        <template #tips-top>
          同一电费账户在充值期间切勿在多平台重复充值,下单前请仔细阅读下方须知内容。若接到陌生来电,切勿轻信!!!
        </template>
      </RechargeTipsView>
    </div>
    <ConfirmDialog v-model:visible="confirmDialogVisible" @ok="goPay">
      <template #tips>
        该产品为慢充模式,0-72小时内到账,介意请勿付款!充值前请仔细阅读充值须知!
      </template>
      <template #info>
        <ConfirmDialogInfoItem
          label="燃气类型"
          :content="currentGasParValueItem?.gasOrgName ?? ''"
        />
        <ConfirmDialogInfoItem :label-width="96" label="户号" :content="form.gasAccount" />
        <ConfirmDialogInfoItem label="充值金额" :content="`¥${form.parValue.toFixed(2)}`" danger />
        <ConfirmDialogInfoItem label="优惠金额" :content="`¥${discountParValue.toFixed(2)}`" />
        <ConfirmDialogInfoItem label="实付金额" :content="`¥${realParValue}`" danger />
      </template>
      <template #warning>
        同一燃气费账户在充值期间,未到账前切勿在其他任何平台再次充值。因此造成的资金损失须用户自行承担!!!
      </template>
    </ConfirmDialog>
  </NutForm>
</template>
<script setup lang="ts">
import {
  Form as NutForm,
  FormItem as NutFormItem,
  RadioGroup as NutRadioGroup,
  Radio as NutRadio,
  Button as NutButton,
} from '@nutui/nutui-taro';
import { FormRules } from '@nutui/nutui-taro/dist/types/__VUE/form/types';
import { reactive, ref, computed } from 'vue';
import {
  useLifeRechargeContext,
  LifeElectricDataCreateLifePayOrderInput,
  LifeRechargeConstants,
  LifeGasDataCreateLifePayOrderInput,
} from '@life-payment/core-vue';
import { useGetRate, useGetGasParValue, useSetUserAccountBySelect } from '../../hooks';
import { useGasBillRechargeContext, GasUserAccountExtraProperties } from './context';
import { FormValidator } from '../../utils';
import { CustomerServiceTips } from '../../constants';
import AccountAddCard from '../../components/Card/AccountAddCard.vue';
import AccountCard from '../../components/Card/AccountCard.vue';
import RechargeTipsView from '../../components/RechargeTipsView/RechargeTipsView.vue';
import ConfirmDialog from '../../components/Dialog/ConfirmDialog.vue';
import ConfirmDialogInfoItem from '../../components/Dialog/ConfirmDialogInfoItem.vue';
defineOptions({
  name: 'GasBillRechargeStep3',
});
type Props = {
  isDev?: boolean;
};
const props = withDefaults(defineProps<Props>(), {
  isDev: false,
});
const emit = defineEmits<{
  (e: 'goPay', orderNo: string): void;
}>();
const { goTo } = useGasBillRechargeContext();
const { blLifeRecharge } = useLifeRechargeContext();
const { lifePayGasRate } = useGetRate();
const { gasParValueList } = useGetGasParValue();
const form = reactive({
  parValue: 0,
  // province: '',
  // city: '',
  gasOrgType: '',
  gasAccount: '',
  currentUserAccountId: '',
  remark: '',
  areaList: [] as string[],
});
const { userAccountAllList, handleUserAccountChange } = useSetUserAccountBySelect({
  lifePayOrderType: LifeRechargeConstants.LifePayOrderTypeEnum.燃气订单,
  onSetUserAccount(currentUserAccount) {
    const currentUserAccountExtraProperties = JSON.parse(
      currentUserAccount.extraProperties
    ) as GasUserAccountExtraProperties;
    form.currentUserAccountId = currentUserAccount.id;
    form.gasAccount = currentUserAccount.content;
    form.areaList = [currentUserAccount.province, currentUserAccount.city];
    form.gasOrgType = currentUserAccount.operators;
    form.remark = currentUserAccount.remark;
    const gasParValueItem = gasParValueList.value.find((x) => x.gasOrgCode === form.gasOrgType);
    if (gasParValueItem && gasParValueItem.parValue.every((x) => Number(x) !== form.parValue)) {
      form.parValue = 0;
    }
  },
});
function handleAddUserAccount() {
  goTo('step1');
}
const currentGasParValueItem = computed(() =>
  gasParValueList.value.find((x) => x.gasOrgCode === form.gasOrgType)
);
const gasValueList = computed(() => {
  const gasValueList = currentGasParValueItem.value?.parValue ?? [];
  return blLifeRecharge.filterParValueList(gasValueList);
});
const realParValue = computed(() =>
  blLifeRecharge.getRechargeParValue(form.parValue, lifePayGasRate.value)
);
const discountParValue = computed(() => form.parValue - Number(realParValue.value));
const rules = reactive<FormRules>({
  parValue: [
    { required: true, message: '请选择充值金额', validator: FormValidator.validatorNumberNotNull },
  ],
  currentUserAccountId: [{ required: true, message: '请选择充值户号' }],
});
const formRef = ref<any>(null);
function handleSubmit() {
  if (!formRef.value) return;
  formRef.value.validate().then(({ valid, errors }: any) => {
    if (valid) {
      recharge();
    }
  });
}
const tips = [
  '平台提供慢充服务,订单提交后,燃气将于0 - 72 小时内到账,若未能按时到账,系统将自动发起退款。',
  '目前平台仅支持中国燃气和北京燃气充值服务。',
  '中国燃气充值户号必须在“壹品慧”APP燃气缴费界面查询到账户信息,户号为11开头或者5开头的10位数字。',
  '北京燃气不支持欠费充值,仅支持智能表的户号,户号是9开头11位的账户进行充值。',
  '充值期间,若同一账户的充值款未到账,请勿在其他平台重复充值,因上述操作导致的资金损失,由用户自行承担。',
  '如接到陌生来电,对方以缴费或误操作等理由要求处理款项,务必立即拉黑,谨防诈骗。',
  '下单时,请您务必准确填写完整的省市及户号信息。充值完成后,发票由运营商提供,您可登录网上营业厅下载对应的电子发票。',
  CustomerServiceTips,
];
const confirmDialogVisible = ref(false);
function recharge() {
  confirmDialogVisible.value = true;
}
async function goPay() {
  try {
    let params: LifeGasDataCreateLifePayOrderInput = {
      userId: blLifeRecharge.accountModel.userId,
      channelId: blLifeRecharge.accountModel.channlesNum,
      productData: {
        parValue: props.isDev ? 0.1 : form.parValue,
        gasOrgType: form.gasOrgType,
        gasAccount: form.gasAccount,
        province: form.areaList?.[0] ?? '',
        city: form.areaList?.[1] ?? '',
      },
    };
    let res = await blLifeRecharge.services.createLifePayGasOrder(params);
    emit('goPay', res.orderNo);
  } catch (error) {}
}
</script>
packages/components/src/views/GasBillRecharge/GasOrgTypeCard.vue
New file
@@ -0,0 +1,20 @@
<template>
  <div class="gasOrgType-card">
    <div class="gasOrgType-card-title">{{ title }}</div>
    <NutButton class="gasOrgType-card-button" type="primary"> 进入充值 </NutButton>
  </div>
</template>
<script setup lang="ts">
import { Button as NutButton } from '@nutui/nutui-taro';
defineOptions({
  name: 'GasOrgTypeCard',
});
type Props = {
  title?: string;
};
const props = withDefaults(defineProps<Props>(), {});
</script>
packages/components/src/views/GasBillRecharge/context.ts
New file
@@ -0,0 +1,29 @@
import type { InjectionKey, UnwrapNestedRefs, Ref } from 'vue';
import { inject } from 'vue';
import { UseStepperReturn } from 'senin-mini/hooks';
import { LifeRechargeConstants } from '@life-payment/core-vue';
type GasBillRechargeSteps = 'step1' | 'step2' | 'step3';
export interface GasBillRechargeContext
  extends UseStepperReturn<GasBillRechargeSteps, GasBillRechargeSteps[], GasBillRechargeSteps> {
  preSetForm: GasUserAccountExtraProperties;
}
export const GasBillRechargeContextKey: InjectionKey<GasBillRechargeContext> = Symbol(
  'GasBillRechargeContextKey'
);
export function useGasBillRechargeContext() {
  return inject(GasBillRechargeContextKey);
}
export type GasUserAccountExtraProperties = {
  // gasOrgType: LifeRechargeConstants.GasOrgCodeEnum;
  gasOrgType: string;
  // province: string;
  // city: string;
  gasAccount: string;
  remark: string;
  areaList: string[];
};
packages/components/src/views/Order/OrderApplyRefundView.vue
New file
@@ -0,0 +1,98 @@
<template>
  <NutForm
    :model-value="form"
    ref="formRef"
    :rules="rules"
    label-position="top"
    class="order-bill-recharge phone"
  >
    <NutFormItem class="bole-form-item" prop="refundApplyRemark" required>
      <NutTextarea
        placeholder="请输入退款原因"
        placeholderClass="bole-input-text-placeholder"
        autoSize
        class="bole-input-textarea"
        v-model="form.refundApplyRemark"
        :max-length="200"
        limit-show
      >
      </NutTextarea>
    </NutFormItem>
    <div class="common-content">
      <nut-button class="recharge-button" type="primary" @click="handleSubmit">
        <div class="recharge-button-inner">
          <div class="recharge-button-text">提交</div>
        </div>
      </nut-button>
    </div>
  </NutForm>
</template>
<script setup lang="ts">
import {
  Form as NutForm,
  FormItem as NutFormItem,
  Input as NutInput,
  Textarea as NutTextarea,
} from '@nutui/nutui-taro';
import { FormRules } from '@nutui/nutui-taro/dist/types/__VUE/form/types';
import { reactive, ref, computed } from 'vue';
import {
  useLifeRechargeContext,
  LifeRechargeConstants,
  RefundUserLifePayOrderInput,
} from '@life-payment/core-vue';
import { useQueryClient } from '@tanstack/vue-query';
defineOptions({
  name: 'OrderApplyRefundView',
});
type Props = {
  id: string;
};
const props = withDefaults(defineProps<Props>(), {});
const emit = defineEmits<{
  (e: 'submitApplyRefund'): void;
}>();
const form = reactive({
  refundApplyRemark: '',
});
const rules = reactive<FormRules>({
  refundApplyRemark: [{ required: true, message: '请输入退款原因' }],
});
const { blLifeRecharge } = useLifeRechargeContext();
const formRef = ref<any>(null);
function handleSubmit() {
  if (!formRef.value) return;
  formRef.value.validate().then(({ valid, errors }: any) => {
    if (valid) {
      refundUserLifePayOrder();
    }
  });
}
const queryClient = useQueryClient();
async function refundUserLifePayOrder() {
  try {
    let params: RefundUserLifePayOrderInput = {
      id: props.id,
      userId: blLifeRecharge.accountModel.userId,
      refundApplyRemark: form.refundApplyRemark,
    };
    let res = await blLifeRecharge.services.refundUserLifePayOrder(params);
    emit('submitApplyRefund');
    queryClient.invalidateQueries({
      queryKey: ['blLifeRecharge/getUserLifePayOrderPage'],
    });
  } catch (error) {}
}
</script>
packages/components/src/views/Order/OrderRefundResultView.vue
New file
@@ -0,0 +1,57 @@
<template>
  <LoadingLayout :loading="isLoading">
    <div class="recharge-result-view">
      <div class="recharge-result-view-title">{{ title }}</div>
      <div class="recharge-result-view-subtitle">订单号:{{ orderNo }}</div>
      <div class="recharge-result-view-remark">
        {{ detail.refundCheckRemark }},如有疑问请联系客服 {{ CustomerServicePhone }}(周一到周五
        9:00-17:30)
      </div>
      <div class="recharge-result-view-btn-wrapper">
        <div class="recharge-result-view-btn" @click="emit('goBackHome')">回首页</div>
      </div>
    </div>
  </LoadingLayout>
</template>
<script setup lang="ts">
import { LifeRechargeConstants, useLifeRechargeContext } from '@life-payment/core-vue';
import { CustomerServicePhone } from '../../constants';
import { useQuery } from '@tanstack/vue-query';
import { computed } from 'vue';
import LoadingLayout from '../../components//Layout/LoadingLayout.vue';
defineOptions({
  name: 'OrderRefundResultView',
});
type Props = {
  title?: string;
  orderNo?: string;
  lifePayOrderType?: LifeRechargeConstants.LifePayOrderTypeEnum;
};
const props = withDefaults(defineProps<Props>(), {
  title: '退款失败',
});
const emit = defineEmits<{
  (e: 'goBackHome'): void;
}>();
const { blLifeRecharge } = useLifeRechargeContext();
const { data: detail, isLoading } = useQuery({
  queryKey: ['blLifeRecharge/getUserLifePayOrderDetail', props.orderNo],
  queryFn: async () => {
    return await blLifeRecharge.services.getUserLifePayOrderDetail(
      { orderNo: props.orderNo },
      {
        showLoading: false,
      }
    );
  },
  enabled: computed(() => !!props.orderNo),
});
</script>
packages/components/src/views/Order/components/ElectricOrder.vue
@@ -6,8 +6,11 @@
    <template #renderItem="{ item }">
      <OrderCard
        title="电费充值"
        :status="orderStatusEnum(item?.payStatus, item?.lifePayOrderStatus)"
        :status="convertOrderFrontStatus(item?.payStatus, item?.lifePayOrderStatus)"
        :order-no="item?.orderNo"
        :id="item?.id"
        @goApplyRefund="emit('goApplyRefund', $event)"
        @goRefundDetail="emit('goRefundDetail', $event)"
      >
        <OrderCardItem
          label="充值地区:"
@@ -63,7 +66,7 @@
import { useGetUserLifePayOrderPage } from '../../../hooks';
import { BlLifeRecharge } from '@life-payment/core-vue';
import dayjs from 'dayjs';
import { toThousand, orderStatusEnum } from '../../../utils';
import { toThousand, convertOrderFrontStatus } from '../../../utils';
defineOptions({
  name: 'ElectricOrder',
@@ -73,6 +76,11 @@
// const props = withDefaults(defineProps<Props>(), {});
const emit = defineEmits<{
  (e: 'goApplyRefund', id: string): void;
  (e: 'goRefundDetail', orderNo: string): void;
}>();
const { infiniteLoadingProps } = useGetUserLifePayOrderPage({
  lifePayOrderType: BlLifeRecharge.constants.LifePayOrderTypeEnum.电费订单,
});
packages/components/src/views/Order/components/GasOrder.vue
New file
@@ -0,0 +1,79 @@
<template>
  <InfiniteLoading
    scrollViewClassName="life-page-infinite-scroll-list"
    v-bind="infiniteLoadingProps"
  >
    <template #renderItem="{ item }">
      <OrderCard
        title="燃气充值"
        :status="convertOrderFrontStatus(item?.payStatus, item?.lifePayOrderStatus)"
        :order-no="item?.orderNo"
        :id="item?.id"
        @goApplyRefund="emit('goApplyRefund', $event)"
        @goRefundDetail="emit('goRefundDetail', $event)"
      >
        <OrderCardItem
          label="充值账号:"
          :value="JSON.parse(item?.orderParamDetailJsonStr)?.gasAccount"
        />
        <OrderCardItem
          label="下单时间:"
          :value="item?.creationTime && dayjs(item?.creationTime).format('YYYY-MM-DD HH:mm:ss')"
        />
        <template v-if="item.payStatus !== BlLifeRecharge.constants.LifePayStatusEnum.已退款">
          <OrderCardItem
            label="充值金额:"
            :value="`¥${toThousand(item?.rechargeAmount)}`"
            danger
          />
          <OrderCardItem label="优惠金额:" :value="`¥${toThousand(item?.discountAmount)}`" />
        </template>
        <OrderCardItem label="实付金额:" :value="`¥${toThousand(item?.payAmount)}`" danger />
        <OrderCardItem
          label="支付时间:"
          :value="item?.payTime && dayjs(item?.payTime).format('YYYY-MM-DD HH:mm:ss')"
        />
        <OrderCardItem
          v-if="item.payStatus !== BlLifeRecharge.constants.LifePayStatusEnum.已退款"
          label="完成时间:"
          :value="item?.finishTime && dayjs(item?.finishTime).format('YYYY-MM-DD HH:mm:ss')"
        />
        <template v-else>
          <OrderCardItem label="退款金额:" :value="`¥${toThousand(item?.payAmount)}`" danger />
          <OrderCardItem
            label="退款时间:"
            :value="item?.refundTime && dayjs(item?.refundTime).format('YYYY-MM-DD HH:mm:ss')"
          >
          </OrderCardItem>
        </template>
      </OrderCard>
    </template>
  </InfiniteLoading>
</template>
<script setup lang="ts">
import InfiniteLoading from '../../../components/InfiniteLoading/InfiniteLoading.vue';
import OrderCard from '../../../components/Card/OrderCard.vue';
import OrderCardItem from '../../../components/Card/OrderCardItem.vue';
import { useGetUserLifePayOrderPage } from '../../../hooks';
import dayjs from 'dayjs';
import { BlLifeRecharge } from '@life-payment/core-vue';
import { toThousand, convertOrderFrontStatus } from '../../../utils';
defineOptions({
  name: 'GasOrder',
});
// type Props = {};
// const props = withDefaults(defineProps<Props>(), {});
const emit = defineEmits<{
  (e: 'goApplyRefund', id: string): void;
  (e: 'goRefundDetail', orderNo: string): void;
}>();
const { infiniteLoadingProps } = useGetUserLifePayOrderPage({
  lifePayOrderType: BlLifeRecharge.constants.LifePayOrderTypeEnum.燃气订单,
});
</script>
packages/components/src/views/Order/components/PhoneOrder.vue
@@ -6,8 +6,11 @@
    <template #renderItem="{ item }">
      <OrderCard
        title="话费充值"
        :status="orderStatusEnum(item?.payStatus, item?.lifePayOrderStatus)"
        :status="convertOrderFrontStatus(item?.payStatus, item?.lifePayOrderStatus)"
        :order-no="item?.orderNo"
        :id="item?.id"
        @goApplyRefund="emit('goApplyRefund', $event)"
        @goRefundDetail="emit('goRefundDetail', $event)"
      >
        <OrderCardItem
          label="充值账号:"
@@ -55,7 +58,7 @@
import { useGetUserLifePayOrderPage } from '../../../hooks';
import dayjs from 'dayjs';
import { BlLifeRecharge } from '@life-payment/core-vue';
import { toThousand, orderStatusEnum } from '../../../utils';
import { toThousand, convertOrderFrontStatus } from '../../../utils';
defineOptions({
  name: 'PhoneOrder',
@@ -65,6 +68,11 @@
// const props = withDefaults(defineProps<Props>(), {});
const emit = defineEmits<{
  (e: 'goApplyRefund', id: string): void;
  (e: 'goRefundDetail', orderNo: string): void;
}>();
const { infiniteLoadingProps } = useGetUserLifePayOrderPage({
  lifePayOrderType: BlLifeRecharge.constants.LifePayOrderTypeEnum.话费订单,
});
packages/components/src/views/PhoneBillRecharge/PhoneBillRecharge.vue
@@ -1,111 +1,18 @@
<template>
  <NutForm
    :model-value="form"
    ref="formRef"
    :rules="rules"
    label-position="top"
    class="order-bill-recharge phone"
  >
    <NutFormItem label="选择运营商:" class="bole-form-item" prop="ispCode" required>
      <NutRadioGroup v-model="form.ispCode" direction="horizontal" @change="changeIspCode">
        <BlRadio
          :label="key"
          v-for="(val, key) in BlLifeRecharge.constants.IspCodeText"
          :key="key"
          >{{ val }}</BlRadio
        >
      </NutRadioGroup>
    </NutFormItem>
    <NutFormItem label="充值手机号" class="bole-form-item" prop="phone" required>
      <NutInput
        v-model.trim="form.phone"
        class="bole-input-text"
        placeholder="请填写您需要充值的手机号码"
        type="text"
      />
    </NutFormItem>
    <NutFormItem
      label="姓名"
      class="bole-form-item"
      prop="name"
      required
      v-if="form.ispCode === BlLifeRecharge.constants.IspCode.dianxin"
    >
      <NutInput
        v-model.trim="form.name"
        class="bole-input-text"
        placeholder="请填写您的姓名"
        type="text"
      />
    </NutFormItem>
    <NutFormItem label="选择充值金额" class="bole-form-item" prop="parValue" required>
      <NutRadioGroup v-model="form.parValue" direction="horizontal" class="parValue-radio-group">
        <NutRadio
          :label="Number(item)"
          :key="item"
          shape="button"
          v-for="item in parValueList"
          class="parValue-item"
        >
          <div class="parValue-item-inner">
            <div class="amount-wrapper">
              <div class="amount">{{ item }}</div>
              <div class="unit">元</div>
            </div>
            <div class="price-wrapper">
              <div class="price-text">折后</div>
              <div class="price">
                {{ blLifeRecharge.getRechargeParValue(item, lifePayPhoneRate) }}元
              </div>
            </div>
            <div class="discountTag">{{ lifePayPhoneRate * 100 }}折</div>
          </div>
        </NutRadio>
      </NutRadioGroup>
    </NutFormItem>
    <div class="common-content">
      <nut-button class="recharge-button" type="primary" @click="handleSubmit">
        <div class="recharge-button-inner">
          <div>¥{{ realParValue }}</div>
          <div class="recharge-button-text">立即充值</div>
        </div>
      </nut-button>
      <RechargeTipsView :tips="tips" />
    </div>
    <ConfirmDialog v-model:visible="confirmDialogVisible" @ok="goPay">
      <template #info>
        <ConfirmDialogInfoItem label="充值账号" :content="form.phone" />
        <ConfirmDialogInfoItem label="充值金额" :content="`¥${form.parValue.toFixed(2)}`" danger />
        <ConfirmDialogInfoItem label="优惠金额" :content="`¥${discountParValue.toFixed(2)}`" />
        <ConfirmDialogInfoItem label="实付金额" :content="`¥${realParValue}`" danger />
      </template>
    </ConfirmDialog>
  </NutForm>
  <PhoneBillRechargeStep1 v-if="current === 'step1'" />
  <PhoneBillRechargeStep2
    v-else-if="current === 'step2'"
    v-bind="props"
    @go-pay="emit('goPay', $event)"
  />
</template>
<script setup lang="ts">
import {
  Form as NutForm,
  FormItem as NutFormItem,
  RadioGroup as NutRadioGroup,
  Radio as NutRadio,
  Input as NutInput,
  Button as NutButton,
} from '@nutui/nutui-taro';
import { FormRules } from '@nutui/nutui-taro/dist/types/__VUE/form/types';
import { reactive, ref, computed } from 'vue';
import BlRadio from '../../components/Radio/Radio.vue';
import { FormValidator } from '../../utils';
import {
  useLifeRechargeContext,
  BlLifeRecharge,
  LifePhoneDataCreateLifePayOrderInput,
  LifeRechargeConstants,
} from '@life-payment/core-vue';
import RechargeTipsView from '../../components/RechargeTipsView/RechargeTipsView.vue';
import ConfirmDialog from '../../components/Dialog/ConfirmDialog.vue';
import ConfirmDialogInfoItem from '../../components/Dialog/ConfirmDialogInfoItem.vue';
import { useGetRate, useGetPhoneParValue } from '../../hooks';
import { computed, provide } from 'vue';
import { useStepper } from 'senin-mini/hooks';
import { PhoneBillRechargeContextKey } from './context';
import PhoneBillRechargeStep1 from './PhoneBillRechargeStep1.vue';
import PhoneBillRechargeStep2 from './PhoneBillRechargeStep2.vue';
defineOptions({
  name: 'PhoneBillRecharge',
@@ -119,88 +26,14 @@
  isDev: false,
});
const form = reactive({
  ispCode: '',
  phone: '',
  parValue: 0,
  name: '',
});
const stepperInfo = useStepper(['step1', 'step2'], 'step2');
const current = computed(() => stepperInfo.current.value);
const emit = defineEmits<{
  (e: 'goPay', orderNo: string): void;
}>();
const { lifePayPhoneRate } = useGetRate();
const { phoneParValueList } = useGetPhoneParValue();
const parValueList = computed(
  () => phoneParValueList.value.find((x) => x.ispCode === form.ispCode)?.parValue ?? []
);
function changeIspCode(val: LifeRechargeConstants.IspCode) {
  const phoneParValueItem = phoneParValueList.value.find((x) => x.ispCode === val);
  if (phoneParValueItem.parValue.every((x) => Number(x) !== form.parValue)) {
    form.parValue = 0;
  }
}
const realParValue = computed(() =>
  blLifeRecharge.getRechargeParValue(form.parValue, lifePayPhoneRate.value)
);
const discountParValue = computed(() => form.parValue - Number(realParValue.value));
const { blLifeRecharge } = useLifeRechargeContext();
const rules = reactive<FormRules>({
  ispCode: [{ required: true, message: '请选择运营商' }],
  phone: [
    { required: true, message: '请输入充值手机号' },
    { validator: FormValidator.validatorPhoneNumber, message: '请输入正确的手机号' },
  ],
  name: [{ required: true, message: '请输入姓名' }],
  parValue: [
    { required: true, message: '请选择充值金额', validator: FormValidator.validatorNumberNotNull },
  ],
provide(PhoneBillRechargeContextKey, {
  ...stepperInfo,
});
const formRef = ref<any>(null);
function handleSubmit() {
  if (!formRef.value) return;
  formRef.value.validate().then(({ valid, errors }: any) => {
    if (valid) {
      recharge();
    }
  });
}
const tips = [
  '平台提供慢充服务,订单提交后,话费将于0 - 24小时内到账。若未能按时到账,系统将自动发起退款。',
  '充值期间,若同一号码款项未到账,请勿在其他平台重复充值;主副卡不可同时充值。因上述操作导致的资金损失,由用户自行承担。',
  '本平台话费充值服务不适用于已停机号码。电信号码若有欠费,也无法完成充值。电信已完成维护的区域包括:广东、江苏、湖北、四川、江西、河北、河南、福建、辽宁。其它区域正在分批次进行维护中,在此期间可能会出现充值不成功并自动退款的情况,请您谅解。',
  '如接到陌生来电,对方以缴费或误操作等理由要求处理款项,务必立即拉黑,谨防诈骗。',
  '充值发票由运营商提供,您可登录网上营业厅下载电子发票。',
];
const confirmDialogVisible = ref(false);
function recharge() {
  confirmDialogVisible.value = true;
}
async function goPay() {
  try {
    let params: LifePhoneDataCreateLifePayOrderInput = {
      userId: blLifeRecharge.accountModel.userId,
      productData: {
        ispCode: form.ispCode,
        parValue: props.isDev ? 0.1 : form.parValue,
        phone: form.phone,
        name: form.ispCode === BlLifeRecharge.constants.IspCode.dianxin ? form.name : '',
      },
    };
    let res = await blLifeRecharge.services.createLifePayPhoneOrder(params);
    emit('goPay', res.orderNo);
  } catch (error) {}
}
</script>
packages/components/src/views/PhoneBillRecharge/PhoneBillRechargeBaseForm.vue
New file
@@ -0,0 +1,97 @@
<template>
  <NutForm
    :model-value="form"
    ref="formRef"
    :rules="rules"
    label-position="top"
    class="order-bill-recharge phone"
  >
    <NutFormItem label="选择运营商:" class="bole-form-item" prop="ispCode" required>
      <NutRadioGroup v-model="form.ispCode" direction="horizontal" @change="handleIspCodeChange">
        <BlRadio
          :label="key"
          v-for="(val, key) in BlLifeRecharge.constants.IspCodeText"
          :key="key"
          >{{ val }}</BlRadio
        >
      </NutRadioGroup>
    </NutFormItem>
    <NutFormItem label="充值手机号" class="bole-form-item" prop="phone" required>
      <NutInput
        v-model.trim="form.phone"
        class="bole-input-text"
        placeholder="请填写您需要充值的手机号码"
        type="text"
      />
    </NutFormItem>
    <NutFormItem
      label="姓名"
      class="bole-form-item"
      prop="name"
      required
      v-if="form.ispCode === BlLifeRecharge.constants.IspCode.dianxin"
    >
      <NutInput
        v-model.trim="form.name"
        class="bole-input-text"
        placeholder="请填写您的姓名"
        type="text"
      />
    </NutFormItem>
    <slot></slot>
    <NutDialog
      title="提示"
      content="电信可充值区域包括:广东、江苏、湖北、四川、江西、河北、河南、福建、辽宁。其它区域正在分批次进行维护中,在此期间可能会出现充值不成功并自动退款的情况,请您谅解。"
      v-model:visible="dialogVisible"
    />
  </NutForm>
</template>
<script setup lang="ts">
import {
  Form as NutForm,
  FormItem as NutFormItem,
  RadioGroup as NutRadioGroup,
  Input as NutInput,
  Dialog as NutDialog,
} from '@nutui/nutui-taro';
import { FormRules } from '@nutui/nutui-taro/dist/types/__VUE/form/types';
import { reactive, ref, computed } from 'vue';
import BlRadio from '../../components/Radio/Radio.vue';
import { FormValidator } from '../../utils';
import { BlLifeRecharge, LifeRechargeConstants } from '@life-payment/core-vue';
defineOptions({
  name: 'PhoneBillRechargeBaseForm',
});
const form = defineModel<{
  ispCode: string;
  phone: string;
  name: string;
}>('form');
const rules = reactive<FormRules>({
  ispCode: [{ required: true, message: '请选择运营商' }],
  phone: [
    { required: true, message: '请输入充值手机号' },
    { validator: FormValidator.validatorPhoneNumber, message: '请输入正确的手机号' },
  ],
  name: [{ required: true, message: '请输入姓名' }],
});
const dialogVisible = ref(false);
function handleIspCodeChange(ispCode: LifeRechargeConstants.IspCode) {
  console.log('ispCode: ', ispCode);
  if (ispCode === LifeRechargeConstants.IspCode.dianxin) {
    dialogVisible.value = true;
  }
}
const formRef = ref<any>(null);
defineExpose({
  validate: computed(() => formRef.value.validate),
});
</script>
packages/components/src/views/PhoneBillRecharge/PhoneBillRechargeStep1.vue
New file
@@ -0,0 +1,88 @@
<template>
  <PhoneBillRechargeBaseForm ref="formRef" v-model:form="form">
    <NutFormItem label="备注信息" class="bole-form-item" prop="remark">
      <NutTextarea
        placeholder="请输入备注信息"
        placeholderClass="bole-input-text-placeholder"
        autoSize
        class="bole-input-textarea"
        v-model="form.remark"
        :max-length="30"
        limit-show
      >
      </NutTextarea>
    </NutFormItem>
    <div class="common-content">
      <nut-button class="recharge-button" type="primary" @click="handleNext">
        <div class="recharge-button-inner">
          <div class="recharge-button-text">保存</div>
        </div>
      </nut-button>
      <nut-button class="recharge-button" type="primary" plain @click="goToNext">
        <div class="recharge-button-inner">
          <div class="recharge-button-text">返回</div>
        </div>
      </nut-button>
    </div>
  </PhoneBillRechargeBaseForm>
</template>
<script setup lang="ts">
import {
  Button as NutButton,
  FormItem as NutFormItem,
  Textarea as NutTextarea,
} from '@nutui/nutui-taro';
import { reactive, ref, computed, provide } from 'vue';
import PhoneBillRechargeBaseForm from './PhoneBillRechargeBaseForm.vue';
import { usePhoneBillRechargeContext } from './context';
import {
  useLifeRechargeContext,
  LifeRechargeConstants,
  AddUpdateUserAccountInput,
} from '@life-payment/core-vue';
import { useAddUpdateUserAccount } from '../../hooks';
defineOptions({
  name: 'PhoneBillRechargeStep1',
});
const { blLifeRecharge } = useLifeRechargeContext();
const form = reactive({
  ispCode: blLifeRecharge.getCarrierByPhoneNumber(blLifeRecharge.accountModel.phoneNumber),
  phone: blLifeRecharge.accountModel.phoneNumber,
  name: '',
  remark: '',
});
const { goToNext } = usePhoneBillRechargeContext();
const formRef = ref<any>(null);
function handleNext() {
  if (!formRef.value) return;
  formRef.value.validate().then(({ valid, errors }: any) => {
    if (valid) {
      handleAddUpdateUserAccount();
    }
  });
}
const { addUpdateUserAccount } = useAddUpdateUserAccount();
async function handleAddUpdateUserAccount() {
  try {
    let params: AddUpdateUserAccountInput = {
      userId: blLifeRecharge.accountModel.userId,
      operators: form.ispCode,
      lifePayType: LifeRechargeConstants.LifePayOrderTypeEnum.话费订单,
      content: form.phone,
      extraProperties: JSON.stringify(form),
      remark: form.remark,
    };
    await addUpdateUserAccount(params);
    goToNext();
  } catch (error) {}
}
</script>
packages/components/src/views/PhoneBillRecharge/PhoneBillRechargeStep2.vue
New file
@@ -0,0 +1,230 @@
<template>
  <NutForm
    :model-value="form"
    ref="formRef"
    :rules="rules"
    label-position="top"
    class="order-bill-recharge phone"
  >
    <NutFormItem class="bole-form-item" prop="currentUserAccountId">
      <NutRadioGroup
        v-model="form.currentUserAccountId"
        direction="horizontal"
        class="par-account-list"
        v-if="userAccountAllList.length > 0"
        @change="handleUserAccountChange"
      >
        <NutRadio
          :label="item.id"
          shape="button"
          v-for="item in userAccountAllList"
          :key="item.id"
          >{{ item.content }}</NutRadio
        >
      </NutRadioGroup>
      <AccountCard
        v-if="userAccountAllList.length > 0"
        title="充值手机号"
        :content="form.phone"
        :remark="form.remark"
      >
        <template #action>
          <div class="account-card-action" @click="handleAddUserAccount">新增</div>
        </template>
      </AccountCard>
      <AccountAddCard v-else @click="handleAddUserAccount" />
    </NutFormItem>
    <NutFormItem label="选择充值金额" class="bole-form-item" prop="parValue" required>
      <NutRadioGroup v-model="form.parValue" direction="horizontal" class="parValue-radio-group">
        <NutRadio
          :label="Number(item)"
          :key="item"
          shape="button"
          v-for="item in parValueList"
          class="parValue-item"
        >
          <div class="parValue-item-inner">
            <div class="amount-wrapper">
              <div class="amount">{{ item }}</div>
              <div class="unit">元</div>
            </div>
            <div class="price-wrapper">
              <div class="price-text">折后</div>
              <div class="price">
                {{ blLifeRecharge.getRechargeParValue(item, lifePayPhoneRate) }}元
              </div>
            </div>
            <div class="discountTag">{{ lifePayPhoneRate }}折</div>
          </div>
        </NutRadio>
      </NutRadioGroup>
    </NutFormItem>
    <div class="common-content">
      <nut-button class="recharge-button" type="primary" @click="handleSubmit">
        <div class="recharge-button-inner">
          <div>¥{{ realParValue }}</div>
          <div class="recharge-button-text">立即充值</div>
        </div>
      </nut-button>
      <RechargeTipsView :tips="tips" />
    </div>
    <ConfirmDialog v-model:visible="confirmDialogVisible" @ok="goPay">
      <template #info>
        <ConfirmDialogInfoItem label="充值账号" :content="form.phone" />
        <ConfirmDialogInfoItem label="充值金额" :content="`¥${form.parValue.toFixed(2)}`" danger />
        <ConfirmDialogInfoItem label="优惠金额" :content="`¥${discountParValue.toFixed(2)}`" />
        <ConfirmDialogInfoItem label="实付金额" :content="`¥${realParValue}`" danger />
      </template>
    </ConfirmDialog>
  </NutForm>
</template>
<script setup lang="ts">
import {
  Form as NutForm,
  FormItem as NutFormItem,
  RadioGroup as NutRadioGroup,
  Radio as NutRadio,
  Input as NutInput,
  Button as NutButton,
} from '@nutui/nutui-taro';
import { FormRules } from '@nutui/nutui-taro/dist/types/__VUE/form/types';
import { reactive, ref, computed, provide } from 'vue';
import { FormValidator } from '../../utils';
import {
  useLifeRechargeContext,
  BlLifeRecharge,
  LifePhoneDataCreateLifePayOrderInput,
  LifeRechargeConstants,
} from '@life-payment/core-vue';
import RechargeTipsView from '../../components/RechargeTipsView/RechargeTipsView.vue';
import ConfirmDialog from '../../components/Dialog/ConfirmDialog.vue';
import ConfirmDialogInfoItem from '../../components/Dialog/ConfirmDialogInfoItem.vue';
import { useGetRate, useGetPhoneParValue, useSetUserAccountBySelect } from '../../hooks';
import { CustomerServiceTips } from '../../constants';
import AccountAddCard from '../../components/Card/AccountAddCard.vue';
import AccountCard from '../../components/Card/AccountCard.vue';
import { usePhoneBillRechargeContext, PhoneUserAccountExtraProperties } from './context';
defineOptions({
  name: 'PhoneBillRechargeStep2',
});
type Props = {
  isDev?: boolean;
};
const props = withDefaults(defineProps<Props>(), {
  isDev: false,
});
const { goTo } = usePhoneBillRechargeContext();
const form = reactive({
  ispCode: '',
  phone: '',
  parValue: 0,
  name: '',
  currentUserAccountId: '',
  remark: '',
});
const { userAccountAllList, handleUserAccountChange } = useSetUserAccountBySelect({
  lifePayOrderType: LifeRechargeConstants.LifePayOrderTypeEnum.话费订单,
  onSetUserAccount(currentUserAccount) {
    const currentUserAccountExtraProperties = JSON.parse(
      currentUserAccount.extraProperties
    ) as PhoneUserAccountExtraProperties;
    form.currentUserAccountId = currentUserAccount.id;
    form.phone = currentUserAccount.content;
    form.ispCode = currentUserAccountExtraProperties.ispCode;
    form.name = currentUserAccountExtraProperties.name;
    form.remark = currentUserAccount.remark;
    changeIspCode(form.ispCode as any);
  },
});
function handleAddUserAccount() {
  goTo('step1');
}
const emit = defineEmits<{
  (e: 'goPay', orderNo: string): void;
}>();
const { lifePayPhoneRate } = useGetRate();
const { phoneParValueList } = useGetPhoneParValue();
const parValueList = computed(() => {
  const _parValueList =
    phoneParValueList.value.find((x) => x.ispCode === form.ispCode)?.parValue ?? [];
  return blLifeRecharge.filterParValueList(_parValueList);
});
function changeIspCode(val: LifeRechargeConstants.IspCode) {
  const phoneParValueItem = phoneParValueList.value.find((x) => x.ispCode === val);
  if (phoneParValueItem && phoneParValueItem.parValue.every((x) => Number(x) !== form.parValue)) {
    form.parValue = 0;
  }
}
const realParValue = computed(() =>
  blLifeRecharge.getRechargeParValue(form.parValue, lifePayPhoneRate.value)
);
const discountParValue = computed(() => form.parValue - Number(realParValue.value));
const { blLifeRecharge } = useLifeRechargeContext();
const rules = reactive<FormRules>({
  parValue: [
    { required: true, message: '请选择充值金额', validator: FormValidator.validatorNumberNotNull },
  ],
  currentUserAccountId: [{ required: true, message: '请选择充值手机号' }],
});
const formRef = ref<any>(null);
function handleSubmit() {
  if (!formRef.value) return;
  formRef.value.validate().then(({ valid, errors }: any) => {
    if (valid) {
      recharge();
    }
  });
}
const tips = [
  '平台提供慢充服务,订单提交后,话费将于0 - 24小时内到账。若未能按时到账,系统将自动发起退款。',
  '充值期间,若同一号码款项未到账,请勿在其他平台重复充值;主副卡不可同时充值。因上述操作导致的资金损失,由用户自行承担。',
  '本平台话费充值服务不适用于已停机号码。电信号码若有欠费,也无法完成充值。电信已完成维护的区域包括:广东、江苏、湖北、四川、江西、河北、河南、福建、辽宁。其它区域正在分批次进行维护中,在此期间可能会出现充值不成功并自动退款的情况,请您谅解。',
  '如接到陌生来电,对方以缴费或误操作等理由要求处理款项,务必立即拉黑,谨防诈骗。',
  '充值发票由运营商提供,您可登录网上营业厅下载电子发票。',
  CustomerServiceTips,
];
const confirmDialogVisible = ref(false);
function recharge() {
  confirmDialogVisible.value = true;
}
async function goPay() {
  try {
    let params: LifePhoneDataCreateLifePayOrderInput = {
      userId: blLifeRecharge.accountModel.userId,
      channelId: blLifeRecharge.accountModel.channlesNum,
      productData: {
        ispCode: form.ispCode,
        parValue: props.isDev ? 0.1 : form.parValue,
        phone: form.phone,
        name: form.ispCode === BlLifeRecharge.constants.IspCode.dianxin ? form.name : '',
      },
    };
    let res = await blLifeRecharge.services.createLifePayPhoneOrder(params);
    emit('goPay', res.orderNo);
  } catch (error) {}
}
</script>
packages/components/src/views/PhoneBillRecharge/context.ts
New file
@@ -0,0 +1,34 @@
import type { InjectionKey, UnwrapNestedRefs, Ref } from 'vue';
import { inject } from 'vue';
import { UseStepperReturn } from 'senin-mini/hooks';
type PhoneBillRechargeSteps = 'step1' | 'step2';
export interface PhoneBillRechargeContext
  extends UseStepperReturn<
    PhoneBillRechargeSteps,
    PhoneBillRechargeSteps[],
    PhoneBillRechargeSteps
  > {
  //   form: UnwrapNestedRefs<{
  //     ispCode: string;
  //     phone: string;
  //     parValue: number;
  //     name: string;
  //   }>;
}
export const PhoneBillRechargeContextKey: InjectionKey<PhoneBillRechargeContext> = Symbol(
  'PhoneBillRechargeContextKey'
);
export function usePhoneBillRechargeContext() {
  return inject(PhoneBillRechargeContextKey);
}
export type PhoneUserAccountExtraProperties = {
  ispCode: string;
  phone: string;
  name: string;
  remark: string;
};
packages/components/src/views/RechargeResultView/RechargeResultView.vue
@@ -1,12 +1,16 @@
<template>
  <div class="recharge-result-view">
    <div class="recharge-result-view-title">{{ title }}</div>
    <div class="recharge-result-view-subtitle">订单号:{{ orderNo }}</div>
    <div class="recharge-result-view-tips">
      同一号码充值期间,未到账前切勿在其他任何平台再次充值。因此造成的资金损失须用户自行承担!!!
      <slot name="tips">
        同一号码充值期间,未到账前切勿在其他任何平台再次充值。因此造成的资金损失须用户自行承担!!!
      </slot>
    </div>
    <div class="recharge-result-view-warning">
      如接到陌生来电,对方以缴费或误操作等理由要求处理款项,务必立即拉黑,谨防诈骗!!!
    </div>
    <div class="recharge-result-view-customerService">{{ CustomerServiceTips }}</div>
    <div class="recharge-result-view-btn-wrapper">
      <div class="recharge-result-view-btn" @click="emit('goBackHome')">回首页</div>
    </div>
@@ -15,6 +19,7 @@
<script setup lang="ts">
import { LifeRechargeConstants } from '@life-payment/core-vue';
import { CustomerServiceTips } from '../../constants';
defineOptions({
  name: 'RechargeResultView',
packages/components/src/views/electricBillRecharge/ElectricBillRechargeBaseForm.vue
New file
@@ -0,0 +1,128 @@
<template>
  <NutForm
    :model-value="form"
    ref="formRef"
    :rules="rules"
    label-position="top"
    class="order-bill-recharge electric"
  >
    <NutFormItem label="所在区域" class="bole-form-item" prop="province" required>
      <ChooseInputWithPicker
        v-model="form.province"
        placeholder="请选择区域"
        :value-enum="electricParValueList"
        enum-label-key="cityName"
        enum-value-key="cityName"
      />
    </NutFormItem>
    <NutFormItem label="所在城市" class="bole-form-item" prop="city" required v-if="form.province">
      <ChooseInputWithPicker
        v-model="form.city"
        placeholder="请选择城市"
        :value-enum="electricCityList"
        enum-label-key="cityName"
        enum-value-key="cityName"
      />
    </NutFormItem>
    <!-- <NutFormItem label="电网类型" class="bole-form-item" prop="electricType" required>
      <ChooseInputWithPicker
        v-model="form.electricType"
        placeholder="请选择电网类型"
        :value-enum="blLifeRecharge.constants.ElectricTypeText"
      />
    </NutFormItem> -->
    <NutFormItem label="电费类型" class="bole-form-item" prop="electricAccountType" required>
      <ChooseInputWithPicker
        v-model="form.electricAccountType"
        placeholder="请选择电费类型"
        :value-enum="blLifeRecharge.constants.ElectricAccountTypeText"
      />
    </NutFormItem>
    <NutFormItem label="电网户号" class="bole-form-item" prop="electricAccount" required>
      <NumberInput
        v-model.trim="form.electricAccount"
        class="bole-input-text"
        placeholder="请输入13位数字编号"
        max-length="13"
      />
    </NutFormItem>
    <NutFormItem
      v-if="form.electricType === blLifeRecharge.constants.ElectricType.nanwang"
      label="身份证后六位"
      class="bole-form-item"
      prop="sixID"
      required
    >
      <NutInput
        v-model.trim="form.sixID"
        class="bole-input-text"
        placeholder="请输入身份证后六位"
        type="text"
        max-length="6"
      />
    </NutFormItem>
    <slot />
  </NutForm>
</template>
<script setup lang="ts">
import { Form as NutForm, FormItem as NutFormItem, Input as NutInput } from '@nutui/nutui-taro';
import { FormRules } from '@nutui/nutui-taro/dist/types/__VUE/form/types';
import { reactive, ref, computed, watch } from 'vue';
import { useLifeRechargeContext } from '@life-payment/core-vue';
import ChooseInputWithPicker from '../../components/Input/ChooseInputWithPicker.vue';
import NumberInput from '../../components/Input/NumberInput.vue';
import { useGetElectricParValue } from '../../hooks';
import { FormValidator } from '../../utils';
defineOptions({
  name: 'ElectricBillRechargeBaseForm',
});
const form = defineModel<{
  electricAccount: string;
  electricType: string;
  electricAccountType: string;
  province: string;
  city: string;
  sixID: string;
}>('form');
const { electricParValueList } = useGetElectricParValue();
const electricCityList = computed(
  () =>
    electricParValueList.value.find((x) => x.cityName === form.value.province)?.childCityList ?? []
);
watch(
  () => form.value.province,
  (provinceName) => {
    const electricParValue = electricParValueList.value.find(
      (item) => item.cityName === provinceName
    );
    form.value.electricType = electricParValue.electricType;
  }
);
const { blLifeRecharge } = useLifeRechargeContext();
const rules = reactive<FormRules>({
  province: [{ required: true, message: '请选择所在区域' }],
  city: [{ required: true, message: '请选择所在城市' }],
  electricAccountType: [{ required: true, message: '请选择电费类型' }],
  electricAccount: [{ required: true, message: '请输入电网户号', regex: /^\d{13}$/ }],
  sixID: [
    {
      required: true,
      message: '请输入身份证后六位',
      validator: FormValidator.validatorIDNumberSix,
    },
  ],
});
const formRef = ref<any>(null);
defineExpose({
  validate: computed(() => formRef.value.validate),
});
</script>
packages/components/src/views/electricBillRecharge/ElectricBillRechargeStep1.vue
New file
@@ -0,0 +1,93 @@
<template>
  <ElectricBillRechargeBaseForm ref="formRef" v-model:form="form">
    <NutFormItem label="备注信息" class="bole-form-item" prop="remark">
      <NutTextarea
        placeholder="请输入备注信息"
        placeholderClass="bole-input-text-placeholder"
        autoSize
        class="bole-input-textarea"
        v-model="form.remark"
        :max-length="30"
        limit-show
      >
      </NutTextarea>
    </NutFormItem>
    <div class="common-content">
      <nut-button class="recharge-button" type="primary" @click="handleNext">
        <div class="recharge-button-inner">
          <div class="recharge-button-text">保存</div>
        </div>
      </nut-button>
      <nut-button class="recharge-button" type="primary" plain @click="goToNext">
        <div class="recharge-button-inner">
          <div class="recharge-button-text">返回</div>
        </div>
      </nut-button>
    </div>
  </ElectricBillRechargeBaseForm>
</template>
<script setup lang="ts">
import {
  Button as NutButton,
  FormItem as NutFormItem,
  Input as NutInput,
  Textarea as NutTextarea,
} from '@nutui/nutui-taro';
import { reactive, ref } from 'vue';
import { useElectricBillRechargeContext } from './context';
import ElectricBillRechargeBaseForm from './ElectricBillRechargeBaseForm.vue';
import {
  useLifeRechargeContext,
  LifeRechargeConstants,
  AddUpdateUserAccountInput,
} from '@life-payment/core-vue';
import { useAddUpdateUserAccount } from '../../hooks';
defineOptions({
  name: 'ElectricBillRechargeStep1',
});
const form = reactive({
  electricAccount: '',
  electricType: '',
  electricAccountType: '',
  province: '',
  city: '',
  sixID: '',
  remark: '',
});
const { goToNext } = useElectricBillRechargeContext();
const formRef = ref<any>(null);
function handleNext() {
  if (!formRef.value) return;
  formRef.value.validate().then(({ valid, errors }: any) => {
    if (valid) {
      handleAddUpdateUserAccount();
    }
  });
}
const { addUpdateUserAccount } = useAddUpdateUserAccount();
const { blLifeRecharge } = useLifeRechargeContext();
async function handleAddUpdateUserAccount() {
  try {
    let params: AddUpdateUserAccountInput = {
      userId: blLifeRecharge.accountModel.userId,
      lifePayType: LifeRechargeConstants.LifePayOrderTypeEnum.电费订单,
      operators: form.electricType,
      content: form.electricAccount,
      province: form.province,
      city: form.city,
      extraProperties: JSON.stringify(form),
      remark: form.remark,
    };
    await addUpdateUserAccount(params);
    goToNext();
  } catch (error) {}
}
</script>
packages/components/src/views/electricBillRecharge/ElectricBillRechargeStep2.vue
New file
@@ -0,0 +1,250 @@
<template>
  <NutForm
    :model-value="form"
    ref="formRef"
    :rules="rules"
    label-position="top"
    class="order-bill-recharge electric"
  >
    <NutFormItem class="bole-form-item" prop="currentUserAccountId">
      <NutRadioGroup
        v-model="form.currentUserAccountId"
        direction="horizontal"
        class="par-account-list"
        v-if="userAccountAllList.length > 0"
        @change="handleUserAccountChange"
      >
        <NutRadio :label="item.id" shape="button" v-for="item in userAccountAllList" :key="item.id"
          >{{ item.city }}-{{ item.content }}</NutRadio
        >
      </NutRadioGroup>
      <AccountCard
        v-if="userAccountAllList.length > 0"
        title="充值户号"
        :content="`${form.city} ${form.electricAccount}`"
        :remark="form.remark"
      >
        <template #action>
          <div class="account-card-action" @click="handleAddUserAccount">新增</div>
        </template>
      </AccountCard>
      <AccountAddCard text="新增户号" v-else @click="handleAddUserAccount" />
    </NutFormItem>
    <NutFormItem
      v-if="!!form.province"
      label="选择充值金额"
      class="bole-form-item"
      prop="parValue"
      required
    >
      <NutRadioGroup v-model="form.parValue" direction="horizontal" class="parValue-radio-group">
        <NutRadio
          :label="Number(item)"
          :key="item"
          shape="button"
          v-for="item in parValueList"
          class="parValue-item"
        >
          <div class="parValue-item-inner">
            <div class="amount-wrapper">
              <div class="amount">{{ item }}</div>
              <div class="unit">元</div>
            </div>
            <div class="price-wrapper">
              <div class="price-text">折后</div>
              <div class="price">
                {{ blLifeRecharge.getRechargeParValue(item, lifePayElectricRate) }}元
              </div>
            </div>
            <div class="discountTag">{{ lifePayElectricRate }}折</div>
          </div>
        </NutRadio>
      </NutRadioGroup>
    </NutFormItem>
    <div class="common-content">
      <nut-button class="recharge-button" type="primary" @click="handleSubmit">
        <div class="recharge-button-inner">
          <div>¥{{ realParValue }}</div>
          <div class="recharge-button-text">立即充值</div>
        </div>
      </nut-button>
      <RechargeTipsView :tips="tips" />
    </div>
    <ConfirmDialog v-model:visible="confirmDialogVisible" @ok="goPay">
      <template #tips>
        该产品为慢充模式,0-72小时内到账,介意请勿付款!充值前请仔细阅读充值须知!
      </template>
      <template #info>
        <ConfirmDialogInfoItem
          label="电网类型"
          :content="blLifeRecharge.constants.ElectricTypeText[form.electricType]"
        />
        <ConfirmDialogInfoItem :label-width="96" label="户号" :content="form.electricAccount" />
        <ConfirmDialogInfoItem label="充值金额" :content="`¥${form.parValue.toFixed(2)}`" danger />
        <ConfirmDialogInfoItem label="优惠金额" :content="`¥${discountParValue.toFixed(2)}`" />
        <ConfirmDialogInfoItem label="实付金额" :content="`¥${realParValue}`" danger />
      </template>
      <template #warning>
        同一电费账户在充值期间,未到账前切勿在其他任何平台再次充值。因此造成的资金损失须用户自行承担!!!
      </template>
    </ConfirmDialog>
  </NutForm>
</template>
<script setup lang="ts">
import {
  Form as NutForm,
  FormItem as NutFormItem,
  RadioGroup as NutRadioGroup,
  Radio as NutRadio,
  Button as NutButton,
} from '@nutui/nutui-taro';
import { FormRules } from '@nutui/nutui-taro/dist/types/__VUE/form/types';
import { reactive, ref, computed } from 'vue';
import {
  useLifeRechargeContext,
  LifeElectricDataCreateLifePayOrderInput,
  LifeRechargeConstants,
  UserAccountListOutput,
} from '@life-payment/core-vue';
import RechargeTipsView from '../../components/RechargeTipsView/RechargeTipsView.vue';
import ConfirmDialog from '../../components/Dialog/ConfirmDialog.vue';
import ConfirmDialogInfoItem from '../../components/Dialog/ConfirmDialogInfoItem.vue';
import { useGetRate, useGetElectricParValue, useSetUserAccountBySelect } from '../../hooks';
import { FormValidator } from '../../utils';
import { CustomerServiceTips } from '../../constants';
import AccountAddCard from '../../components/Card/AccountAddCard.vue';
import AccountCard from '../../components/Card/AccountCard.vue';
import { useElectricBillRechargeContext, ElectricUserAccountExtraProperties } from './context';
defineOptions({
  name: 'ElectricBillRechargeStep2',
});
type Props = {
  isDev?: boolean;
};
const props = withDefaults(defineProps<Props>(), {
  isDev: false,
});
const emit = defineEmits<{
  (e: 'goPay', orderNo: string): void;
}>();
const { goTo } = useElectricBillRechargeContext();
const form = reactive({
  parValue: 0,
  electricAccount: '',
  electricType: '',
  electricAccountType: '',
  province: '',
  city: '',
  sixID: '',
  currentUserAccountId: '',
  remark: '',
});
const { userAccountAllList, handleUserAccountChange } = useSetUserAccountBySelect({
  lifePayOrderType: LifeRechargeConstants.LifePayOrderTypeEnum.电费订单,
  onSetUserAccount(currentUserAccount) {
    const currentUserAccountExtraProperties = JSON.parse(
      currentUserAccount.extraProperties
    ) as ElectricUserAccountExtraProperties;
    form.currentUserAccountId = currentUserAccount.id;
    form.electricAccount = currentUserAccount.content;
    form.province = currentUserAccount.province;
    form.city = currentUserAccount.city;
    form.electricType = currentUserAccountExtraProperties.electricType;
    form.electricAccountType = currentUserAccountExtraProperties.electricAccountType;
    form.sixID = currentUserAccountExtraProperties.sixID;
    form.remark = currentUserAccount.remark;
    const electricParValueItem = electricParValueList.value.find(
      (x) => x.cityName === form.province
    );
    if (
      electricParValueItem &&
      electricParValueItem.parValue.every((x) => Number(x) !== form.parValue)
    ) {
      form.parValue = 0;
    }
  },
});
function handleAddUserAccount() {
  goTo('step1');
}
const { lifePayElectricRate } = useGetRate();
const { electricParValueList } = useGetElectricParValue();
const { blLifeRecharge } = useLifeRechargeContext();
const parValueList = computed(() => {
  const parValueList =
    electricParValueList.value.find((x) => x.cityName === form.province)?.parValue ?? [];
  return blLifeRecharge.filterParValueList(parValueList);
});
const realParValue = computed(() =>
  blLifeRecharge.getRechargeParValue(form.parValue, lifePayElectricRate.value)
);
const discountParValue = computed(() => form.parValue - Number(realParValue.value));
const rules = reactive<FormRules>({
  parValue: [
    { required: true, message: '请选择充值金额', validator: FormValidator.validatorNumberNotNull },
  ],
  currentUserAccountId: [{ required: true, message: '请选择充值户号' }],
});
const formRef = ref<any>(null);
function handleSubmit() {
  if (!formRef.value) return;
  formRef.value.validate().then(({ valid, errors }: any) => {
    if (valid) {
      recharge();
    }
  });
}
const tips = [
  '平台提供慢充服务,订单提交后,电费将于0 - 72 小时内到账,若未能按时到账,系统将自动发起退款。',
  '充值期间,若同一账户的充值款未到账,请勿在其他平台重复充值,因上述操作导致的资金损失,由用户自行承担。',
  '为确保充值顺利进行,目前平台不支持对欠款金额超过1000元的账户进行充值,且每次充值金额必须高于欠费总额。',
  '如接到陌生来电,对方以缴费或误操作等理由要求处理款项,务必立即拉黑,谨防诈骗。',
  '下单时,请您务必准确填写完整的省市及户号信息。充值完成后,发票由运营商提供,您可登录网上营业厅下载对应的电子发票。',
  CustomerServiceTips,
];
const confirmDialogVisible = ref(false);
function recharge() {
  confirmDialogVisible.value = true;
}
async function goPay() {
  try {
    let params: LifeElectricDataCreateLifePayOrderInput = {
      userId: blLifeRecharge.accountModel.userId,
      channelId: blLifeRecharge.accountModel.channlesNum,
      productData: {
        parValue: props.isDev ? 0.1 : form.parValue,
        electricType: form.electricType,
        electricAccountType: form.electricAccountType,
        electricAccount: form.electricAccount,
        province: form.province,
        city: form.city,
        sixID: form.sixID,
      },
    };
    let res = await blLifeRecharge.services.createLifePayElectricOrder(params);
    emit('goPay', res.orderNo);
  } catch (error) {}
}
</script>
packages/components/src/views/electricBillRecharge/context.ts
New file
@@ -0,0 +1,37 @@
import type { InjectionKey, UnwrapNestedRefs, Ref } from 'vue';
import { inject } from 'vue';
import { UseStepperReturn } from 'senin-mini/hooks';
type ElectricBillRechargeSteps = 'step1' | 'step2';
export interface ElectricBillRechargeContext
  extends UseStepperReturn<
    ElectricBillRechargeSteps,
    ElectricBillRechargeSteps[],
    ElectricBillRechargeSteps
  > {
  //   form: UnwrapNestedRefs<{
  //     ispCode: string;
  //     phone: string;
  //     parValue: number;
  //     name: string;
  //   }>;
}
export const ElectricBillRechargeContextKey: InjectionKey<ElectricBillRechargeContext> = Symbol(
  'ElectricBillRechargeContextKey'
);
export function useElectricBillRechargeContext() {
  return inject(ElectricBillRechargeContextKey);
}
export type ElectricUserAccountExtraProperties = {
  electricAccount: string;
  electricType: string;
  electricAccountType: string;
  province: string;
  city: string;
  sixID: string;
  remark: string;
};
packages/components/src/views/electricBillRecharge/electricBillRecharge.vue
@@ -1,150 +1,18 @@
<template>
  <NutForm
    :model-value="form"
    ref="formRef"
    :rules="rules"
    label-position="top"
    class="order-bill-recharge electric"
  >
    <FormItem label="所在区域" class="bole-form-item" prop="province" required>
      <ChooseInputWithPicker
        v-model="form.province"
        placeholder="请选择区域"
        :value-enum="electricParValueList"
        enum-label-key="cityName"
        enum-value-key="cityName"
      />
    </FormItem>
    <FormItem label="所在城市" class="bole-form-item" prop="city" required v-if="form.province">
      <ChooseInputWithPicker
        v-model="form.city"
        placeholder="请选择城市"
        :value-enum="electricCityList"
        enum-label-key="cityName"
        enum-value-key="cityName"
      />
    </FormItem>
    <!-- <FormItem label="电网类型" class="bole-form-item" prop="electricType" required>
      <ChooseInputWithPicker
        v-model="form.electricType"
        placeholder="请选择电网类型"
        :value-enum="blLifeRecharge.constants.ElectricTypeText"
      />
    </FormItem> -->
    <FormItem label="电费类型" class="bole-form-item" prop="electricAccountType" required>
      <ChooseInputWithPicker
        v-model="form.electricAccountType"
        placeholder="请选择电费类型"
        :value-enum="blLifeRecharge.constants.ElectricAccountTypeText"
      />
    </FormItem>
    <FormItem label="电网户号" class="bole-form-item" prop="electricAccount" required>
      <NumberInput
        v-model.trim="form.electricAccount"
        class="bole-input-text"
        placeholder="请输入13位数字编号"
        max-length="13"
      />
    </FormItem>
    <FormItem
      v-if="form.electricType === blLifeRecharge.constants.ElectricType.nanwang"
      label="身份证后六位"
      class="bole-form-item"
      prop="sixID"
      required
    >
      <NutInput
        v-model.trim="form.sixID"
        class="bole-input-text"
        placeholder="请输入身份证后六位"
        type="text"
        max-length="6"
      />
    </FormItem>
    <FormItem
      v-if="!!form.province"
      label="选择充值金额"
      class="bole-form-item"
      prop="parValue"
      required
    >
      <NutRadioGroup v-model="form.parValue" direction="horizontal" class="parValue-radio-group">
        <NutRadio
          :label="Number(item)"
          :key="item"
          shape="button"
          v-for="item in parValueList"
          class="parValue-item"
        >
          <div class="parValue-item-inner">
            <div class="amount-wrapper">
              <div class="amount">{{ item }}</div>
              <div class="unit">元</div>
            </div>
            <div class="price-wrapper">
              <div class="price-text">折后</div>
              <div class="price">
                {{ blLifeRecharge.getRechargeParValue(item, lifePayElectricRate) }}元
              </div>
            </div>
            <div class="discountTag">{{ lifePayElectricRate * 100 }}折</div>
          </div>
        </NutRadio>
      </NutRadioGroup>
    </FormItem>
    <div class="common-content">
      <nut-button class="recharge-button" type="primary" @click="handleSubmit">
        <div class="recharge-button-inner">
          <div>¥{{ realParValue }}</div>
          <div class="recharge-button-text">立即充值</div>
        </div>
      </nut-button>
      <RechargeTipsView :tips="tips" />
    </div>
    <ConfirmDialog v-model:visible="confirmDialogVisible" @ok="goPay">
      <template #tips>
        该产品为慢充模式,0-72小时内到账,介意请勿付款!充值前请仔细阅读充值须知!
      </template>
      <template #info>
        <ConfirmDialogInfoItem
          label="电网类型"
          :content="blLifeRecharge.constants.ElectricTypeText[form.electricType]"
        />
        <ConfirmDialogInfoItem label="电费类型" content="住宅" />
        <ConfirmDialogInfoItem label="充值金额" :content="`¥${form.parValue.toFixed(2)}`" danger />
        <ConfirmDialogInfoItem label="优惠金额" :content="`¥${discountParValue.toFixed(2)}`" />
        <ConfirmDialogInfoItem label="实付金额" :content="`¥${realParValue}`" danger />
      </template>
      <template #warning>
        同一电费账户在充值期间,未到账前切勿在其他任何平台再次充值。因此造成的资金损失须用户自行承担!!!
      </template>
    </ConfirmDialog>
  </NutForm>
  <ElectricBillRechargeStep1 v-if="current === 'step1'" />
  <ElectricBillRechargeStep2
    v-else-if="current === 'step2'"
    v-bind="props"
    @go-pay="emit('goPay', $event)"
  />
</template>
<script setup lang="ts">
import {
  Form as NutForm,
  FormItem,
  RadioGroup as NutRadioGroup,
  Radio as NutRadio,
  Input as NutInput,
  Button as NutButton,
} from '@nutui/nutui-taro';
import { FormRules } from '@nutui/nutui-taro/dist/types/__VUE/form/types';
import { reactive, ref, computed, watch } from 'vue';
import {
  useLifeRechargeContext,
  BlLifeRecharge,
  LifeElectricDataCreateLifePayOrderInput,
} from '@life-payment/core-vue';
import RechargeTipsView from '../../components/RechargeTipsView/RechargeTipsView.vue';
import ConfirmDialog from '../../components/Dialog/ConfirmDialog.vue';
import ConfirmDialogInfoItem from '../../components/Dialog/ConfirmDialogInfoItem.vue';
import ChooseInputWithPicker from '../../components/Input/ChooseInputWithPicker.vue';
import NumberInput from '../../components/Input/NumberInput.vue';
import { useGetRate, useGetElectricParValue } from '../../hooks';
import { FormValidator } from '../../utils';
import { computed, provide } from 'vue';
import { useStepper } from 'senin-mini/hooks';
import { ElectricBillRechargeContextKey } from './context';
import ElectricBillRechargeStep1 from './ElectricBillRechargeStep1.vue';
import ElectricBillRechargeStep2 from './ElectricBillRechargeStep2.vue';
defineOptions({
  name: 'electricBillRecharge',
@@ -162,102 +30,10 @@
  (e: 'goPay', orderNo: string): void;
}>();
const form = reactive({
  parValue: 0,
  electricAccount: '',
  electricType: '',
  electricAccountType: '',
  province: '',
  city: '',
  sixID: '',
const stepperInfo = useStepper(['step1', 'step2'], 'step2');
const current = computed(() => stepperInfo.current.value);
provide(ElectricBillRechargeContextKey, {
  ...stepperInfo,
});
const { lifePayElectricRate } = useGetRate();
const { electricParValueList } = useGetElectricParValue();
const parValueList = computed(
  () => electricParValueList.value.find((x) => x.cityName === form.province)?.parValue ?? []
);
const electricCityList = computed(
  () => electricParValueList.value.find((x) => x.cityName === form.province)?.childCityList ?? []
);
watch(
  () => form.province,
  (provinceName) => {
    const electricParValue = electricParValueList.value.find(
      (item) => item.cityName === provinceName
    );
    form.electricType = electricParValue.electricType;
  }
);
const realParValue = computed(() =>
  blLifeRecharge.getRechargeParValue(form.parValue, lifePayElectricRate.value)
);
const discountParValue = computed(() => form.parValue - Number(realParValue.value));
const { blLifeRecharge } = useLifeRechargeContext();
const rules = reactive<FormRules>({
  province: [{ required: true, message: '请选择所在区域' }],
  city: [{ required: true, message: '请选择所在城市' }],
  electricAccountType: [{ required: true, message: '请选择电费类型' }],
  electricAccount: [{ required: true, message: '请输入电网户号', regex: /^\d{13}$/ }],
  sixID: [
    {
      required: true,
      message: '请输入身份证后六位',
      validator: FormValidator.validatorIDNumberSix,
    },
  ],
  parValue: [
    { required: true, message: '请选择充值金额', validator: FormValidator.validatorNumberNotNull },
  ],
});
const formRef = ref<any>(null);
function handleSubmit() {
  if (!formRef.value) return;
  formRef.value.validate().then(({ valid, errors }: any) => {
    if (valid) {
      recharge();
    }
  });
}
const tips = [
  '平台提供慢充服务,订单提交后,电费将于0 - 72 小时内到账,若未能按时到账,系统将自动发起退款。',
  '充值期间,若同一账户的充值款未到账,请勿在其他平台重复充值,因上述操作导致的资金损失,由用户自行承担。',
  '为确保充值顺利进行,目前平台不支持对欠款金额超过1000元的账户进行充值,且每次充值金额必须高于欠费总额。',
  '如接到陌生来电,对方以缴费或误操作等理由要求处理款项,务必立即拉黑,谨防诈骗。',
  '下单时,请您务必准确填写完整的省市及户号信息。充值完成后,发票由运营商提供,您可登录网上营业厅下载对应的电子发票。',
];
const confirmDialogVisible = ref(false);
function recharge() {
  confirmDialogVisible.value = true;
}
async function goPay() {
  try {
    let params: LifeElectricDataCreateLifePayOrderInput = {
      userId: blLifeRecharge.accountModel.userId,
      productData: {
        parValue: props.isDev ? 0.1 : form.parValue,
        electricType: form.electricType,
        electricAccountType: form.electricAccountType,
        electricAccount: form.electricAccount,
        province: form.province,
        city: form.city,
        sixID: form.sixID,
      },
    };
    let res = await blLifeRecharge.services.createLifePayElectricOrder(params);
    emit('goPay', res.orderNo);
  } catch (error) {}
}
</script>
packages/components/src/views/userAccount/EditElectricUserAccount.vue
New file
@@ -0,0 +1,123 @@
<template>
  <LoadingLayout :loading="isLoading">
    <ElectricBillRechargeBaseForm ref="formRef" v-model:form="form">
      <NutFormItem label="备注信息" class="bole-form-item" prop="remark">
        <NutTextarea
          placeholder="请输入备注信息"
          placeholderClass="bole-input-text-placeholder"
          autoSize
          class="bole-input-textarea"
          v-model="form.remark"
          :max-length="30"
          limit-show
        >
        </NutTextarea>
      </NutFormItem>
      <div class="common-content">
        <NutButton class="recharge-button" type="primary" @click="handleSave">
          <div class="recharge-button-inner">
            <div class="recharge-button-text">保存</div>
          </div>
        </NutButton>
      </div>
    </ElectricBillRechargeBaseForm>
  </LoadingLayout>
</template>
<script setup lang="ts">
import ElectricBillRechargeBaseForm from '../electricBillRecharge/ElectricBillRechargeBaseForm.vue';
import { Button as NutButton, Textarea as NutTextarea } from '@nutui/nutui-taro';
import { reactive, ref, computed } from 'vue';
import {
  useLifeRechargeContext,
  LifeRechargeConstants,
  AddUpdateUserAccountInput,
} from '@life-payment/core-vue';
import { useAddUpdateUserAccount } from '../../hooks';
import LoadingLayout from '../../components//Layout/LoadingLayout.vue';
import { useQuery } from '@tanstack/vue-query';
import { ElectricUserAccountExtraProperties } from '../electricBillRecharge/context';
defineOptions({
  name: 'EditElectricUserAccount',
});
type Props = {
  id?: string;
};
const props = withDefaults(defineProps<Props>(), {});
const emit = defineEmits<{
  (e: 'success'): void;
}>();
const { blLifeRecharge } = useLifeRechargeContext();
const { isLoading } = useQuery({
  queryKey: ['blLifeRecharge/getUserAccountDetail', props.id],
  queryFn: async () => {
    return await blLifeRecharge.services.getUserAccountDetail(
      { id: props.id },
      {
        showLoading: false,
      }
    );
  },
  onSuccess(data) {
    const currentUserAccountExtraProperties = JSON.parse(
      data.extraProperties
    ) as ElectricUserAccountExtraProperties;
    form.electricAccount = data.content;
    form.province = data.province;
    form.city = data.city;
    form.electricType = currentUserAccountExtraProperties.electricType;
    form.electricAccountType = currentUserAccountExtraProperties.electricAccountType;
    form.sixID = currentUserAccountExtraProperties.sixID;
    form.remark = data.remark;
  },
  enabled: computed(() => !!props.id),
});
const form = reactive({
  electricAccount: '',
  electricType: '',
  electricAccountType: '',
  province: '',
  city: '',
  sixID: '',
  remark: '',
});
const formRef = ref<any>(null);
function handleSave() {
  if (!formRef.value) return;
  formRef.value.validate().then(({ valid, errors }: any) => {
    if (valid) {
      handleAddUpdateUserAccount();
    }
  });
}
const { addUpdateUserAccount } = useAddUpdateUserAccount();
async function handleAddUpdateUserAccount() {
  try {
    let params: AddUpdateUserAccountInput = {
      userId: blLifeRecharge.accountModel.userId,
      operators: form.electricType,
      lifePayType: LifeRechargeConstants.LifePayOrderTypeEnum.电费订单,
      content: form.electricAccount,
      province: form.province,
      city: form.city,
      extraProperties: JSON.stringify(form),
      remark: form.remark,
      id: props.id,
    };
    await addUpdateUserAccount(params);
    emit('success');
  } catch (error) {}
}
</script>
packages/components/src/views/userAccount/EditGasUserAccount.vue
New file
@@ -0,0 +1,133 @@
<template>
  <LoadingLayout :loading="isLoading">
    <GasBillRechargeBaseForm ref="formRef" v-model:form="form">
      <template #top>
        <NutFormItem label="燃气类型" class="bole-form-item" prop="gasOrgType" required>
          <ChooseInputWithPicker
            v-model="form.gasOrgType"
            placeholder="请选择燃气类型"
            :value-enum="gasParValueList"
            enum-label-key="gasOrgName"
            enum-value-key="gasOrgCode"
          />
        </NutFormItem>
      </template>
      <NutFormItem label="备注信息" class="bole-form-item" prop="remark">
        <NutTextarea
          placeholder="请输入备注信息"
          placeholderClass="bole-input-text-placeholder"
          autoSize
          class="bole-input-textarea"
          v-model="form.remark"
          :max-length="30"
          limit-show
        >
        </NutTextarea>
      </NutFormItem>
      <div class="common-content">
        <NutButton class="recharge-button" type="primary" @click="handleSave">
          <div class="recharge-button-inner">
            <div class="recharge-button-text">保存</div>
          </div>
        </NutButton>
      </div>
    </GasBillRechargeBaseForm>
  </LoadingLayout>
</template>
<script setup lang="ts">
import GasBillRechargeBaseForm from '../GasBillRecharge/GasBillRechargeBaseForm.vue';
import { Button as NutButton, Textarea as NutTextarea } from '@nutui/nutui-taro';
import { reactive, ref, computed } from 'vue';
import {
  useLifeRechargeContext,
  LifeRechargeConstants,
  AddUpdateUserAccountInput,
} from '@life-payment/core-vue';
import { useAddUpdateUserAccount, useGetGasParValue } from '../../hooks';
import LoadingLayout from '../../components//Layout/LoadingLayout.vue';
import ChooseInputWithPicker from '../../components//Input/ChooseInputWithPicker.vue';
import { useQuery } from '@tanstack/vue-query';
import { GasUserAccountExtraProperties } from '../GasBillRecharge/context';
defineOptions({
  name: 'EditGasUserAccount',
});
type Props = {
  id?: string;
};
const props = withDefaults(defineProps<Props>(), {});
const emit = defineEmits<{
  (e: 'success'): void;
}>();
const { blLifeRecharge } = useLifeRechargeContext();
const { gasParValueList } = useGetGasParValue();
const { isLoading } = useQuery({
  queryKey: ['blLifeRecharge/getUserAccountDetail', props.id],
  queryFn: async () => {
    return await blLifeRecharge.services.getUserAccountDetail(
      { id: props.id },
      {
        showLoading: false,
      }
    );
  },
  onSuccess(data) {
    const currentUserAccountExtraProperties = JSON.parse(
      data.extraProperties
    ) as GasUserAccountExtraProperties;
    form.gasAccount = data.content;
    form.areaList = [data.province, data.city];
    form.gasOrgType = data.operators as any;
    form.remark = data.remark;
  },
  enabled: computed(() => !!props.id),
});
const form = reactive({
  gasOrgType: '',
  // province: '',
  // city: '',
  gasAccount: '',
  remark: '',
  areaList: [] as string[],
});
const formRef = ref<any>(null);
function handleSave() {
  if (!formRef.value) return;
  formRef.value.validate().then(({ valid, errors }: any) => {
    if (valid) {
      handleAddUpdateUserAccount();
    }
  });
}
const { addUpdateUserAccount } = useAddUpdateUserAccount();
async function handleAddUpdateUserAccount() {
  try {
    let params: AddUpdateUserAccountInput = {
      userId: blLifeRecharge.accountModel.userId,
      lifePayType: LifeRechargeConstants.LifePayOrderTypeEnum.燃气订单,
      content: form.gasAccount,
      province: form.areaList?.[0] ?? '',
      city: form.areaList?.[1] ?? '',
      extraProperties: JSON.stringify(form),
      remark: form.remark,
      operators: form.gasOrgType,
      id: props.id,
    };
    await addUpdateUserAccount(params);
    emit('success');
  } catch (error) {}
}
</script>
packages/components/src/views/userAccount/EditPhoneUserAccount.vue
New file
@@ -0,0 +1,114 @@
<template>
  <LoadingLayout :loading="isLoading">
    <PhoneBillRechargeBaseForm ref="formRef" v-model:form="form">
      <NutFormItem label="备注信息" class="bole-form-item" prop="remark">
        <NutTextarea
          placeholder="请输入备注信息"
          placeholderClass="bole-input-text-placeholder"
          autoSize
          class="bole-input-textarea"
          v-model="form.remark"
          :max-length="30"
          limit-show
        >
        </NutTextarea>
      </NutFormItem>
      <div class="common-content">
        <NutButton class="recharge-button" type="primary" @click="handleSave">
          <div class="recharge-button-inner">
            <div class="recharge-button-text">保存</div>
          </div>
        </NutButton>
      </div>
    </PhoneBillRechargeBaseForm>
  </LoadingLayout>
</template>
<script setup lang="ts">
import PhoneBillRechargeBaseForm from '../PhoneBillRecharge/PhoneBillRechargeBaseForm.vue';
import { Button as NutButton, Textarea as NutTextarea } from '@nutui/nutui-taro';
import { reactive, ref, computed } from 'vue';
import {
  useLifeRechargeContext,
  LifeRechargeConstants,
  AddUpdateUserAccountInput,
} from '@life-payment/core-vue';
import { useAddUpdateUserAccount } from '../../hooks';
import LoadingLayout from '../../components//Layout/LoadingLayout.vue';
import { useQuery } from '@tanstack/vue-query';
import { PhoneUserAccountExtraProperties } from '../PhoneBillRecharge/context';
defineOptions({
  name: 'EditPhoneUserAccount',
});
type Props = {
  id?: string;
};
const props = withDefaults(defineProps<Props>(), {});
const emit = defineEmits<{
  (e: 'success'): void;
}>();
const { blLifeRecharge } = useLifeRechargeContext();
const { isLoading } = useQuery({
  queryKey: ['blLifeRecharge/getUserAccountDetail', props.id],
  queryFn: async () => {
    return await blLifeRecharge.services.getUserAccountDetail(
      { id: props.id },
      {
        showLoading: false,
      }
    );
  },
  onSuccess(data) {
    const currentUserAccountExtraProperties = JSON.parse(
      data.extraProperties
    ) as PhoneUserAccountExtraProperties;
    form.ispCode = currentUserAccountExtraProperties.ispCode;
    form.phone = data.content;
    form.name = currentUserAccountExtraProperties.name;
    form.remark = data.remark;
  },
  enabled: computed(() => !!props.id),
});
const form = reactive({
  ispCode: '',
  phone: '',
  name: '',
  remark: '',
});
const formRef = ref<any>(null);
function handleSave() {
  if (!formRef.value) return;
  formRef.value.validate().then(({ valid, errors }: any) => {
    if (valid) {
      handleAddUpdateUserAccount();
    }
  });
}
const { addUpdateUserAccount } = useAddUpdateUserAccount();
async function handleAddUpdateUserAccount() {
  try {
    let params: AddUpdateUserAccountInput = {
      userId: blLifeRecharge.accountModel.userId,
      operators: form.ispCode,
      lifePayType: LifeRechargeConstants.LifePayOrderTypeEnum.话费订单,
      content: form.phone,
      extraProperties: JSON.stringify(form),
      remark: form.remark,
      id: props.id,
    };
    await addUpdateUserAccount(params);
    emit('success');
  } catch (error) {}
}
</script>
packages/components/src/views/userAccount/UserAccountListView.vue
New file
@@ -0,0 +1,98 @@
<template>
  <InfiniteLoading
    scrollViewClassName="life-page-infinite-scroll-list"
    v-bind="infiniteLoadingProps"
  >
    <template #renderItem="{ item }">
      <AccountCard
        :title="TitleMap[item.lifePayType]"
        :content="
          item.lifePayType === LifeRechargeConstants.LifePayOrderTypeEnum.话费订单
            ? item.content
            : `${item.city}-${item.content}`
        "
        :remark="item.remark"
        :style="{
          marginBottom: Taro.pxTransform(20),
          backgroundColor: '#ffffff',
        }"
      >
        <template #action>
          <div class="account-card-action" @click="handleEditUserAccount(item)">编辑</div>
          <div class="account-card-action" @click="handleDeleteUserAccount(item)">删除</div>
        </template>
      </AccountCard>
    </template>
  </InfiniteLoading>
</template>
<script setup lang="ts">
import InfiniteLoading from '../../components/InfiniteLoading/InfiniteLoading.vue';
import {
  BlLifeRecharge,
  useLifeRechargeContext,
  QueryUserAccountListInput,
  LifeRechargeConstants,
  UserAccountListOutput,
} from '@life-payment/core-vue';
import { useInfiniteLoading } from '../../hooks/infiniteLoading';
import { OrderInputType } from '../../constants';
import AccountCard from '../../components/Card/AccountCard.vue';
import Taro from '@tarojs/taro';
defineOptions({
  name: 'UserAccountListView',
});
const emit = defineEmits<{
  (e: 'goEdit', row: UserAccountListOutput): void;
}>();
const { blLifeRecharge } = useLifeRechargeContext();
const TitleMap = {
  [LifeRechargeConstants.LifePayOrderTypeEnum.话费订单]: '手机号',
  [LifeRechargeConstants.LifePayOrderTypeEnum.电费订单]: '电费户号',
  [LifeRechargeConstants.LifePayOrderTypeEnum.燃气订单]: '燃气户号',
};
const { infiniteLoadingProps, invalidateQueries } = useInfiniteLoading(
  ({ pageParam }) => {
    let params: QueryUserAccountListInput = {
      pageModel: {
        rows: 20,
        page: pageParam,
        orderInput: [{ property: 'creationTime', order: OrderInputType.Desc }],
      },
      userId: blLifeRecharge.accountModel.userId,
    };
    return blLifeRecharge.services.getUserAccountList(params, {
      showLoading: false,
    });
  },
  {
    queryKey: ['blLifeRecharge/getUserAccountList', blLifeRecharge.accountModel.userId],
  }
);
function handleEditUserAccount(row: UserAccountListOutput) {
  emit('goEdit', row);
}
async function handleDeleteUserAccount(row: UserAccountListOutput) {
  try {
    const res = await Taro.showModal({
      title: '提示',
      content: '确定要删除该数据吗?',
      confirmColor: '#3a71ff',
    });
    if (res.confirm) {
      await blLifeRecharge.services.deleteUserAccount({
        id: row.id,
      });
      invalidateQueries();
    }
  } catch (error) {}
}
</script>
packages/core-vue/package.json
@@ -2,7 +2,6 @@
  "name": "@life-payment/core-vue",
  "main": "src/index.ts",
  "module": "./src/index.ts",
  "types": "./dist/types/index.d.ts",
  "source": "./src/index.ts",
  "version": "0.0.3",
  "scripts": {
packages/core/CHANGELOG.md
@@ -1,5 +1,26 @@
## [0.0.3](http://120.26.58.240:8888/r/LifePaymentFront/compare/core/v0.0.2...core/v0.0.3) (2025-03-13)
### Bug Fixes
* 对接 ([337c9f5](http://120.26.58.240:8888/r/LifePaymentFront/commits/337c9f5fe3956021fb32db5054dfb395c7801beb))
* 对接 ([818d0f4](http://120.26.58.240:8888/r/LifePaymentFront/commits/818d0f406772f00c43c8d6d68e9b52e9b729f35a))
* 对接 ([b916fb4](http://120.26.58.240:8888/r/LifePaymentFront/commits/b916fb416c25a7e11c25fb62bc83f2f3434778d0))
* 对接 ([eb194e0](http://120.26.58.240:8888/r/LifePaymentFront/commits/eb194e0179c83ba86f1fcac398057bf423aaab34))
* 二期需求 ([2719e1b](http://120.26.58.240:8888/r/LifePaymentFront/commits/2719e1b7487c2b8080218bbbd625eb1191260d04))
* 二期需求 ([8525b5c](http://120.26.58.240:8888/r/LifePaymentFront/commits/8525b5c780d8855eca89c46790627c00b3d83c79))
* 二期需求 ([db365a5](http://120.26.58.240:8888/r/LifePaymentFront/commits/db365a5eff31c040c42463df4966bf34a5de6a6d))
* 二期需求 ([5a5af7e](http://120.26.58.240:8888/r/LifePaymentFront/commits/5a5af7e63a639541db5121d9fa30775b6d500108))
* 二期需求 ([f202553](http://120.26.58.240:8888/r/LifePaymentFront/commits/f2025539d8bf4798b90a5ab8a47c5a379ab68e9b))
* 二期需求 ([866879a](http://120.26.58.240:8888/r/LifePaymentFront/commits/866879aaf4b209e4820d21d11f9569e72dd6e0a5))
* 二期需求 ([5dd9eb5](http://120.26.58.240:8888/r/LifePaymentFront/commits/5dd9eb5d8a69fa8c2b66706434a6cc7748ff4786))
* 二期需求 ([6bc53a7](http://120.26.58.240:8888/r/LifePaymentFront/commits/6bc53a7251d5a323475757358d00ff051f166497))
* 二期需求 ([0787f6b](http://120.26.58.240:8888/r/LifePaymentFront/commits/0787f6b63b9332dde3e8007f4cec83fc66903028))
* some ([afdc0fa](http://120.26.58.240:8888/r/LifePaymentFront/commits/afdc0faf165dbc0c90e45043b4f500a3d53ba20f))
* some ([c4db0ed](http://120.26.58.240:8888/r/LifePaymentFront/commits/c4db0ed5c4218dba29c9924511dc2bbcf169d468))
## 0.0.2 (2025-03-06)
packages/core/package.json
@@ -2,9 +2,8 @@
  "name": "@life-payment/core",
  "main": "src/index.ts",
  "module": "./src/index.ts",
  "types": "./dist/types/index.d.ts",
  "source": "./src/index.ts",
  "version": "0.0.2",
  "version": "0.0.3",
  "scripts": {
    "dev": "modern dev",
    "build": "modern build",
packages/core/src/lifeRecharge.ts
@@ -15,10 +15,11 @@
  constants = LifeRechargeConstants;
  constructor(options: BlLifeRechargeOptions<TResponse, TRequestOptions>) {
    this.services = new BlLifeRechargeServices(options);
    this.services = new BlLifeRechargeServices(this, options);
    this.accountModel = new BlLifeRechargeAccountModel({
      userId: options.userId,
      phoneNumber: options.phoneNumber,
      channlesNum: options.channlesNum,
    });
  }
@@ -43,6 +44,78 @@
  }
  getRechargeParValue(amount: number | string, rate: number) {
    return (Number(amount) * rate).toFixed(2);
    return ((Number(amount) * rate) / 100).toFixed(2);
  }
  MaxParValue = 300;
  filterParValueList(parValueList: string[]) {
    return parValueList.filter((x) => Number(x) <= this.MaxParValue);
  }
  getCarrierByPhoneNumber(phoneNumber: string): LifeRechargeConstants.IspCode {
    // 定义号段和对应的运营商
    const carrierSegments = {
      [LifeRechargeConstants.IspCode.yidong]: [
        '134',
        '135',
        '136',
        '137',
        '138',
        '139',
        '150',
        '151',
        '152',
        '157',
        '158',
        '159',
        '182',
        '183',
        '184',
        '187',
        '188',
        '198',
        '147',
        '178',
        '165',
      ],
      [LifeRechargeConstants.IspCode.liantong]: [
        '130',
        '131',
        '132',
        '155',
        '156',
        '185',
        '186',
        '145',
        '176',
        '166',
      ],
      [LifeRechargeConstants.IspCode.dianxin]: [
        '133',
        '153',
        '180',
        '181',
        '189',
        '177',
        '199',
        '191',
      ],
    };
    // 检查手机号是否有效(这里只简单检查长度)
    if (!/^\d{11}$/.test(phoneNumber)) {
      return '' as any;
    }
    let prefix = phoneNumber.substr(0, 3);
    for (let carrier in carrierSegments) {
      if (carrierSegments[carrier].includes(prefix)) {
        return carrier as LifeRechargeConstants.IspCode;
      }
    }
    // 如果没有找到匹配的号段,则返回未知
    return '' as any;
  }
}
packages/core/src/lifeRechargeAccountModel.ts
@@ -3,11 +3,13 @@
export class BlLifeRechargeAccountModel {
  userId = '';
  phoneNumber = '';
  channlesNum = '';
  constructor(options: BlLifeRechargeAccountModelOptions = {}) {
    const { userId = '', phoneNumber = '' } = options;
    const { userId = '', phoneNumber = '', channlesNum } = options;
    this.setUserId(userId);
    this.setPhoneNumber(phoneNumber);
    this.setChannlesNum(channlesNum);
  }
  setUserId(userId: string) {
@@ -17,4 +19,7 @@
  setPhoneNumber(phoneNumber: string) {
    this.phoneNumber = phoneNumber;
  }
  setChannlesNum(channlesNum: string) {
    this.channlesNum = channlesNum;
  }
}
packages/core/src/lifeRechargeConstants.ts
@@ -1,7 +1,11 @@
export namespace LifeRechargeConstants {
  export enum LifePayRateTypeEnum {
    '默认话费折扣' = 10,
    '默认电费折扣' = 10,
    '默认电费折扣' = 20,
    默认燃气折扣 = 30,
    供应商折扣价 = 40,
  }
  export enum LifePayTypeEnum {
@@ -12,6 +16,7 @@
  export enum LifePayOrderTypeEnum {
    话费订单 = 10,
    电费订单 = 20,
    燃气订单 = 30,
  }
  export enum LifePayStatusEnum {
@@ -30,7 +35,38 @@
    已失败 = 20,
    已完成 = 30,
    退款待审核 = 40,
    已退款 = 50,
    退款失败 = 60,
  }
  export const LifePayOrderStatusEnumText = {
    [LifePayOrderStatusEnum.待确认]: '待确认',
    [LifePayOrderStatusEnum.已失败]: '已失败',
    [LifePayOrderStatusEnum.已完成]: '已完成',
    [LifePayOrderStatusEnum.退款待审核]: '退款待审核',
    [LifePayOrderStatusEnum.已退款]: '已退款',
    [LifePayOrderStatusEnum.退款失败]: '退款失败',
  };
  export enum LifePayOrderFrontStatusEnum {
    支付成功 = 10,
    退款待审核 = 40,
    已退款 = 50,
    退款失败 = 60,
    充值成功 = 100,
  }
  export const LifePayOrderFrontStatusEnumText = {
    [LifePayOrderFrontStatusEnum.支付成功]: '支付成功',
    [LifePayOrderFrontStatusEnum.退款待审核]: '退款待审核',
    [LifePayOrderFrontStatusEnum.已退款]: '已退款',
    [LifePayOrderFrontStatusEnum.退款失败]: '退款失败',
    [LifePayOrderFrontStatusEnum.充值成功]: '充值成功',
  };
  export enum IspCode {
    /**中国移动 */
@@ -76,4 +112,22 @@
    [ElectricAccountType.shop]: '店铺',
    [ElectricAccountType.nanwashopng]: '店铺-不建议使用',
  };
  export enum GasOrgCodeEnum {
    中国燃气 = 'zhong_guo',
    新奥燃气 = 'xin_ao',
    华润燃气 = 'hua_run',
    港华燃气 = 'gang_hua',
    中燃燃气 = 'zhong_ran',
    北京燃气 = 'bei_jing',
  }
  export const GasOrgCodeEnumText = {
    [GasOrgCodeEnum.中国燃气]: '中国燃气',
    [GasOrgCodeEnum.新奥燃气]: '新奥燃气',
    [GasOrgCodeEnum.华润燃气]: '华润燃气',
    [GasOrgCodeEnum.港华燃气]: '港华燃气',
    [GasOrgCodeEnum.中燃燃气]: '中燃燃气',
    [GasOrgCodeEnum.北京燃气]: '北京燃气',
  };
}
packages/core/src/lifeRechargeServices.ts
@@ -1,15 +1,36 @@
import { BlLifeRechargeServicesOptions } from './types';
import { LifeRechargeConstants } from './lifeRechargeConstants';
import { Request, IRequest } from 'senior-request';
import { BlLifeRecharge } from './lifeRecharge';
export interface RequestConfig {}
export class BlLifeRechargeServices<TResponse = any, TRequestOptions = any> {
  private request: IRequest;
  constructor({ axiosConfig }: BlLifeRechargeServicesOptions<TResponse, TRequestOptions>) {
  ctx: BlLifeRecharge<TResponse, TRequestOptions>;
  constructor(
    ctx: BlLifeRecharge<TResponse, TRequestOptions>,
    { axiosConfig }: BlLifeRechargeServicesOptions<TResponse, TRequestOptions>
  ) {
    this.ctx = ctx;
    this.request = Request.create({
      ...axiosConfig,
      // baseURL: process.env.NODE_ENV === 'development' ? '/' : 'https://api.81812333.com',
      requestInterceptors: [
        [
          (config) => {
            if (config.params) {
              config.params.checkChannelId = this.ctx.accountModel.channlesNum;
            }
            if (config.data) {
              config.data.checkChannelId = this.ctx.accountModel.channlesNum;
            }
            return config;
          },
        ],
        ...axiosConfig.requestInterceptors,
      ],
      timeout: 10 * 1000,
      headers: {
        Accept: 'application/json, text/plain, */*',
@@ -40,25 +61,37 @@
  }
  /** 获取电费充值区域 GET /api/LifePay/GetElectricSupportArea */
  async getElectricSupportArea(options?: RequestConfig) {
  async getElectricSupportArea(body: ChannelsBaseInput, options?: RequestConfig) {
    return this.request<ElectricSupportAreaResponse>('/api/LifePay/GetElectricSupportArea', {
      method: 'GET',
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      data: body,
      ...(options || {}),
    });
  }
  /** 获取电费面值 GET /api/LifePay/GetElectricParValue */
  async getElectricParValue(options?: RequestConfig) {
  /** 获取电费面值 POST /api/LifePay/GetElectricParValue */
  async getElectricParValue(body: ChannelsBaseInput, options?: RequestConfig) {
    return this.request<ElectricParValueResponse>('/api/LifePay/GetElectricParValue', {
      method: 'GET',
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      data: body,
      ...(options || {}),
    });
  }
  /** 获取话费面值 GET /api/LifePay/GetPhoneParValue */
  async getPhoneParValue(options?: RequestConfig) {
  async getPhoneParValue(body: ChannelsBaseInput, options?: RequestConfig) {
    return this.request<PhoneParValueResponse>('/api/LifePay/GetPhoneParValue', {
      method: 'GET',
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      data: body,
      ...(options || {}),
    });
  }
@@ -94,14 +127,15 @@
  }
  /** 根据订单号获取支付状态 GET /api/LifePay/GetPayStatusByOrderNo */
  async getPayStatusByOrderNo(params: APIgetPayStatusByOrderNoParams, options?: RequestConfig) {
  async getPayStatusByOrderNo(body: GetPayStatusByOrderNoInput, options?: RequestConfig) {
    return this.request<LifeRechargeConstants.LifePayStatusEnum>(
      '/api/LifePay/GetPayStatusByOrderNo',
      {
        method: 'GET',
        params: {
          ...params,
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        data: body,
        ...(options || {}),
      }
    );
@@ -153,6 +187,131 @@
        'Content-Type': 'application/json',
      },
      data: body,
      ...(options || {}),
    });
  }
  /** 获取我的全部户号列表 POST /api/LifePay/GetUserAccountAllList */
  async getUserAccountAllList(body: QueryUserAccountAllListInput, options?: RequestConfig) {
    return this.request<UserAccountListOutput[]>('/api/LifePay/GetUserAccountAllList', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      data: body,
      ...(options || {}),
    });
  }
  /** 获取我的户号列表 POST /api/LifePay/GetUserAccountList */
  async getUserAccountList(body: QueryUserAccountListInput, options?: RequestConfig) {
    return this.request<UserAccountListOutputPageOutput>('/api/LifePay/GetUserAccountList', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      data: body,
      ...(options || {}),
    });
  }
  /** 添加或修改我的户号 POST /api/LifePay/AddUpdateUserAccount */
  async addUpdateUserAccount(body: AddUpdateUserAccountInput, options?: RequestConfig) {
    return this.request<number>('/api/LifePay/AddUpdateUserAccount', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      data: body,
      ...(options || {}),
    });
  }
  /** 创建生活缴费燃气订单 POST /api/LifePay/CreateLifePayGasOrder */
  async createLifePayGasOrder(body: LifeGasDataCreateLifePayOrderInput, options?: RequestConfig) {
    return this.request<CreateLifePayOrderOutput>('/api/LifePay/CreateLifePayGasOrder', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      data: body,
      ...(options || {}),
    });
  }
  /** 获取燃气面值 GET /api/LifePay/GetGasParValue */
  async getGasParValue(body: ChannelsBaseInput, options?: RequestConfig) {
    return this.request<GasParValueResponse>('/api/LifePay/GetGasParValue', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      data: body,
      ...(options || {}),
    });
  }
  /** 用户发起生活缴费退款 POST /api/LifePay/RefundUserLifePayOrder */
  async refundUserLifePayOrder(body: RefundUserLifePayOrderInput, options?: RequestConfig) {
    return this.request<number>('/api/LifePay/RefundUserLifePayOrder', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      data: body,
      ...(options || {}),
    });
  }
  /** 删除我的户号 POST /api/LifePay/DeleteUserAccount */
  async deleteUserAccount(
    // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
    params: APIdeleteUserAccountParams,
    options?: RequestConfig
  ) {
    return this.request<number>('/api/LifePay/DeleteUserAccount', {
      method: 'POST',
      params: {
        ...params,
      },
      ...(options || {}),
    });
  }
  /** 获取我的户号详情 GET /api/LifePay/GetUserAccountDetail */
  async getUserAccountDetail(
    // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
    params: APIgetUserAccountDetailParams,
    options?: RequestConfig
  ) {
    return this.request<UserAccountOutput>('/api/LifePay/GetUserAccountDetail', {
      method: 'GET',
      params: {
        ...params,
      },
      ...(options || {}),
    });
  }
  /** 获取我的订单详情 GET /api/LifePay/GetUserLifePayOrderDetail */
  async getUserLifePayOrderDetail(
    // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
    params: APIgetUserLifePayOrderDetailParams,
    options?: RequestConfig
  ) {
    return this.request<UserLifePayOrderOutput>('/api/LifePay/GetUserLifePayOrderDetail', {
      method: 'GET',
      params: {
        ...params,
      },
      ...(options || {}),
    });
  }
  /** 搜索管理--列表(区域管理) GET /api/Area/GetRegionalManagementList */
  async getRegionalManagementList(options?: RequestConfig) {
    return this.request<AreaInfo[]>('/api/Area/GetRegionalManagementList', {
      method: 'GET',
      ...(options || {}),
    });
  }
@@ -219,6 +378,8 @@
export interface LifePhoneDataCreateLifePayOrderInput {
  userId?: string;
  /** 渠道Id */
  channelId?: string;
  productData?: LifePhoneData;
}
@@ -239,6 +400,8 @@
export interface LifeElectricDataCreateLifePayOrderInput {
  userId?: string;
  /** 渠道Id */
  channelId?: string;
  productData?: LifeElectricData;
}
@@ -328,6 +491,12 @@
  creationTime?: string;
  /** 退款时间 */
  refundTime?: string;
  /** 退款凭证 */
  refundCredentialsImgUrl?: string;
  refundApplyRemark?: string;
  refundCheckRemark?: string;
  /** 渠道流水号 */
  acoolyOrderNo?: string;
}
export interface ElectricSupportAreaResponse {
@@ -392,3 +561,166 @@
  timeExpire?: string;
  message?: string;
}
export interface QueryUserAccountAllListInput {
  /** 用户Id */
  userId?: string;
  lifePayOrderType?: LifeRechargeConstants.LifePayOrderTypeEnum;
}
export interface UserAccountListOutput {
  id?: string;
  lifePayType?: LifeRechargeConstants.LifePayOrderTypeEnum;
  /** 运营商 */
  operators?: string;
  /** 手机号/户号 */
  content?: string;
  /** 省 */
  province?: string;
  /** 市 */
  city?: string;
  /** 拓展字段(电费类型) */
  extraProperties?: string;
  /** 备注 */
  remark?: string;
  /** 创建时间 */
  creationTime?: string;
  isDeleted?: boolean;
}
export interface AddUpdateUserAccountInput {
  id?: string;
  /** 用户编号 */
  userId?: string;
  lifePayType?: LifeRechargeConstants.LifePayOrderTypeEnum;
  /** 运营商 */
  operators?: string;
  /** 手机号/户号 */
  content?: string;
  /** 省 */
  province?: string;
  /** 市 */
  city?: string;
  /** 拓展字段(电费类型) */
  extraProperties?: string;
  /** 备注 */
  remark?: string;
}
export interface LifeGasDataCreateLifePayOrderInput {
  userId?: string;
  /** 渠道Id */
  channelId?: string;
  productData?: LifeGasData;
}
export interface LifeGasData {
  /** 充值面额,单位为元。 */
  parValue: number;
  /** 天然气公司类型,"zhong_ran"代表中燃燃气,"bei_jing"代表北京燃气。 */
  gasOrgType: string;
  /** 燃气户号 */
  gasAccount: string;
  /** 省份 */
  province: string;
  /** 城市 */
  city?: string;
}
export interface GasParValueResponse {
  success?: boolean;
  requestNo?: string;
  partnerId?: string;
  service?: string;
  version?: string;
  protocol?: string;
  context?: string;
  ext?: any;
  code?: string;
  message?: string;
  detail?: string;
  gasParValue?: GasParValueOutput[];
}
export interface GasParValueOutput {
  gasOrgName?: string;
  gasOrgCode?: string;
  parValue?: string[];
  rate?: number;
  comments?: string;
}
export interface RefundUserLifePayOrderInput {
  id?: string;
  /** 用户Id */
  userId?: string;
  refundApplyRemark?: string;
}
export interface QueryUserAccountListInput {
  pageModel?: Pagination;
  /** 用户Id */
  userId?: string;
  lifePayOrderType?: LifeRechargeConstants.LifePayOrderTypeEnum;
}
export interface UserAccountListOutputPageOutput {
  pageModel?: Pagination;
  objectData?: any;
  data?: UserAccountListOutput[];
}
export interface APIdeleteUserAccountParams {
  id?: string;
}
export interface APIgetUserAccountDetailParams {
  id?: string;
}
export interface UserAccountOutput {
  id?: string;
  lifePayType?: LifeRechargeConstants.LifePayOrderTypeEnum;
  /** 运营商 */
  operators?: string;
  /** 手机号/户号 */
  content?: string;
  /** 省 */
  province?: string;
  /** 市 */
  city?: string;
  /** 拓展字段(电费类型) */
  extraProperties?: string;
  /** 备注 */
  remark?: string;
  /** 创建时间 */
  creationTime?: string;
  isDeleted?: boolean;
}
export interface APIgetUserLifePayOrderDetailParams {
  orderNo?: string;
}
export interface ChannelsBaseInput {
  checkChannelId?: string;
}
export interface AreaInfo {
  areaCode?: number;
  parentId?: number;
  areaName?: string;
  /** 1省 2市 3区 4镇 */
  layer?: number;
  sort?: number;
  children?: AreaInfo[];
  /** 简易拼音 */
  simpleSpelling?: string;
  /** 快速检索 */
  quickQuery?: string;
}
export interface GetPayStatusByOrderNoInput {
  checkChannelId?: string;
  orderNo?: string;
}
packages/core/src/types.ts
@@ -8,6 +8,7 @@
export type BlLifeRechargeAccountModelOptions = {
  userId?: string;
  phoneNumber?: string;
  channlesNum?: string;
};
export type BlLifeRechargeOptions<
packages/services/api/LifePay.ts
@@ -2,12 +2,72 @@
// @ts-ignore
import { request } from '@/utils/request';
/** 添加或修改我的户号 POST /api/LifePay/AddUpdateUserAccount */
export async function addUpdateUserAccount(
  body: API.AddUpdateUserAccountInput,
  options?: API.RequestConfig
) {
  return request<number>('/api/LifePay/AddUpdateUserAccount', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 折扣配置 POST /api/LifePay/CreateEditLifePayRate */
export async function createEditLifePayRate(
  body: API.LifePayRateInput[],
  options?: API.RequestConfig
) {
  return request<number>('/api/LifePay/CreateEditLifePayRate', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 渠道管理 POST /api/LifePay/CreateEditPayChannels */
export async function createEditPayChannels(
  body: API.CreateEditPayChannelsInput,
  options?: API.RequestConfig
) {
  return request<number>('/api/LifePay/CreateEditPayChannels', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 创建生活缴费电费订单 POST /api/LifePay/CreateLifePayElectricOrder */
export async function createLifePayElectricOrder(
  body: API.LifeElectricDataCreateLifePayOrderInput,
  options?: API.RequestConfig
) {
  return request<API.CreateLifePayOrderOutput>('/api/LifePay/CreateLifePayElectricOrder', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 创建生活缴费燃气订单 POST /api/LifePay/CreateLifePayGasOrder */
export async function createLifePayGasOrder(
  body: API.LifeGasDataCreateLifePayOrderInput,
  options?: API.RequestConfig
) {
  return request<API.CreateLifePayOrderOutput>('/api/LifePay/CreateLifePayGasOrder', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
@@ -32,18 +92,113 @@
  });
}
/** 获取电费面值 GET /api/LifePay/GetElectricParValue */
export async function getElectricParValue(options?: API.RequestConfig) {
  return request<API.ElectricParValueResponse>('/api/LifePay/GetElectricParValue', {
    method: 'GET',
/** 删除我的户号 POST /api/LifePay/DeleteUserAccount */
export async function deleteUserAccount(
  // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
  params: API.APIdeleteUserAccountParams,
  options?: API.RequestConfig
) {
  return request<number>('/api/LifePay/DeleteUserAccount', {
    method: 'POST',
    params: {
      ...params,
    },
    ...(options || {}),
  });
}
/** 获取电费充值区域 GET /api/LifePay/GetElectricSupportArea */
export async function getElectricSupportArea(options?: API.RequestConfig) {
/** 获取用户户号分页数据 POST /api/LifePay/GetAccountPage */
export async function getAccountPage(
  body: API.QueryUserAccountListInput,
  options?: API.RequestConfig
) {
  return request<API.UserAccountOutputPageOutput>('/api/LifePay/GetAccountPage', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 获取电费面值 POST /api/LifePay/GetElectricParValue */
export async function getElectricParValue(
  body: API.ChannelsBaseInput,
  options?: API.RequestConfig
) {
  return request<API.ElectricParValueResponse>('/api/LifePay/GetElectricParValue', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 获取电费充值区域 POST /api/LifePay/GetElectricSupportArea */
export async function getElectricSupportArea(
  body: API.ChannelsBaseInput,
  options?: API.RequestConfig
) {
  return request<API.ElectricSupportAreaResponse>('/api/LifePay/GetElectricSupportArea', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 获取燃气支持商户 POST /api/LifePay/GetGasOrgType */
export async function getGasOrgType(body: API.ChannelsBaseInput, options?: API.RequestConfig) {
  return request<API.GasOrgTypeValueResponse>('/api/LifePay/GetGasOrgType', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 获取燃气面值 POST /api/LifePay/GetGasParValue */
export async function getGasParValue(body: API.ChannelsBaseInput, options?: API.RequestConfig) {
  return request<API.GasParValueResponse>('/api/LifePay/GetGasParValue', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 获取渠道详情 GET /api/LifePay/GetLifePayChannlesDto */
export async function getLifePayChannlesDto(
  // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
  params: API.APIgetLifePayChannlesDtoParams,
  options?: API.RequestConfig
) {
  return request<API.CreateEditPayChannelsInput>('/api/LifePay/GetLifePayChannlesDto', {
    method: 'GET',
    params: {
      ...params,
    },
    ...(options || {}),
  });
}
/** 获取缴费渠道列表 POST /api/LifePay/GetLifePayChannlesPage */
export async function getLifePayChannlesPage(body: API.PageInput, options?: API.RequestConfig) {
  return request<API.CreateEditPayChannelsInputPageOutput>('/api/LifePay/GetLifePayChannlesPage', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
@@ -54,6 +209,21 @@
  options?: API.RequestConfig
) {
  return request<API.LifePayOrderListOutputPageOutput>('/api/LifePay/GetLifePayOrderPage', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 导出订单Excel POST /api/LifePay/GetLifePayOrderPageExport */
export async function getLifePayOrderPageExport(
  body: API.QueryLifePayOrderListInput,
  options?: API.RequestConfig
) {
  return request<any>('/api/LifePay/GetLifePayOrderPageExport', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
@@ -78,25 +248,29 @@
  });
}
/** 根据订单号获取支付状态 GET /api/LifePay/GetPayStatusByOrderNo */
/** 根据订单号获取支付状态 POST /api/LifePay/GetPayStatusByOrderNo */
export async function getPayStatusByOrderNo(
  // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
  params: API.APIgetPayStatusByOrderNoParams,
  body: API.GetPayStatusByOrderNoInput,
  options?: API.RequestConfig
) {
  return request<API.LifePayStatusEnum>('/api/LifePay/GetPayStatusByOrderNo', {
    method: 'GET',
    params: {
      ...params,
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 获取话费面值 GET /api/LifePay/GetPhoneParValue */
export async function getPhoneParValue(options?: API.RequestConfig) {
/** 获取话费面值 POST /api/LifePay/GetPhoneParValue */
export async function getPhoneParValue(body: API.ChannelsBaseInput, options?: API.RequestConfig) {
  return request<API.PhoneParValueResponse>('/api/LifePay/GetPhoneParValue', {
    method: 'GET',
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
@@ -105,6 +279,66 @@
export async function getRate(options?: API.RequestConfig) {
  return request<API.LifePayRateListOutput[]>('/api/LifePay/GetRate', {
    method: 'GET',
    ...(options || {}),
  });
}
/** 获取我的全部户号列表 POST /api/LifePay/GetUserAccountAllList */
export async function getUserAccountAllList(
  body: API.QueryUserAccountAllListInput,
  options?: API.RequestConfig
) {
  return request<API.UserAccountOutput[]>('/api/LifePay/GetUserAccountAllList', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 获取我的户号详情 GET /api/LifePay/GetUserAccountDetail */
export async function getUserAccountDetail(
  // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
  params: API.APIgetUserAccountDetailParams,
  options?: API.RequestConfig
) {
  return request<API.UserAccountOutput>('/api/LifePay/GetUserAccountDetail', {
    method: 'GET',
    params: {
      ...params,
    },
    ...(options || {}),
  });
}
/** 获取我的户号列表 POST /api/LifePay/GetUserAccountList */
export async function getUserAccountList(
  body: API.QueryUserAccountListInput,
  options?: API.RequestConfig
) {
  return request<API.UserAccountOutputPageOutput>('/api/LifePay/GetUserAccountList', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 获取我的订单详情 GET /api/LifePay/GetUserLifePayOrderDetail */
export async function getUserLifePayOrderDetail(
  // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
  params: API.APIgetUserLifePayOrderDetailParams,
  options?: API.RequestConfig
) {
  return request<API.UserLifePayOrderOutput>('/api/LifePay/GetUserLifePayOrderDetail', {
    method: 'GET',
    params: {
      ...params,
    },
    ...(options || {}),
  });
}
@@ -120,6 +354,21 @@
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 用户查看生活缴费退款失败详情 GET /api/LifePay/GetUserLifePayOrderRefund */
export async function getUserLifePayOrderRefund(
  // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
  params: API.APIgetUserLifePayOrderRefundParams,
  options?: API.RequestConfig
) {
  return request<API.UserLifePayOrderRefundOutput>('/api/LifePay/GetUserLifePayOrderRefund', {
    method: 'GET',
    params: {
      ...params,
    },
    ...(options || {}),
  });
}
@@ -151,6 +400,51 @@
  });
}
/** 用户发起生活缴费退款 POST /api/LifePay/RefundUserLifePayOrder */
export async function refundUserLifePayOrder(
  body: API.RefundUserLifePayOrderInput,
  options?: API.RequestConfig
) {
  return request<number>('/api/LifePay/RefundUserLifePayOrder', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 退款驳回 POST /api/LifePay/RejectRefundLifePayOrder */
export async function rejectRefundLifePayOrder(
  body: API.RefundLifePayOrderInput,
  options?: API.RequestConfig
) {
  return request<number>('/api/LifePay/RejectRefundLifePayOrder', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
/** 设置渠道启用状态 GET /api/LifePay/SetLifePayChannelsStatus */
export async function setLifePayChannelsStatus(
  // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
  params: API.APIsetLifePayChannelsStatusParams,
  options?: API.RequestConfig
) {
  return request<number>('/api/LifePay/SetLifePayChannelsStatus', {
    method: 'GET',
    params: {
      ...params,
    },
    ...(options || {}),
  });
}
/** 设置生活缴费支付类型 POST /api/LifePay/SetLifePayOrderPayType */
export async function setLifePayOrderPayType(
  body: API.SetLifePayOrderPayTypeInput,
packages/services/api/typings.d.ts
@@ -517,6 +517,26 @@
    jobType?: string;
  }
  interface AddUpdateUserAccountInput {
    checkChannelId?: string;
    id?: string;
    /** 用户编号 */
    userId?: string;
    lifePayType?: LifePayOrderTypeEnum;
    /** 运营商 */
    operators: string;
    /** 手机号/户号 */
    content?: string;
    /** 省 */
    province?: string;
    /** 市 */
    city?: string;
    /** 拓展字段(电费类型) */
    extraProperties?: string;
    /** 备注 */
    remark?: string;
  }
  interface AddUserCertificationAuditDto {
    id?: string;
    auditNo?: string;
@@ -1126,6 +1146,10 @@
    id?: string;
  }
  interface APIdeleteUserAccountParams {
    id?: string;
  }
  interface APIdeleteUserParams {
    id?: string;
  }
@@ -1466,6 +1490,10 @@
    id?: string;
  }
  interface APIgetLifePayChannlesDtoParams {
    id?: string;
  }
  interface APIgetLifePayWxIndentityParams {
    /** 用户登录凭证 */
    code?: string;
@@ -1563,10 +1591,6 @@
  interface APIgetParkRewardDetailParams {
    id?: string;
  }
  interface APIgetPayStatusByOrderNoParams {
    orderNo?: string;
  }
  interface APIgetPersonalAttestationParams {
@@ -1685,6 +1709,10 @@
    id?: string;
  }
  interface APIgetUserAccountDetailParams {
    id?: string;
  }
  interface APIgetUserCanAuthProductListParams {
    companyId?: string;
  }
@@ -1711,6 +1739,14 @@
  interface APIgetUserFollowInfoParams {
    userId?: string;
  }
  interface APIgetUserLifePayOrderDetailParams {
    orderNo?: string;
  }
  interface APIgetUserLifePayOrderRefundParams {
    id?: string;
  }
  interface APIgetUserListByPhoneNumberParams {
@@ -1866,6 +1902,11 @@
  interface APIsetForUserParams {
    userId?: string;
    permissionName?: string;
  }
  interface APIsetLifePayChannelsStatusParams {
    id?: string;
    status?: LifePayChannelsStatsEnum;
  }
  interface APIsetMessageIsReadParams {
@@ -2946,6 +2987,10 @@
    verificationCode: string;
  }
  interface ChannelsBaseInput {
    checkChannelId?: string;
  }
  type ChargeTypeEnum = 1 | 2;
  interface CheckBatchCreateCompanyUserInput {
@@ -3884,6 +3929,22 @@
    /** 跟进备注 */
    remark?: string;
    status?: CooperationApplyStatusEnum;
  }
  interface CreateEditPayChannelsInput {
    id?: string;
    channlesName?: string;
    channlesNum?: string;
    channlesRate?: number;
    switchType?: LifePaySwitchTypeEnum;
    status?: LifePayChannelsStatsEnum;
    channlesType?: LifePayChannlesTypeEnum;
  }
  interface CreateEditPayChannelsInputPageOutput {
    pageModel?: Pagination;
    objectData?: any;
    data?: CreateEditPayChannelsInput[];
  }
  interface CreateInformationAdvertiseInput {
@@ -6239,6 +6300,49 @@
    charset?: string;
  }
  interface GasOrgTypeValueResponse {
    success?: boolean;
    requestNo?: string;
    partnerId?: string;
    service?: string;
    version?: string;
    protocol?: string;
    context?: string;
    ext?: any;
    code?: string;
    message?: string;
    detail?: string;
    gasSupportMerchantInfos?: GasSupportMerchantInfos[];
  }
  interface GasParValueOutput {
    gasOrgName?: string;
    gasOrgCode?: string;
    parValue?: string[];
    rate?: number;
    comments?: string;
  }
  interface GasParValueResponse {
    success?: boolean;
    requestNo?: string;
    partnerId?: string;
    service?: string;
    version?: string;
    protocol?: string;
    context?: string;
    ext?: any;
    code?: string;
    message?: string;
    detail?: string;
    gasParValue?: GasParValueOutput[];
  }
  interface GasSupportMerchantInfos {
    gasOrgTypeCode?: string;
    gasOrgTypeName?: string;
  }
  interface GeAlltCompanyUsersInput {
    /** 冠名:0其他,1省级,2市级,3区县级 */
    namingType?: number;
@@ -7795,6 +7899,12 @@
    openId?: string;
    attach?: string;
    payAppId?: string;
    checkChannelId?: string;
  }
  interface GetPayStatusByOrderNoInput {
    checkChannelId?: string;
    orderNo?: string;
  }
  interface GetPermissionListResultDto {
@@ -12220,8 +12330,36 @@
  interface LifeElectricDataCreateLifePayOrderInput {
    userId?: string;
    /** 渠道名称 */
    channelId?: string;
    checkChannelId?: string;
    productData?: LifeElectricData;
  }
  interface LifeGasData {
    /** 充值面额,单位为元。 */
    parValue: number;
    /** 天然气公司类型,"zhong_ran"代表中燃燃气,"bei_jing"代表北京燃气。 */
    gasOrgType: string;
    /** 燃气户号 */
    gasAccount: string;
    /** 省份 */
    province: string;
    /** 城市 */
    city?: string;
  }
  interface LifeGasDataCreateLifePayOrderInput {
    userId?: string;
    /** 渠道名称 */
    channelId?: string;
    checkChannelId?: string;
    productData?: LifeGasData;
  }
  type LifePayChannelsStatsEnum = 10 | 20;
  type LifePayChannlesTypeEnum = 10 | 20;
  interface LifePayOrderListOutput {
    id?: string;
@@ -12229,6 +12367,8 @@
    /** 用户手机号 */
    phoneNumber?: string;
    lifePayType?: LifePayTypeEnum;
    /** 渠道名称 */
    channelName?: string;
    lifePayOrderType?: LifePayOrderTypeEnum;
    /** 订单号 */
    orderNo?: string;
@@ -12250,6 +12390,11 @@
    refundCredentialsImgUrl?: string;
    /** 下单时间 */
    creationTime?: string;
    /** 退款时间 */
    refundTime?: string;
    refundApplyRemark?: string;
    refundCheckRemark?: string;
    acoolyOrderNo?: string;
  }
  interface LifePayOrderListOutputPageOutput {
@@ -12258,23 +12403,33 @@
    data?: LifePayOrderListOutput[];
  }
  type LifePayOrderStatusEnum = 10 | 20 | 30;
  type LifePayOrderStatusEnum = 10 | 20 | 30 | 40 | 50 | 60;
  type LifePayOrderTypeEnum = 10 | 20;
  type LifePayOrderTypeEnum = 10 | 20 | 30;
  interface LifePayPhoneMesssageCodeLoginInput {
    checkChannelId?: string;
    /** 手机号 */
    phoneNumber: string;
  }
  interface LifePayRateInput {
    rateType?: LifePayRateTypeEnum;
    rate?: number;
    id?: string;
  }
  interface LifePayRateListOutput {
    rateType?: LifePayRateTypeEnum;
    rate?: number;
    id?: string;
  }
  type LifePayRateTypeEnum = 10 | 20;
  type LifePayRateTypeEnum = 10 | 20 | 30 | 40;
  type LifePayStatusEnum = 10 | 20 | 30 | 40;
  type LifePaySwitchTypeEnum = 10 | 20 | 30;
  type LifePayTypeEnum = 10 | 20;
@@ -12291,6 +12446,9 @@
  interface LifePhoneDataCreateLifePayOrderInput {
    userId?: string;
    /** 渠道名称 */
    channelId?: string;
    checkChannelId?: string;
    productData?: LifePhoneData;
  }
@@ -13569,7 +13727,8 @@
    | 30
    | 31
    | 32
    | 40;
    | 40
    | 42;
  interface OrderChangedBzContentInput {
    outBizNo?: string;
@@ -16101,6 +16260,7 @@
  interface QueryLifePayOrderListInput {
    pageModel?: Pagination;
    lifePayOrderType?: LifePayOrderTypeEnum;
    lifePayType?: LifePayTypeEnum;
    /** 开始支付时间 */
    beginPayTime?: string;
    /** 结束支付时间 */
@@ -16113,6 +16273,9 @@
    endFinishTime?: string;
    /** 用户Id */
    userId?: string;
    /** 搜索关键词 */
    keyWords?: string;
    checkChannelId?: string;
  }
  interface QueryMatchMakingApplyByOrderInput {
@@ -16279,6 +16442,20 @@
    pageModel?: Pagination;
    applyUserId?: string;
    orderUserId?: string;
  }
  interface QueryUserAccountAllListInput {
    checkChannelId?: string;
    /** 用户Id */
    userId?: string;
    lifePayOrderType?: LifePayOrderTypeEnum;
  }
  interface QueryUserAccountListInput {
    pageModel?: Pagination;
    /** 用户Id */
    userId?: string;
    lifePayOrderType?: LifePayOrderTypeEnum;
  }
  interface QueryUserCertificationAuditListInput {
@@ -16777,6 +16954,7 @@
  interface RefundLifePayOrderInput {
    id?: string;
    refundCredentialsImgUrl?: string;
    refundCheckRemark?: string;
  }
  interface RefundOrderContactSignInput {
@@ -16786,6 +16964,14 @@
    userId?: string;
    /** 订单协议Id */
    orderSignId?: string;
  }
  interface RefundUserLifePayOrderInput {
    checkChannelId?: string;
    id?: string;
    /** 用户Id */
    userId?: string;
    refundApplyRemark?: string;
  }
  interface RegisterDto {
@@ -17485,6 +17671,7 @@
    h5Type?: string;
    openId?: string;
    attach?: string;
    checkChannelId?: string;
  }
  interface SetManyContractTemplateHandSignKeyInput {
@@ -19387,6 +19574,32 @@
    staffCount?: number;
  }
  interface UserAccountOutput {
    id?: string;
    lifePayType?: LifePayOrderTypeEnum;
    /** 运营商 */
    operators?: string;
    /** 手机号/户号 */
    content?: string;
    /** 省 */
    province?: string;
    /** 市 */
    city?: string;
    /** 拓展字段(电费类型) */
    extraProperties?: string;
    /** 备注 */
    remark?: string;
    /** 创建时间 */
    creationTime?: string;
    isDeleted?: boolean;
  }
  interface UserAccountOutputPageOutput {
    pageModel?: Pagination;
    objectData?: any;
    data?: UserAccountOutput[];
  }
  interface UserAttentionsDto {
    /** 产品关注数 */
    productCount?: number;
@@ -20285,6 +20498,12 @@
    creationTime?: string;
    /** 退款时间 */
    refundTime?: string;
    /** 退款凭证 */
    refundCredentialsImgUrl?: string;
    refundApplyRemark?: string;
    refundCheckRemark?: string;
    /** 渠道流水号 */
    acoolyOrderNo?: string;
  }
  interface UserLifePayOrderOutputPageOutput {
@@ -20293,6 +20512,18 @@
    data?: UserLifePayOrderOutput[];
  }
  interface UserLifePayOrderRefundOutput {
    /** 订单编号 */
    id?: string;
    /** 订单号 */
    orderNo?: string;
    /** 退款原因 */
    refundApplyRemark?: string;
    /** 后台填写的驳回原因 */
    refundCheckRemark?: string;
    lifePayOrderStatus?: LifePayOrderStatusEnum;
  }
  interface UserListOutput {
    id?: string;
    /** 用户手机号 */
packages/utils/common.ts
@@ -124,3 +124,6 @@
export const hiddenIDNumberForEnd6 = (realIDNumber: string) =>
  realIDNumber.replace(/^(\d+)(.{6})$/, '$1******');
export const hiddenPhoneNumber = (realPhoneNumbe: string) =>
  realPhoneNumbe.replace(/^(.{3})(?:\d+)(.{4})$/, '$1****$2');
pnpm-lock.yaml
Diff too large