Admin 发布的文章

const whiteListSuffixs = [
  '*', // allow all domain suffix
]
async function handleRequest(request) {
  const urlReq = new URL(request?.url)
  let url = urlReq.href?.replace(urlReq.origin+'/', '').trim()
  if (!url) {
    return new Response(`error code 1, usage: ${urlReq.origin}/http(s)://api.example.com`, {status: 400})
  }
  if (0!==url.indexOf('https://') && 0===url.indexOf('https:')) {
    url = url.replace('https:/', 'https://')
  } else if (0!==url.indexOf('http://') && 0===url.indexOf('http:')) {
    url = url.replace('http:/', 'http://')
  }
  let urlTarget
  try {
    urlTarget = new URL(url)
  } catch(e) {
    return new Response(`error code 2, usage: ${urlReq.origin}/http(s)://api.example.com`, {status: 400})
  }
  if (urlTarget?.port) {
    return new Response('port is not allowed', {status: 400})
  }
  const hostname = urlTarget?.hostname
  if (!hostname) {
    return new Response(`error code 3, usage: ${urlReq.origin}/http(s)://api.example.com`, {status: 400})
  }
  let inWhiteList = false
  for (const suffix of whiteListSuffixs) {
    if (hostname.indexOf(suffix) > -1 || '*'===suffix.trim()) {
      inWhiteList = true
      break
    }
  }
  if (!inWhiteList) {
    return new Response( `${urlTarget.hostname} not in white list`, {status: 403} )
  }
  const response = await fetch(url, {
    headers: request.headers,
    body: request.body,
    method: request.method
  })
  let respHeaders = {}
  response.headers.forEach((value, key)=>respHeaders[key] = value)
  if ('*'!==respHeaders['Access-Control-Allow-Origin']?.trim() && '*'!==respHeaders['access-control-allow-origin']?.trim()) {
    respHeaders['Access-Control-Allow-Origin'] = '*'
  }
  return new Response( await response.body , {
    headers: respHeaders,
    status: response.status
  })
}
addEventListener('fetch', event => {
  return event.respondWith(handleRequest(event.request))
})

已知Bug:如果你反代带端口的url,例如http(s)://example.com:3000/path?query=string,它会自动去除端口再请求,变成请求http(s)://example.com/path?query=string

安卓

安卓很简单,用以下代码即可:

<WebView 
  source={{ uri: '包含支付宝的网页,例如有赞手机网页商城' }} 
  originWhitelist={["*"]} // default only http and https
  sharedCookiesEnabled={true}
  onShouldStartLoadWithRequest={navState => {
    if (0===navState.url.indexOf('alipays://') || 0===navState.url.indexOf('alipay://')) {
      Linking.openURL(navState.url)
      return false
    }
    return true // if not alipay scheme, just open
  }}
/>

其中安卓scheme是alipays://,iOS是alipay://

iOS/iPadOS

iOS的话,无法直接在Expo Go上测试支付宝支付,需要更改配置编译.ipa安装包
https://docs.expo.dev/guides/linking/#opening-links-to-other-apps
在./app.json里

"expo": {
  ... ...
  "ios": {
    "supportsTablet": true,
    "infoPlist": {
      "LSApplicationQueriesSchemes": ["alipay", "alipays"]
    },
    "bundleIdentifier": "com.yourdomain.yourproject"
  },
  ... ...
}

编译.ipa安装包并在iOS/iPadOS设备上安装运行的方式:https://medium.com/nerd-for-tech/abbde4086d08
备份文章:https://nftstorage.link/ipfs/bafybeidpjbd7ye5vfxa6vhsrjssfsk5qw6ib2kmnkkbe6lqd3qdrcakpym
上文用的是windows系统,如果你是Mac系统,USB连接iPhone后,可以在Finder左边栏里找到iPhone设备的界面,将.ipa安装包拖到这个界面即可安装到手机

./src/components/NoticeDialog/NoticeDialog.tsx

import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Skeleton, Typography } from "@mui/material";
export type NoticeDialogType = {open: boolean, title: string, content: string}
export function NoticeDialog(props: NoticeDialogType & {close: Function}) {
  return (
    <Dialog
        open={props.open||false}
        aria-labelledby="alert-dialog-title"
        aria-describedby="alert-dialog-description"
        fullWidth
      >
      <DialogTitle id="alert-dialog-title">
        {props.title}
      </DialogTitle>
      <DialogContent>
        <DialogContentText id="alert-dialog-description">
          {props.content}
        </DialogContentText>
      </DialogContent>
      <DialogActions>
        <Button onClick={()=>props.close()}>Close</Button>
      </DialogActions>
    </Dialog>
  )
}

./src/examples/NoticeDialogExample.tsx

import { Button } from "@mui/material"
import { Box } from "@mui/system"
import { useState } from "react"
import { NoticeDialog, NoticeDialogType } from "../../components/NoticeDialog/NoticeDialog" // STEP 1

export default function NoticeDialogExample() {
  const [dialog, setDialog] = useState<NoticeDialogType>() // STEP 2

  // STEP 3
  function openDialog(content: string, title='' ) {
    setDialog({open: true, content, title})
  }

  return (
    <Box className='flex items-center justify-center h-screen'>

      {/* Usage */}
      <Button onClick={()=>openDialog('Dialog content, title can be empty', 'Title')}>Show Dilog</Button>

      {/* STEP 4 */}
      <NoticeDialog title={dialog?.title||''} content={dialog?.content||''} open={dialog?.open||false} close={()=>{
        if (dialog?.open) {
          setDialog({...dialog, open: false})
        }
      }} />
    </Box>
  )
}

TypeScript

https://create-react-app.dev/docs/adding-typescript/

yarn create react-app my-app --template typescript

if use npx, the package manager will be npm

CRACO

(Create React App Configuration Override)

https://www.npmjs.com/package/@craco/craco

yarn add @craco/craco

touch ./craco.config.ts, content:

export {}

in ./package.json

"scripts": {
  "start": "PORT=3000 craco start",
  "build": "craco build",
  "test": "craco test"
},

then

yarn start

MUI

https://mui.com/material-ui/getting-started/installation/

yarn add @mui/material @emotion/react @emotion/styled @mui/icons-material @fontsource/roboto

in ./index.tsx

import '@fontsource/roboto/300.css';
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';

Auto-Dark mode: https://mui.com/zh/material-ui/customization/dark-mode/#system-preference

in ./App/tsx

import React from 'react'
import './App.css'
import { Button } from '@mui/material'
import { createTheme, ThemeProvider } from '@mui/material/styles'
import {useMediaQuery, CssBaseline} from '@mui/material'
function App() {
  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)')
  const theme = React.useMemo(
    () =>
      createTheme({
        palette: {
          mode: prefersDarkMode ? 'dark' : 'light',
        },
      }),
    [prefersDarkMode],
  )
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <Button variant='contained'>MUI Button</Button>
    </ThemeProvider>
  )
}
export default App

Tailwind

https://tailwindcss.com/docs/guides/create-react-app

yarn add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p # generate files tailwind.config.js and postcss.config.js

in ./tailwind.config.js

module.exports = {
  content: [
    "./src/**/*.{js,jsx,ts,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

in ./src/index.css

@tailwind base;
@tailwind components;
@tailwind utilities;

test, in ./src/App.tsx

<h1 className="text-3xl font-bold underline">
  Hello world!
</h1>

yarn start

<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
  <title>生命数字</title>
  <link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.15.7/theme-chalk/index.css">
  <style>
    .number-cell {
      font-size: 1em;
      width: 1em;
      text-align: center
    }

    .el-message-box {
      width: 90% !important;
      max-width: 420px
    }

    body {
      margin: 0 15px;
    }

    * {
      font-family: -apple-system-font, Helvetica Neue, sans-serif;
      font-weight: bold;
    }

    input::-webkit-outer-spin-button,
    input::-webkit-inner-spin-button {
      -webkit-appearance: none
    }
  </style>
</head>

<body>
  <div id="app"
    style="display: none; flex-direction: column; min-height: 70vh; justify-content: center; max-width: 512px; margin: 0 auto;">
    <h1 style="align-self: center; cursor: pointer;" @click="location.reload()">生命数字</h1>
    <div style="display: flex;">
      <el-input @input="inputing" v-model="birthday" placeholder="生日yyyymmdd" type="number" style="margin-right: 10px;">
      </el-input>
      <el-input @input="inputing" v-model="name" placeholder="姓名拼音" style="margin-right: 10px;"></el-input>
      <el-button @click="generate" type="primary">生成</el-button>
    </div>

    <div v-if="y1 || false" id="smsz-1"
      style="border-radius: 4px; display: flex; flex-direction: column; align-items: center; border: 1px solid #DCDFE6; width: fit-content; margin: 20px auto 0 auto; padding: 10px;">

      <svg width="303" height="232" xmlns="http://www.w3.org/2000/svg">
        <g id="Layer_1">
          <title>Layer 1</title>
          <line fill="none" stroke="#000" x1="636" y1="473" x2="636" y2="472" id="svg_4" stroke-linejoin="undefined"
            stroke-linecap="undefined" />
          <line fill="none" stroke="#000" x1="150" y1="66.5" x2="61" y2="231.5" id="svg_1" stroke-linejoin="undefined"
            stroke-linecap="undefined" />
          <line fill="none" stroke="#000" x1="150" y1="66.5" x2="239" y2="231.5" id="svg_2" stroke-linejoin="undefined"
            stroke-linecap="undefined" />
          <line fill="none" stroke="#000" x1="61" y1="230.5" x2="239" y2="230.5" id="svg_3" stroke-linejoin="undefined"
            stroke-linecap="undefined" />
          <line fill="none" stroke="#000" x1="113" y1="136.5" x2="187" y2="136.5" id="svg_5" stroke-linejoin="undefined"
            stroke-linecap="undefined" />
          <line fill="none" x1="85.99999" y1="184.5" x2="213.99999" y2="184.5" id="svg_7" stroke-linejoin="undefined"
            stroke-linecap="undefined" stroke="#000" />
          <line fill="none" stroke="#000" x1="151" y1="137.5" x2="150" y2="230.5" id="svg_9" stroke-linejoin="undefined"
            stroke-linecap="undefined" />
          <line fill="none" stroke="#000" x1="83" y1="66.5" x2="216" y2="66.5" id="svg_11" stroke-linejoin="undefined"
            stroke-linecap="undefined" />
          <line fill="none" x1="129.5" y1="26.5" x2="170.5" y2="26.5" id="svg_12" stroke-linejoin="undefined"
            stroke-linecap="undefined" stroke="#000" />
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            stroke-width="0" id="svg_6" y="214.5" x="95" stroke="#000" fill="#000000">{{a1}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            stroke-width="0" id="svg_8" y="214.5" x="122" stroke="#000" fill="#000000">{{a2}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            stroke-width="0" id="svg_10" y="167.5" x="122" stroke="#000" fill="#000000">{{a5}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            stroke-width="0" id="svg_13" y="214.5" x="169" stroke="#000" fill="#000000">{{a3}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            stroke-width="0" id="svg_14" y="214.5" x="197" stroke="#000" fill="#000000">{{a4}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            stroke-width="0" id="svg_15" y="167.5" x="169" stroke="#000" fill="#000000">{{a6}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            id="svg_16" y="115.5" x="145" stroke-width="0" stroke="#000" fill="#000000">{{a7}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            id="svg_17" y="54.5" x="106" stroke-width="0" stroke="#000" fill="#000000">{{a8}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            id="svg_18" y="54.5" x="185" stroke-width="0" stroke="#000" fill="#000000">{{a9}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            id="svg_19" y="14.5" x="145" stroke-width="0" stroke="#000" fill="#000000">{{a10}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            id="svg_20" y="154.5" x="56" stroke-width="0" stroke="#000" fill="#000000">{{a11}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            id="svg_21" y="154.5" x="29" stroke-width="0" stroke="#000" fill="#000000">{{a12}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            id="svg_22" y="154.5" x="0" stroke-width="0" stroke="#000" fill="#000000">{{a13}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            id="svg_23" y="154.5" x="231" stroke-width="0" stroke="#000" fill="#000000">{{a14}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            id="svg_24" y="154.5" x="261" stroke-width="0" stroke="#000" fill="#000000">{{a15}}</text>
          <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em"
            id="svg_25" y="154.5" x="293" stroke-width="0" stroke="#000" fill="#000000">{{a16}}</text>
        </g>
      </svg>

      <div style="display: flex; width: 100%; margin-top: 20px; justify-content: space-around;">
        <div style="display: flex; flex-direction: column;">
          <div>{{a1}}{{a2}}{{a5}}</div>
          <div>{{a2}}{{a5}}{{a11}}</div>
          <div>{{a1}}{{a5}}{{a12}}</div>
          <div>{{a11}}{{a12}}{{a13}}</div>
        </div>
        <div style="display: flex; flex-direction: column;">
          <div>{{a5}}{{a6}}{{a7}}</div>
          <div>{{a5}}{{a7}}{{a9}}</div>
          <div>{{a6}}{{a7}}{{a8}}</div>
          <div>{{a8}}{{a9}}{{a10}}</div>
        </div>
        <div style="display: flex; flex-direction: column;">
          <div>{{a3}}{{a4}}{{a6}}</div>
          <div>{{a3}}{{a6}}{{a14}}</div>
          <div>{{a4}}{{a6}}{{a15}}</div>
          <div>{{a14}}{{a15}}{{a16}}</div>
        </div>
      </div>

    </div>

    <div v-if="nameInputed || false" style="display: flex; width: fit-content; margin: 20px auto 0 auto;">
      <div id="name-1"
        style="border-radius: 4px; display: flex; flex-direction: column; align-items: left; border: 1px solid #DCDFE6; padding: 10px; margin-right: 20px;">
        <div>使命数:{{shiming}}</div>
        <div>内驱数:{{neiqu}}</div>
        <div>人际数:{{renji}}</div>
        <div>成熟数:{{chengshu}}</div>
      </div>

      <div id="name-2"
        style="border-radius: 4px; display: flex; flex-direction: column; align-items: left; border: 1px solid #DCDFE6; padding: 10px;">
        <div>头脑:{{tounao}}</div>
        <div>情绪:{{qingxu}}</div>
        <div>身体:{{shenti}}</div>
        <div>直觉:{{zhijue}}</div>
      </div>
    </div>

    <div v-if="y1 || false "
      style="border-radius: 4px; display: flex; align-items: center; border: 1px solid #DCDFE6; width: fit-content; margin: 20px auto 0 auto; padding: 10px;">
      <div style="display: flex; flex-direction: column; align-items: center; margin-right: 0.5em;">
        <svg width="192" height="313" xmlns="http://www.w3.org/2000/svg">
          <g id="Layer_1">
            <title>Layer 1</title>
            <g id="svg_32">
              <rect fill="none" stroke="#000" x="0" y="138" width="192" height="41" id="svg_1" />
              <line fill="none" x1="34" y1="137" x2="96" y2="46" id="svg_2" stroke-linejoin="undefined"
                stroke-linecap="undefined" stroke="#000" />
              <line fill="none" stroke="#000" x1="161" y1="138" x2="96" y2="46" id="svg_3" stroke-linejoin="undefined"
                stroke-linecap="undefined" />
              <path fill="none" stroke-linejoin="undefined" stroke-linecap="undefined" opacity="undefined"
                d="m63,95l68,0" id="svg_4" stroke="#000" />
              <line fill="none" stroke="#000" x1="96" y1="138" x2="129" y2="94" id="svg_5" stroke-linejoin="undefined"
                stroke-linecap="undefined" />
              <line fill="none" stroke="#000" x1="66" y1="95" x2="96" y2="137" id="svg_6" stroke-linejoin="undefined"
                stroke-linecap="undefined" />
              <line fill="none" x1="65" y1="46" x2="125" y2="46" id="svg_7" stroke="#000" />
              <line fill="none" stroke="#000" x1="66" y1="46" x2="96" y2="0" id="svg_8" />
              <line fill="none" stroke="#000" x1="126" y1="46" x2="96" y2="1" id="svg_9" />
              <path fill="none" opacity="undefined" d="m34,179l62,91" id="svg_10" stroke="#000" />
              <line fill="none" stroke="#000" x1="159" y1="179" x2="96" y2="271" id="svg_11" />
              <line fill="none" x1="66" y1="224" x2="128" y2="224" id="svg_12" stroke="#000" />
              <line fill="none" stroke="#000" x1="97" y1="179" x2="65" y2="224" id="svg_13" />
              <line fill="none" stroke="#000" x1="130" y1="224" x2="97" y2="178" id="svg_14" />
              <line stroke="#000" fill="none" x1="66" y1="272" x2="126" y2="272" id="svg_15" />
              <line fill="none" stroke="#000" x1="125" y1="273" x2="96" y2="312" id="svg_16" />
              <line fill="none" stroke="#000" x1="66" y1="272" x2="96" y2="313" id="svg_17" />
              <line fill="none" stroke="#000" x1="65" y1="138" x2="65" y2="179" id="svg_18" stroke-linejoin="undefined"
                stroke-linecap="undefined" />
              <line fill="none" stroke="#000" x1="127" y1="138" x2="127" y2="179" id="svg_19"
                stroke-linejoin="undefined" stroke-linecap="undefined" />
              <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP"
                font-size="1em" id="svg_20" y="165" x="28" stroke-width="0" stroke="#000" fill="#000000">{{b1}}</text>
              <text xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="1em" stroke-width="0"
                id="svg_21" y="165" x="92" stroke="#000" fill="#000000">{{b2}}</text>
              <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP"
                font-size="1em" stroke-width="0" id="svg_23" y="165" x="154" stroke="#000" fill="#000000">{{b3}}</text>
              <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP"
                font-size="1em" stroke-width="0" id="svg_24" y="203" x="59" stroke="#000" fill="#000000">{{b8}}</text>
              <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP"
                font-size="1em" stroke-width="0" id="svg_25" y="203" x="124" stroke="#000" fill="#000000">{{b9}}</text>
              <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP"
                font-size="1em" id="svg_26" y="249" x="91" stroke-width="0" stroke="#000" fill="#000000">{{b10}}</text>
              <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP"
                font-size="1em" id="svg_27" y="294" x="91" stroke-width="0" stroke="#000" fill="#000000">{{b11}}</text>
              <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP"
                font-size="1em" stroke-width="0" id="svg_28" y="127" x="59" stroke="#000" fill="#000000">{{b4}}</text>
              <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP"
                font-size="1em" stroke-width="0" id="svg_29" y="128" x="123" stroke="#000" fill="#000000">{{b5}}</text>
              <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP"
                font-size="1em" stroke-width="0" id="svg_30" y="83" x="91" stroke="#000" fill="#000000">{{b6}}</text>
              <text font-weight="bold" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP"
                font-size="1em" id="svg_31" y="34" x="91" stroke-width="0" stroke="#000" fill="#000000">{{b7}}</text>
            </g>
          </g>
        </svg>
      </div>
      <div style="display: flex; flex-direction: column; margin-left: 0.5em;">
        {{this.smsz2Right}}
      </div>
    </div>

    <div v-if="y1" id="liunian" :style="`
      display: grid; grid-auto-flow: column; width: ${Math.ceil(liunian.length/10)*70}px;
      border-radius: 4px; border: 1px solid #DCDFE6; margin: 20px auto 0 auto; padding: 10px;
      grid-template-columns: repeat(auto-fill, 70px);
      grid-template-rows: repeat(9, 1em);
    `">
      <div v-for="(item, index) in liunian" :key="index"
        :style="`color: ${((year18+index)===yearNow?'red':'')}; text-align: center`">
        {{item.year}}/{{item.num}}
      </div>
    </div>

    <el-collapse style="margin-top: 20px;">
      <el-collapse-item title="广告,点开查看">
        <img style="width: 100%; border-radius: 4px;"
          src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-c2fdd86e-36c1-43f7-a906-f89bb382e713/82eb8b91-5a2b-4314-9c66-ed2dd4262d7d.jpg">
      </el-collapse-item>
    </el-collapse>

  </div>
  <script src="https://cdn.staticfile.org/vue/2.6.9/vue.min.js"></script>
  <script src="https://cdn.staticfile.org/element-ui/2.15.7/index.min.js"></script>
  <script>
    const letter2num = {
      A: '1', B: '2', C: '3', D: '4', E: '5', F: '6', G: '7', H: '8', I: '9',
      J: '1', K: '2', L: '3', M: '4', N: '5', O: '6', P: '7', Q: '8', R: '9',
      S: '1', T: '2', U: '3', V: '4', W: '5', X: '6', Y: '7', Z: '8'
    }
    const vm = new Vue({
      el: '#app',
      data() {
        return {
          y1: '', y2: '', y3: '', y4: '', m1: 'm1', m2: 'm2', d1: 'd1', d2: 'd2',
          a1: 'a1', a2: 'a2', a3: 'a3', a4: 'a4', a5: 'a5', a6: 'a6', a7: 'a7', a8: 'a8',
          a9: 'a9', a10: 'a10', a11: 'a11', a12: 'a12', a13: 'a13', a14: 'a14', a15: 'a15', a16: 'a16',
          birthday: '', name: '', nameInputed: false,
          b1: 'b1', b2: 'b2', b3: 'b3', b4: 'b4', b5: 'b5', b6: 'b6', b7: 'b7',
          b8: 'b8', b9: 'b9', b10: 'b10', b11: 'b11', b12: 'b12', b13: 'b13', b14: 'b14',
          smsz2Right: '',
          tounao: 0, qingxu: 0, shenti: 0, zhijue: 0,
          shiming: '', neiqu: '', renji: '', chengshu: '',
          yearNow: new Date().getFullYear(), year18: 0, liunian: []
        }
      },
      methods: {
        inputing() {
          this.y1 = ''
          this.nameInputed = false
        },
        generate() {
          const birthday = this.birthday.trim()
          const intVal = parseInt(birthday)
          if (isNaN(intVal) || intVal < 10000101 || intVal > 99991231) {
            this.$alert('生日范围 10000101 ~ 99991231')
            return
          }
          this.y1 = birthday[0]
          this.y2 = birthday[1]
          this.y3 = birthday[2]
          this.y4 = birthday[3]
          this.m1 = birthday[4]
          this.m2 = birthday[5]
          this.d1 = birthday[6]
          this.d2 = birthday[7]
          this.smsz1()
          this.smsz2()
          this.nameDeal() // must below this.smsz2()

          this.liunian = []
          this.year18 = Number(this.y1 + this.y2 + this.y3 + this.y4) + 18
          for (let i = this.year18; i <= this.year18 + (53 - 18); i++) {
            this.liunian.push({ age: i - this.year18 + 18, num: addAndAdd(i + this.m1 + this.m2 + this.d1 + this.d2), year: i })
          }
        },
        smsz2() {
          this.b1 = addAndAdd(this.m1 + this.m2)
          this.b2 = addAndAdd(this.d1 + this.d2)
          this.b3 = addAndAdd(this.y1 + this.y2 + this.y3 + this.y4)
          this.b4 = addAndAdd(this.b1 + this.b2)
          this.b5 = addAndAdd(this.b2 + this.b3)
          this.b6 = addAndAdd(this.b4 + this.b5)
          this.b7 = addAndAdd(this.b1 + this.b3)
          this.b8 = Math.abs(Number(this.b1) - Number(this.b2)) + ''
          this.b9 = Math.abs(Number(this.b2) - Number(this.b3)) + ''
          this.b10 = Math.abs(Number(this.b8) - Number(this.b9)) + ''
          this.b11 = Math.abs(Number(this.b1) - Number(this.b3)) + ''
          this.b12 = addAndAdd(this.y1 + this.y2 + this.y3 + this.y4 + this.m1 + this.m2 + this.d1 + this.d2, 2)
          this.smsz2Right = this.b12
          this.b14 = this.b12 // 用于计算成熟数
          if (this.b12.length > 1) {
            this.b13 = addAndAdd(Number(this.b12[0]) + Number(this.b12[1]), 2)
            this.smsz2Right += `/${this.b13}`
            this.b14 = this.b13
          }
          if (this.b13.length > 1) {
            this.b14 = addAndAdd(Number(this.b13[0]) + Number(this.b13[1]), 2)
            this.smsz2Right += `/${this.b14}`
          }
        },
        smsz1() {
          this.a1 = addAndAdd(this.d1 + this.d2)
          this.a2 = addAndAdd(this.m1 + this.m2)
          this.a3 = addAndAdd(this.y1 + this.y2)
          this.a4 = addAndAdd(this.y3 + this.y4)
          this.a5 = addAndAdd(this.a1 + this.a2)
          this.a6 = addAndAdd(this.a3 + this.a4)
          this.a7 = addAndAdd(this.a5 + this.a6)
          this.a8 = addAndAdd(this.a6 + this.a7)
          this.a9 = addAndAdd(this.a5 + this.a7)
          this.a10 = addAndAdd(this.a8 + this.a9)
          this.a11 = addAndAdd(this.a2 + this.a5)
          this.a12 = addAndAdd(this.a1 + this.a5)
          this.a13 = addAndAdd(this.a11 + this.a12)
          this.a14 = addAndAdd(this.a3 + this.a6)
          this.a15 = addAndAdd(this.a4 + this.a6)
          this.a16 = addAndAdd(this.a14 + this.a15)
        },

        nameDeal() {
          const name = this.name.trim().toUpperCase()
          let yuanfu = ''
          let yuanyin = ''
          let fuyin = ''
          for (let i = 0; i < name.length; i++) {
            const charCode = letter2num[name[i]]
            if (!charCode) {
              continue
            }
            yuanfu += charCode
            if ('A' === name[i] || 'O' === name[i] || 'E' === name[i] || 'I' === name[i] || 'U' === name[i] || 'V' === name[i]) {
              yuanyin += charCode
            } else {
              fuyin += charCode
            }
          }
          this.nameInputed = yuanfu.length > 0

          this.shiming = ''
          this.neiqu = ''
          this.renji = ''
          this.chengshu = ''
          let cache = ''

          cache = addAndAdd(yuanfu, 2, 0, false, true)
          this.shiming += cache
          while (cache.length > 1) {
            cache = addAndAdd(Number(cache[0]) + Number(cache[1]), 2, 0, false)
            this.shiming += '/' + cache
          }
          const c = cache // c用于计算成熟数

          cache = addAndAdd(yuanyin, 2, 0, false, true)
          this.neiqu += cache
          while (cache.length > 1) {
            cache = addAndAdd(Number(cache[0]) + Number(cache[1]), 2, 0)
            this.neiqu += '/' + cache
          }

          cache = addAndAdd(fuyin, 2, 0, false, true)
          this.renji += cache
          while (cache.length > 1) {
            cache = addAndAdd(Number(cache[0]) + Number(cache[1]), 2, 0)
            this.renji += '/' + cache
          }

          this.chengshu = addAndAdd(Number(this.b14) + Number(c))

          this.tounao = 0
          this.qingxu = 0
          this.shenti = 0
          this.zhijue = 0
          for (let i = 0; i < yuanfu.length; i++) {
            if ('1' === yuanfu[i] || '8' === yuanfu[i]) {
              this.tounao++
            } else if ('2' === yuanfu[i] || '3' === yuanfu[i] || '6' === yuanfu[i]) {
              this.qingxu++
            } else if ('4' === yuanfu[i] || '5' === yuanfu[i]) {
              this.shenti++
            } else if ('7' === yuanfu[i] || '9' === yuanfu[i]) {
              this.zhijue++
            }
          }
        }
      },
      mounted() {
        document.getElementById('app').style.display = 'flex'
      }
    })
    function addAndAdd(number, length = 1, zero = 5, log = false, sumFirst = false) { // length: number; zero: number, 5|0
      number = Number(number)
      if (log) {
        console.log(number, length, zero)
      }
      if (isNaN(number)) {
        return '0'
      } else if (0 === number) {
        return zero + ''
      }
      const string = number + ''
      let sum = 0
      for (let i = 0; i < string.length; i++) {
        sum += Number(string[i])
      }
      if (string.length <= length) {
        if (sumFirst) {
          return sum + ''
        }
        return string
      }
      return addAndAdd(sum, length, zero, log)
    }
  </script>
</body>

</html>