小程序可以加载账单
This commit is contained in:
		
							
								
								
									
										170
									
								
								palette.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								palette.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,170 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  red: {
 | 
			
		||||
    1: '#FFECE8',
 | 
			
		||||
    2: '#FDCDC5',
 | 
			
		||||
    3: '#FBACA3',
 | 
			
		||||
    4: '#F98981',
 | 
			
		||||
    5: '#F76560',
 | 
			
		||||
    6: '#F53F3F',
 | 
			
		||||
    7: '#CB272D',
 | 
			
		||||
    8: '#A1151E',
 | 
			
		||||
    9: '#770813',
 | 
			
		||||
    10: '#4D000A'
 | 
			
		||||
  },
 | 
			
		||||
  orangered: {
 | 
			
		||||
    1: '#FFF3E8',
 | 
			
		||||
    2: '#FDDDC3',
 | 
			
		||||
    3: '#FCC59F',
 | 
			
		||||
    4: '#FAAC7B',
 | 
			
		||||
    5: '#F99057',
 | 
			
		||||
    6: '#F77234',
 | 
			
		||||
    7: '#CC5120',
 | 
			
		||||
    8: '#A23511',
 | 
			
		||||
    9: '#771F06',
 | 
			
		||||
    10: '#4D0E00'
 | 
			
		||||
  },
 | 
			
		||||
  orange: {
 | 
			
		||||
    1: '#FFF7E8',
 | 
			
		||||
    2: '#FFE4BA',
 | 
			
		||||
    3: '#FFCF8B',
 | 
			
		||||
    4: '#FFB65D',
 | 
			
		||||
    5: '#FF9A2E',
 | 
			
		||||
    6: '#FF7D00',
 | 
			
		||||
    7: '#D25F00',
 | 
			
		||||
    8: '#A64500',
 | 
			
		||||
    9: '#792E00',
 | 
			
		||||
    10: '#4D1B00'
 | 
			
		||||
  },
 | 
			
		||||
  gold: {
 | 
			
		||||
    1: '#FFFCE8',
 | 
			
		||||
    2: '#FDF4BF',
 | 
			
		||||
    3: '#FCE996',
 | 
			
		||||
    4: '#FADC6D',
 | 
			
		||||
    5: '#F9CC45',
 | 
			
		||||
    6: '#F7BA1E',
 | 
			
		||||
    7: '#CC9213',
 | 
			
		||||
    8: '#A26D0A',
 | 
			
		||||
    9: '#774B04',
 | 
			
		||||
    10: '#4D2D00'
 | 
			
		||||
  },
 | 
			
		||||
  yellow: {
 | 
			
		||||
    1: '#FEFFE8',
 | 
			
		||||
    2: '#FEFEBE',
 | 
			
		||||
    3: '#FDFA94',
 | 
			
		||||
    4: '#FCF26B',
 | 
			
		||||
    5: '#FBE842',
 | 
			
		||||
    6: '#FADC19',
 | 
			
		||||
    7: '#CFAF0F',
 | 
			
		||||
    8: '#A38408',
 | 
			
		||||
    9: '#785D03',
 | 
			
		||||
    10: '#4D3800'
 | 
			
		||||
  },
 | 
			
		||||
  lime: {
 | 
			
		||||
    1: '#FCFFE8',
 | 
			
		||||
    2: '#EDF8BB',
 | 
			
		||||
    3: '#DCF190',
 | 
			
		||||
    4: '#C9E968',
 | 
			
		||||
    5: '#B5E241',
 | 
			
		||||
    6: '#9FDB1D',
 | 
			
		||||
    7: '#7EB712',
 | 
			
		||||
    8: '#5F940A',
 | 
			
		||||
    9: '#437004',
 | 
			
		||||
    10: '#2A4D00'
 | 
			
		||||
  },
 | 
			
		||||
  green: {
 | 
			
		||||
    1: '#E8FFEA',
 | 
			
		||||
    2: '#AFF0B5',
 | 
			
		||||
    3: '#7BE188',
 | 
			
		||||
    4: '#4CD263',
 | 
			
		||||
    5: '#23C343',
 | 
			
		||||
    6: '#00B42A',
 | 
			
		||||
    7: '#009A29',
 | 
			
		||||
    8: '#008026',
 | 
			
		||||
    9: '#006622',
 | 
			
		||||
    10: '#004D1C'
 | 
			
		||||
  },
 | 
			
		||||
  sggreen: {
 | 
			
		||||
    1: '#DCF5E9',
 | 
			
		||||
    2: '#95E8C1',
 | 
			
		||||
    3: '#69DBAA',
 | 
			
		||||
    4: '#42CF96',
 | 
			
		||||
    5: '#1FC286',
 | 
			
		||||
    6: '#00B578',
 | 
			
		||||
    7: '#008F64',
 | 
			
		||||
    8: '#00694D',
 | 
			
		||||
    9: '#004233',
 | 
			
		||||
    10: '#001C16'
 | 
			
		||||
  },
 | 
			
		||||
  cyan: {
 | 
			
		||||
    1: '#E8FFFB',
 | 
			
		||||
    2: '#B7F4EC',
 | 
			
		||||
    3: '#89E9E0',
 | 
			
		||||
    4: '#5EDFD6',
 | 
			
		||||
    5: '#37D4CF',
 | 
			
		||||
    6: '#14C9C9',
 | 
			
		||||
    7: '#0DA5AA',
 | 
			
		||||
    8: '#07828B',
 | 
			
		||||
    9: '#03616C',
 | 
			
		||||
    10: '#00424D'
 | 
			
		||||
  },
 | 
			
		||||
  blue: {
 | 
			
		||||
    1: '#E8F7FF',
 | 
			
		||||
    2: '#C3E7FE',
 | 
			
		||||
    3: '#9FD4FD',
 | 
			
		||||
    4: '#7BC0FC',
 | 
			
		||||
    5: '#57A9FB',
 | 
			
		||||
    6: '#3491FA',
 | 
			
		||||
    7: '#206CCF',
 | 
			
		||||
    8: '#114BA3',
 | 
			
		||||
    9: '#063078',
 | 
			
		||||
    10: '#001A4D'
 | 
			
		||||
  },
 | 
			
		||||
  arcoblue: {
 | 
			
		||||
    1: '#E8F3FF',
 | 
			
		||||
    2: '#BEDAFF',
 | 
			
		||||
    3: '#94BFFF',
 | 
			
		||||
    4: '#6AA1FF',
 | 
			
		||||
    5: '#4080FF',
 | 
			
		||||
    6: '#165DFF',
 | 
			
		||||
    7: '#0E42D2',
 | 
			
		||||
    8: '#072CA6',
 | 
			
		||||
    9: '#031A79',
 | 
			
		||||
    10: '#000D4D'
 | 
			
		||||
  },
 | 
			
		||||
  purple: {
 | 
			
		||||
    1: '#F5E8FF',
 | 
			
		||||
    2: '#DDBEF6',
 | 
			
		||||
    3: '#C396ED',
 | 
			
		||||
    4: '#A871E3',
 | 
			
		||||
    5: '#8D4EDA',
 | 
			
		||||
    6: '#722ED1',
 | 
			
		||||
    7: '#551DB0',
 | 
			
		||||
    8: '#3C108F',
 | 
			
		||||
    9: '#27066E',
 | 
			
		||||
    10: '#16004D'
 | 
			
		||||
  },
 | 
			
		||||
  magenta: {
 | 
			
		||||
    1: '#FFE8F1',
 | 
			
		||||
    2: '#FDC2DB',
 | 
			
		||||
    3: '#FB9DC7',
 | 
			
		||||
    4: '#F979B7',
 | 
			
		||||
    5: '#F754A8',
 | 
			
		||||
    6: '#F5319D',
 | 
			
		||||
    7: '#CB1E83',
 | 
			
		||||
    8: '#A11069',
 | 
			
		||||
    9: '#77064F',
 | 
			
		||||
    10: '#4D0034'
 | 
			
		||||
  },
 | 
			
		||||
  gray: {
 | 
			
		||||
    1: '#f7f8fa',
 | 
			
		||||
    2: '#f2f3f5',
 | 
			
		||||
    3: '#e5e6eb',
 | 
			
		||||
    4: '#c9cdd4',
 | 
			
		||||
    5: '#a9aeb8',
 | 
			
		||||
    6: '#86909c',
 | 
			
		||||
    7: '#6b7785',
 | 
			
		||||
    8: '#4e5969',
 | 
			
		||||
    9: '#272e3b',
 | 
			
		||||
    10: '#1d2129'
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										54
									
								
								src/components/CompanyNoPark/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/components/CompanyNoPark/index.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
import { BaseResponse } from "@/shared/model-components";
 | 
			
		||||
import {tenementSearchChoice, tenementSearchChoiceByName} from "@q/charge";
 | 
			
		||||
import { useQuery } from "@tanstack/react-query";
 | 
			
		||||
import { isCorrectResult } from "@u/asyncs";
 | 
			
		||||
import { Select } from "antd";
 | 
			
		||||
import { equals } from "ramda";
 | 
			
		||||
import { useState } from "react";
 | 
			
		||||
import { useDebounce } from "react-use";
 | 
			
		||||
import 'twin.macro'
 | 
			
		||||
 | 
			
		||||
interface P {
 | 
			
		||||
    parkId?: string,
 | 
			
		||||
    disabled?: boolean
 | 
			
		||||
    allowClear?: boolean,
 | 
			
		||||
    placeholder?: string,
 | 
			
		||||
    onChange?: (e: any) => void,
 | 
			
		||||
    api?: (keyword: string) => Promise<BaseResponse & { tenements: { fullName: string; id: string; park: string; shortName: string; parkName: string }[] }>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const CompanyNoPark = (props: P) => {
 | 
			
		||||
    const [searchTenement, setSearchTenement] = useState('');
 | 
			
		||||
    const [searchTenementTemp, setSearchTenementTemp] = useState('');
 | 
			
		||||
 | 
			
		||||
    // 商户列表
 | 
			
		||||
    const { data: tenements, status: tenementStatus } = useQuery(
 | 
			
		||||
        ['tenements-getSelectList', searchTenement],
 | 
			
		||||
        () => props.api ? props.api(searchTenement) : props.parkId ? tenementSearchChoice(props.parkId, searchTenement) : tenementSearchChoiceByName(searchTenement),
 | 
			
		||||
        { enabled: !!searchTenement, select: res => (isCorrectResult(res) ? res.tenements : []) }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    useDebounce(() => setSearchTenement(searchTenementTemp), 800, [searchTenementTemp]);
 | 
			
		||||
    return (
 | 
			
		||||
            <Select
 | 
			
		||||
                tw="w-full"
 | 
			
		||||
                showSearch
 | 
			
		||||
                disabled={props.disabled}
 | 
			
		||||
                allowClear={props.allowClear}
 | 
			
		||||
                // showArrow={false}
 | 
			
		||||
                filterOption={false}
 | 
			
		||||
                notFoundContent={null}
 | 
			
		||||
                onChange={e => props.onChange && props.onChange(e)}
 | 
			
		||||
                onSearch={setSearchTenementTemp}
 | 
			
		||||
                defaultActiveFirstOption={false}
 | 
			
		||||
                placeholder={props.placeholder || "请输入商户全称检索"}
 | 
			
		||||
                loading={equals(tenementStatus, 'loading')}
 | 
			
		||||
                options={(tenements || []).map(d => ({ value: d.id, label: `${d.parkName ?( d.parkName || '') + ' - ' : ""} ${d.fullName}` }))}
 | 
			
		||||
                dropdownStyle={{minWidth: "250px", width: 'auto'}}
 | 
			
		||||
            />
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default CompanyNoPark;
 | 
			
		||||
							
								
								
									
										110
									
								
								src/components/TablePlus/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/components/TablePlus/index.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
// @ts-ignore
 | 
			
		||||
import {ProTable} from '@ant-design/pro-components';
 | 
			
		||||
import React, {ReactNode} from "react";
 | 
			
		||||
import "twin.macro"
 | 
			
		||||
import {ExpandableConfig} from "antd/lib/table/interface";
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  columns: any[],
 | 
			
		||||
  dataSource: any[],
 | 
			
		||||
  localStorageKey: string,
 | 
			
		||||
  rowKey: (value: any) => string,
 | 
			
		||||
  rowClassName?: (record: any, index: number) => string,
 | 
			
		||||
  loading: boolean,
 | 
			
		||||
  pagination?:false | {
 | 
			
		||||
    total: number,
 | 
			
		||||
    current: number,
 | 
			
		||||
    onChange: (value: number) => void,
 | 
			
		||||
  },
 | 
			
		||||
  scroll?: {
 | 
			
		||||
    x?: number|string,
 | 
			
		||||
    y?: number|string
 | 
			
		||||
  }
 | 
			
		||||
  toolbarRender?: ReactNode[],
 | 
			
		||||
  toolbar?: ReactNode,
 | 
			
		||||
  expandable?: ExpandableConfig<any>
 | 
			
		||||
  rowSelection?:any,
 | 
			
		||||
  size?: string,
 | 
			
		||||
  customPagination?: boolean,
 | 
			
		||||
  footer?: ReactNode,
 | 
			
		||||
  // search?: ReactNode
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function (props: Props) {
 | 
			
		||||
  const {
 | 
			
		||||
    columns = [],
 | 
			
		||||
    dataSource = [],
 | 
			
		||||
    loading,
 | 
			
		||||
    rowKey,
 | 
			
		||||
    pagination= { total: 0,  current: 1, onChange: () => {}, showSizeChanger: false },
 | 
			
		||||
    scroll,
 | 
			
		||||
    localStorageKey,
 | 
			
		||||
    toolbarRender,
 | 
			
		||||
    toolbar,
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
			
		||||
    size,
 | 
			
		||||
    customPagination,
 | 
			
		||||
    footer,
 | 
			
		||||
    ...other
 | 
			
		||||
    // search
 | 
			
		||||
  } = props
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <style>
 | 
			
		||||
        {
 | 
			
		||||
          `
 | 
			
		||||
            .ant-table-fixed-left table,
 | 
			
		||||
            .ant-table-fixed-right table {
 | 
			
		||||
              width: min-content;
 | 
			
		||||
            }
 | 
			
		||||
            .ant-pro-table-list-toolbar-left, .ant-pro-table-list-toolbar-title {
 | 
			
		||||
              flex: 1 !important;
 | 
			
		||||
            }
 | 
			
		||||
            .ant-pro-table-list-toolbar-right {
 | 
			
		||||
              flex: 0 !important;
 | 
			
		||||
              flex-wrap: nowrap;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            .ant-pro-table-list-toolbar-container {
 | 
			
		||||
              padding-top: 0;
 | 
			
		||||
            }
 | 
			
		||||
          `
 | 
			
		||||
        }
 | 
			
		||||
      </style>
 | 
			
		||||
      <ProTable
 | 
			
		||||
        columns={columns}
 | 
			
		||||
        columnsState={{
 | 
			
		||||
          persistenceKey: localStorageKey,
 | 
			
		||||
          persistenceType: 'sessionStorage',
 | 
			
		||||
        }}
 | 
			
		||||
        tableExtraRender={null}
 | 
			
		||||
        cardProps={false}
 | 
			
		||||
        search={false}
 | 
			
		||||
        rowKey={rowKey}
 | 
			
		||||
        tableAlertRender={false}
 | 
			
		||||
        loading={loading}
 | 
			
		||||
        columnEmptyText={""}
 | 
			
		||||
        options={{
 | 
			
		||||
          setting: true,
 | 
			
		||||
          reload: false,
 | 
			
		||||
          density: false,
 | 
			
		||||
        }}
 | 
			
		||||
        scroll={scroll}
 | 
			
		||||
        dataSource={dataSource}
 | 
			
		||||
        pagination={customPagination ? false : (pagination === false ? pagination : {
 | 
			
		||||
          size: "default",
 | 
			
		||||
          pageSize: 20,
 | 
			
		||||
          showSizeChanger: false,
 | 
			
		||||
          ...pagination
 | 
			
		||||
        })}
 | 
			
		||||
        toolBarRender={() => toolbarRender}
 | 
			
		||||
        toolbar={{
 | 
			
		||||
          title: <div tw={"w-full"}> {toolbar} </div>
 | 
			
		||||
        }}
 | 
			
		||||
        {...other}
 | 
			
		||||
      />
 | 
			
		||||
      {footer}
 | 
			
		||||
    </>
 | 
			
		||||
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								src/components/accountingFooter/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/components/accountingFooter/index.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
import { Pagination } from "antd";
 | 
			
		||||
import { ReactNode } from "react";
 | 
			
		||||
import "twin.macro"
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
    content: ReactNode,
 | 
			
		||||
    current: number,
 | 
			
		||||
    onChange: (value) => void,
 | 
			
		||||
    total: number,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function(props: Props) {
 | 
			
		||||
    const { content, current, total, onChange } = props;
 | 
			
		||||
    return <div tw="flex flex-row justify-end items-center w-full mt-3">
 | 
			
		||||
        <div tw="mr-4"> 求和金额: {content} </div>
 | 
			
		||||
        <Pagination 
 | 
			
		||||
            pageSize={20}
 | 
			
		||||
            current={current}
 | 
			
		||||
            total={total}
 | 
			
		||||
            showTotal={total => <div> 合计 {total}条 </div>}
 | 
			
		||||
            onChange={onChange}
 | 
			
		||||
        />
 | 
			
		||||
    </div>
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										75
									
								
								src/components/business/Daemon.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/components/business/Daemon.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
import { useAuthenticated } from '@h/useAuthenticated';
 | 
			
		||||
import { logout } from '@q/session';
 | 
			
		||||
import { useLayoutStore } from '@st/layout_store';
 | 
			
		||||
import { useSessionStore } from '@st/session_store';
 | 
			
		||||
import { norNilOrEmpty } from '@u/funcs';
 | 
			
		||||
import { notification } from 'antd';
 | 
			
		||||
import dayjs from 'dayjs';
 | 
			
		||||
import { lte, not, range } from 'ramda';
 | 
			
		||||
import { FC, useCallback, useMemo } from 'react';
 | 
			
		||||
import { useNavigate } from 'react-router-dom';
 | 
			
		||||
import { useInterval } from 'react-use';
 | 
			
		||||
import 'twin.macro';
 | 
			
		||||
import { useAutoAsyncFn } from '@h/useAutoAsyncFn';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 这是应用中的伺服精灵组件,不产生任何渲染输出,只用来负责控制应用的状态以及永久循环事件。
 | 
			
		||||
 */
 | 
			
		||||
export const Daemon: FC = () => {
 | 
			
		||||
  const isAuthenticated = useAuthenticated();
 | 
			
		||||
  const navigate = useNavigate();
 | 
			
		||||
  const [, logoutUser] = useAutoAsyncFn(logout);
 | 
			
		||||
  const warningDisplayed = useSessionStore.use.warningDisplayed();
 | 
			
		||||
  const showMask = useLayoutStore.use.showMask();
 | 
			
		||||
  const hideMask = useLayoutStore.use.hideMask();
 | 
			
		||||
 | 
			
		||||
  const unauthenticated = useMemo(() => {
 | 
			
		||||
    return not(isAuthenticated);
 | 
			
		||||
  }, [isAuthenticated]);
 | 
			
		||||
 | 
			
		||||
  const checkAndLogout = useCallback(() => {
 | 
			
		||||
    // 这里务必实时获取LocalStorage中保存的内容,如果依靠select函数,那么在各个计时中,数据将得不到变化。
 | 
			
		||||
    // ! 这里的内容在修改的时候,务必与useSession Hook中的LocalStorage使用方法、键名保持一致。
 | 
			
		||||
    const expiresAt = localStorage.getItem('expires') ?? '2000-01-01';
 | 
			
		||||
    const isLoggedInLocal = norNilOrEmpty(localStorage.getItem('token') ?? null);
 | 
			
		||||
    const isTokenExpiredLocal = dayjs(expiresAt).isBefore(dayjs());
 | 
			
		||||
    const difference = dayjs(expiresAt).diff(dayjs(), 'minute');
 | 
			
		||||
 | 
			
		||||
    [1, 5, 10].forEach((minutes, index) => {
 | 
			
		||||
      const warningDisplays = useSessionStore.getState().expireWarning;
 | 
			
		||||
      if (lte(difference, minutes) && not(warningDisplays[index])) {
 | 
			
		||||
        notification.warning({
 | 
			
		||||
          message: '登录会话即将结束',
 | 
			
		||||
          description: (
 | 
			
		||||
            <div>
 | 
			
		||||
              您的登录会话即将在<span tw="mx-2 text-xl text-red-6">{minutes}分钟</span>
 | 
			
		||||
              内结束,请尽快重新登录。
 | 
			
		||||
            </div>
 | 
			
		||||
          ),
 | 
			
		||||
          placement: 'bottomRight',
 | 
			
		||||
          duration: 10
 | 
			
		||||
        });
 | 
			
		||||
        range(index, 3).forEach(s => warningDisplayed(s));
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (not(isLoggedInLocal) || isTokenExpiredLocal) {
 | 
			
		||||
      showMask();
 | 
			
		||||
      notification.warning({
 | 
			
		||||
        message: '登录会话结束',
 | 
			
		||||
        description: <div>您的登录会话已经结束,请重新登录。</div>,
 | 
			
		||||
        placement: 'bottomRight',
 | 
			
		||||
        duration: 5,
 | 
			
		||||
        onClose: async () => {
 | 
			
		||||
          await logoutUser();
 | 
			
		||||
          navigate('/login', { replace: true });
 | 
			
		||||
          hideMask();
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
  useInterval(checkAndLogout, unauthenticated ? null : 30000);
 | 
			
		||||
 | 
			
		||||
  return null;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										14
									
								
								src/components/business/GlobalMask.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/components/business/GlobalMask.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
import { useLayoutStore } from '@st/layout_store';
 | 
			
		||||
import { FC } from 'react';
 | 
			
		||||
import tw, { styled } from 'twin.macro';
 | 
			
		||||
 | 
			
		||||
const Mask = styled.div(({ visible }: { visible: boolean }) => [
 | 
			
		||||
  visible ? tw`block` : tw`hidden`,
 | 
			
		||||
  tw`fixed top-0 left-0 w-screen h-screen bg-black opacity-50 z-[1001]`
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
export const GlobalMask: FC = () => {
 | 
			
		||||
  const visible = useLayoutStore.use.maskVisible();
 | 
			
		||||
 | 
			
		||||
  return <Mask visible={visible} />;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										61
									
								
								src/components/company/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/components/company/index.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
// 用于生成一个根据关键字搜索商户的输入选择框
 | 
			
		||||
import { BaseResponse } from "@/shared/model-components";
 | 
			
		||||
import { tenementSearchChoice } from "@q/charge";
 | 
			
		||||
import { useQuery } from "@tanstack/react-query";
 | 
			
		||||
import { isCorrectResult } from "@u/asyncs";
 | 
			
		||||
import { Select } from "antd";
 | 
			
		||||
import { useState } from "react";
 | 
			
		||||
import { useDebounce } from "react-use";
 | 
			
		||||
import 'twin.macro'
 | 
			
		||||
 | 
			
		||||
interface P {
 | 
			
		||||
    parkId?: string,
 | 
			
		||||
    tenement?: string,
 | 
			
		||||
    disabled?: boolean
 | 
			
		||||
    allowClear?: boolean
 | 
			
		||||
    placeholder?: string
 | 
			
		||||
    onChange?: (e) => void,
 | 
			
		||||
    valueKey?: string,
 | 
			
		||||
    labelKey?: string,
 | 
			
		||||
    api?: (parkId: string, tenement: string) => Promise<BaseResponse & {
 | 
			
		||||
        tenements: {
 | 
			
		||||
            fullName: string;
 | 
			
		||||
            id: string;
 | 
			
		||||
            park: string;
 | 
			
		||||
            shortName: string;
 | 
			
		||||
        }[];
 | 
			
		||||
    }>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const Company = (props: P) => {
 | 
			
		||||
    const { parkId } = props;
 | 
			
		||||
    const [searchTenement, setSearchTenement] = useState('');
 | 
			
		||||
    const [searchTenementTemp, setSearchTenementTemp] = useState('');
 | 
			
		||||
 | 
			
		||||
    const request = props.api ? props.api :  tenementSearchChoice
 | 
			
		||||
    // 商户列表
 | 
			
		||||
    const { data: tenements } = useQuery(
 | 
			
		||||
        ['tenements-choice', parkId, searchTenement],
 | 
			
		||||
        () => request(parkId, searchTenement),
 | 
			
		||||
        { enabled: !!searchTenement && !!parkId, select: res => (isCorrectResult(res) ? res.tenements : []) }
 | 
			
		||||
    );
 | 
			
		||||
    useDebounce(() => setSearchTenement(searchTenementTemp), 800, [searchTenementTemp]);
 | 
			
		||||
    return (
 | 
			
		||||
        <Select
 | 
			
		||||
            tw="w-full"
 | 
			
		||||
            showSearch
 | 
			
		||||
            allowClear={props.allowClear}
 | 
			
		||||
            filterOption={false}
 | 
			
		||||
            notFoundContent={null}
 | 
			
		||||
            onChange={e => { props.onChange && props.onChange(e) }}
 | 
			
		||||
            onSearch={setSearchTenementTemp}
 | 
			
		||||
            defaultActiveFirstOption={false}
 | 
			
		||||
            value={props.tenement}
 | 
			
		||||
            placeholder={props.placeholder || "请输入商户名称检索"}
 | 
			
		||||
            options={(tenements || []).map(d => ({ value: props.valueKey ? d[props.valueKey]: d.id, label: props.labelKey ? d[props.labelKey] : d.fullName }))}
 | 
			
		||||
        />
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default Company;
 | 
			
		||||
							
								
								
									
										147
									
								
								src/components/hoc/AuthRequired.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								src/components/hoc/AuthRequired.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
			
		||||
//@ts-nocheck
 | 
			
		||||
import { useAuthenticated } from '@h/useAuthenticated';
 | 
			
		||||
import { useAuthorization } from '@h/useAuthorization';
 | 
			
		||||
import { isEmpty, mergeDeepLeft } from 'ramda';
 | 
			
		||||
import { Component, FunctionComponent, PropsWithChildren } from 'react';
 | 
			
		||||
import { Navigate, useLocation } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于配置高阶组件`requireAuthorize`的认证及权限配置。
 | 
			
		||||
 *
 | 
			
		||||
 * 当配置项`all`被设置的时候,配置项`any`的内容将被忽略。如果不设置任何`all`或者`any`配置项,那么将仅判断用户是否已经登录。
 | 
			
		||||
 */
 | 
			
		||||
export interface AuthorizeOptions {
 | 
			
		||||
  /**
 | 
			
		||||
   * 配置指定组件要求用户必须拥有的全部权限。
 | 
			
		||||
   */
 | 
			
		||||
  all?: number[];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 配置指定组件要求用户必须至少拥有其中一项的权限。
 | 
			
		||||
   */
 | 
			
		||||
  any?: number[];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 设定当用户权限认证失败或者用户没有登录的时候,是否跳转到登录页面。
 | 
			
		||||
   */
 | 
			
		||||
  toLogin?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 对被包裹组件进行用户权限验证的组件。
 | 
			
		||||
 * ! 用户如果没有登录,那么验证将始终是失败的。
 | 
			
		||||
 *
 | 
			
		||||
 * @param param0 认证成功状态下路由转移到的组件以及所需要的权限声明
 | 
			
		||||
 * @returns 转向实际路由或者重定向到登录页面
 | 
			
		||||
 */
 | 
			
		||||
export const AuthRequired: FC<PropsWithChildren<AuthorizeOptions>> = ({
 | 
			
		||||
  all,
 | 
			
		||||
  any,
 | 
			
		||||
  toLogin,
 | 
			
		||||
  children
 | 
			
		||||
}: PropsWithChildren<AuthorizeOptions>) => {
 | 
			
		||||
  const requiredAllPrivileges = all ?? [];
 | 
			
		||||
  const requiredAnyPrivileges = any ?? [];
 | 
			
		||||
  const redirectToLogin = toLogin ?? false;
 | 
			
		||||
  const isAuthenticated = useAuthenticated();
 | 
			
		||||
  const { hasAll, hasAny } = useAuthorization();
 | 
			
		||||
  const location = useLocation();
 | 
			
		||||
 | 
			
		||||
  // 注意,这里的判断逻辑是:
 | 
			
		||||
  // 如果所需全部权限和任意权限都为空,即不需要任何权限,那么判断为通过;
 | 
			
		||||
  // 如果所需全部权限为空,那么取任意权限的判定;
 | 
			
		||||
  // 如果全部权限不为空,那么取全部权限的判断。
 | 
			
		||||
  const isUserMatchNeeds =
 | 
			
		||||
    (isEmpty(requiredAllPrivileges) && isEmpty(requiredAnyPrivileges)) ||
 | 
			
		||||
    (isEmpty(requiredAllPrivileges)
 | 
			
		||||
      ? hasAny(...requiredAnyPrivileges)
 | 
			
		||||
      : hasAll(...requiredAllPrivileges));
 | 
			
		||||
 | 
			
		||||
  if (isAuthenticated && isUserMatchNeeds) {
 | 
			
		||||
    return children;
 | 
			
		||||
  } else {
 | 
			
		||||
    return redirectToLogin ? (
 | 
			
		||||
      <Navigate to="/login" state={{ from: location }} replace={true} />
 | 
			
		||||
    ) : (
 | 
			
		||||
      <Navigate to="/unauthorized" state={{ from: location }} replace={true} />
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 动态用户权限验证的高阶组件。
 | 
			
		||||
 * ! 用户如果没有登录,那么验证将始终是失败的。
 | 
			
		||||
 *
 | 
			
		||||
 * @param Comp 需要被检验授权的组件
 | 
			
		||||
 * @param options 访问组件所需要的权限组合
 | 
			
		||||
 * @returns 新生成的具备动态判定权限的新组件
 | 
			
		||||
 */
 | 
			
		||||
export const requireAuthorize = (
 | 
			
		||||
  Comp: Component | FunctionComponent,
 | 
			
		||||
  options?: AuthorizeOptions
 | 
			
		||||
): FunctionComponent<any> => {
 | 
			
		||||
  const altedOptions = mergeDeepLeft(options, { any: [], all: [] });
 | 
			
		||||
  return props => {
 | 
			
		||||
    const isAuthenticated = useAuthenticated();
 | 
			
		||||
    const { hasAll, hasAny } = useAuthorization();
 | 
			
		||||
    const location = useLocation();
 | 
			
		||||
 | 
			
		||||
    const requiredAllPrivileges: string[] = altedOptions.all;
 | 
			
		||||
    const requiredAnyPrivileges: string[] = altedOptions.any;
 | 
			
		||||
    const redirectToLogin = altedOptions.toLogin ?? false;
 | 
			
		||||
 | 
			
		||||
    // 注意,这里的判断逻辑是:
 | 
			
		||||
    // 如果所需全部权限和任意权限都为空,即不需要任何权限,那么判断为通过;
 | 
			
		||||
    // 如果所需全部权限为空,那么取任意权限的判定;
 | 
			
		||||
    // 如果全部权限不为空,那么取全部权限的判断。
 | 
			
		||||
    const isUserMatchNeeds =
 | 
			
		||||
      (isEmpty(requiredAllPrivileges) && isEmpty(requiredAnyPrivileges)) ||
 | 
			
		||||
      (isEmpty(requiredAllPrivileges)
 | 
			
		||||
        ? hasAny(...requiredAnyPrivileges)
 | 
			
		||||
        : hasAll(...requiredAllPrivileges));
 | 
			
		||||
 | 
			
		||||
    if (isAuthenticated && isUserMatchNeeds) {
 | 
			
		||||
      return <Comp {...props} />;
 | 
			
		||||
    } else {
 | 
			
		||||
      return redirectToLogin ? (
 | 
			
		||||
        <Navigate to="/login" state={{ from: location }} replace={true} />
 | 
			
		||||
      ) : (
 | 
			
		||||
        <Navigate to="/unauthorized" state={{ from: location }} replace={true} />
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 包裹需要根据用户所拥有的权限展示的组件。用户在满足给定的权限条件时,被包裹的组件方能被展示。
 | 
			
		||||
 * ! 用户如果没有登录,那么验证将始终是失败的。
 | 
			
		||||
 *
 | 
			
		||||
 * @param param0 认证成功状态下展示被包裹的组件所需要的权限定义
 | 
			
		||||
 * @returns 输出被包裹的组件,或者null
 | 
			
		||||
 */
 | 
			
		||||
export const WithAuth: FC<PropsWithChildren<AuthorizeOptions>> = ({
 | 
			
		||||
  all,
 | 
			
		||||
  any,
 | 
			
		||||
  children
 | 
			
		||||
}: PropsWithChildren<AuthorizeOptions>) => {
 | 
			
		||||
  const requiredAllPrivileges = all ?? [];
 | 
			
		||||
  const requiredAnyPrivileges = any ?? [];
 | 
			
		||||
  const isAuthenticated = useAuthenticated();
 | 
			
		||||
  const { hasAll, hasAny } = useAuthorization();
 | 
			
		||||
 | 
			
		||||
  // 注意,这里的判断逻辑是:
 | 
			
		||||
  // 如果所需全部权限和任意权限都为空,即不需要任何权限,那么判断为通过;
 | 
			
		||||
  // 如果所需全部权限为空,那么取任意权限的判定;
 | 
			
		||||
  // 如果全部权限不为空,那么取全部权限的判断。
 | 
			
		||||
  const isUserMatchNeeds =
 | 
			
		||||
    (isEmpty(requiredAllPrivileges) && isEmpty(requiredAnyPrivileges)) ||
 | 
			
		||||
    (isEmpty(requiredAllPrivileges)
 | 
			
		||||
      ? hasAny(...requiredAnyPrivileges)
 | 
			
		||||
      : hasAll(...requiredAllPrivileges));
 | 
			
		||||
 | 
			
		||||
  if (isAuthenticated && isUserMatchNeeds) {
 | 
			
		||||
    return children;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return null;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										31
									
								
								src/components/hoc/suspense.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/components/hoc/suspense.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
//@ts-nocheck
 | 
			
		||||
import { CentralSpin } from '@c/ui/CentralSpin';
 | 
			
		||||
import { lazyLoad } from '@u/lazyload';
 | 
			
		||||
import { prop } from 'ramda';
 | 
			
		||||
import { FC, Suspense } from 'react';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 为异步加载组件套上一层统一的加载指示。
 | 
			
		||||
 * @param componentName 要导入的组件名称
 | 
			
		||||
 * @param loader 要导入的组件所在文件
 | 
			
		||||
 * @returns 在外部套上一层加载指示的异步加载组件。
 | 
			
		||||
 */
 | 
			
		||||
export const suspense = (componentName: string, loader: () => Promise): FC<any> => {
 | 
			
		||||
  const Component = prop(componentName, lazyLoad(loader));
 | 
			
		||||
  return props => (
 | 
			
		||||
    <Suspense fallback={<CentralSpin />}>
 | 
			
		||||
      <Component {...props} />
 | 
			
		||||
    </Suspense>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 异步加载并导入指定的组件,将直接解析出指定组件,不做其他任何处理。
 | 
			
		||||
 * @param componentName 要导入的组件名称
 | 
			
		||||
 * @param loader
 | 
			
		||||
 * @returns 导入的指定组件
 | 
			
		||||
 */
 | 
			
		||||
export const asyncLoad = (componentName: string, loader: () => Promise): FC<any> => {
 | 
			
		||||
  const Component = prop(componentName, lazyLoad(loader));
 | 
			
		||||
  return props => <Component {...props} />;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										54
									
								
								src/components/meter/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/components/meter/index.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
// 用于生成一个根据关键字搜索商户的输入选择框
 | 
			
		||||
import { meter04List } from "@q/park";
 | 
			
		||||
 | 
			
		||||
import { useQuery } from "@tanstack/react-query";
 | 
			
		||||
import { isCorrectResult } from "@u/asyncs";
 | 
			
		||||
import { Select } from "antd";
 | 
			
		||||
import { equals } from "ramda";
 | 
			
		||||
import { useState } from "react";
 | 
			
		||||
import { useDebounce } from "react-use";
 | 
			
		||||
import 'twin.macro'
 | 
			
		||||
 | 
			
		||||
interface P {
 | 
			
		||||
    parkId?: string,
 | 
			
		||||
    Meter?: string,
 | 
			
		||||
    disabled?: boolean
 | 
			
		||||
    allowClear?: boolean
 | 
			
		||||
    placeholder?: string
 | 
			
		||||
    onChange?: (e) => void,
 | 
			
		||||
    valueKey?: string,
 | 
			
		||||
    labelKey?: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const Meter = (props: P) => {
 | 
			
		||||
    const { parkId } = props;
 | 
			
		||||
    const [searchMeter, setSearchMeter] = useState('');
 | 
			
		||||
    const [searchMeterTemp, setSearchMeterTemp] = useState('');
 | 
			
		||||
    // 商户列表
 | 
			
		||||
    const { data: Meters, status: MeterStatus } = useQuery(
 | 
			
		||||
        ['meter-select-list', parkId, searchMeter],
 | 
			
		||||
        () => { return meter04List(parkId, 1, searchMeter, undefined)},
 | 
			
		||||
        { enabled: !!searchMeter, select: res => (isCorrectResult(res) ? res.meters : []) }
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    useDebounce(() => setSearchMeter(searchMeterTemp), 800, [searchMeterTemp]);
 | 
			
		||||
    return (
 | 
			
		||||
        <Select
 | 
			
		||||
            tw="w-full"
 | 
			
		||||
            showSearch
 | 
			
		||||
            allowClear={props.allowClear}
 | 
			
		||||
            filterOption={false}
 | 
			
		||||
            notFoundContent={null}
 | 
			
		||||
            onChange={e => { props.onChange && props.onChange(e) }}
 | 
			
		||||
            onSearch={setSearchMeterTemp}
 | 
			
		||||
            defaultActiveFirstOption={false}
 | 
			
		||||
            value={props.Meter}
 | 
			
		||||
            placeholder={props.placeholder || "请输入表号检索"}
 | 
			
		||||
            loading={equals(MeterStatus, 'loading')}
 | 
			
		||||
            options={(Meters || []).map(d => ({ value: props.valueKey ? d[props.valueKey]: d.code, label: props.labelKey ? d[props.labelKey] : d.code }))}
 | 
			
		||||
        />
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default Meter;
 | 
			
		||||
							
								
								
									
										143
									
								
								src/components/ui/Capsule.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								src/components/ui/Capsule.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
			
		||||
//@ts-nocheck
 | 
			
		||||
import { omit } from 'ramda';
 | 
			
		||||
import { FC, PropsWithChildren } from 'react';
 | 
			
		||||
import tw, { styled, TwStyle } from 'twin.macro';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 胶囊组件的类型,也即颜色搭配。
 | 
			
		||||
 */
 | 
			
		||||
type CapsuleType =
 | 
			
		||||
  | 'info'
 | 
			
		||||
  | 'warn'
 | 
			
		||||
  | 'error'
 | 
			
		||||
  | 'success'
 | 
			
		||||
  | 'primary'
 | 
			
		||||
  | 'plain'
 | 
			
		||||
  | 'gold'
 | 
			
		||||
  | 'silver'
 | 
			
		||||
  | 'green'
 | 
			
		||||
  | 'lime';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 胶囊组件的尺寸。
 | 
			
		||||
 */
 | 
			
		||||
type CapsuleSize = 'nano' | 'mini' | 'small' | 'normal' | 'large' | 'extra';
 | 
			
		||||
 | 
			
		||||
const TypeStyles: { [key in CapsuleType]: TwStyle } = {
 | 
			
		||||
  info: tw`bg-blue-3 text-white`,
 | 
			
		||||
  warn: tw`bg-orange-6 text-white`,
 | 
			
		||||
  error: tw`bg-red-6 text-white`,
 | 
			
		||||
  success: tw`bg-green-4 text-white`,
 | 
			
		||||
  primary: tw`bg-sggreen-6 text-white`,
 | 
			
		||||
  plain: tw`bg-gray-4 text-white`,
 | 
			
		||||
  gold: tw`bg-gold-6 text-white`,
 | 
			
		||||
  silver: tw`bg-gray-6 text-white`,
 | 
			
		||||
  green: tw`bg-green-6 text-white`,
 | 
			
		||||
  lime: tw`bg-lime-6 text-white`
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const HoverTypeStyles: { [key in CapsuleType]: TwStyle } = {
 | 
			
		||||
  info: tw`hover:bg-blue-3 hover:text-white`,
 | 
			
		||||
  warn: tw`hover:bg-orange-6 hover:text-white`,
 | 
			
		||||
  error: tw`hover:bg-red-6 hover:text-white`,
 | 
			
		||||
  success: tw`hover:bg-green-4 hover:text-white`,
 | 
			
		||||
  primary: tw`hover:bg-sggreen-6 hover:text-white`,
 | 
			
		||||
  plain: tw`hover:bg-gray-4 hover:text-white`,
 | 
			
		||||
  gold: tw`hover:bg-gold-6 hover:text-white`,
 | 
			
		||||
  silver: tw`hover:bg-gray-6 hover:text-white`,
 | 
			
		||||
  green: tw`hover:bg-green-6 hover:text-white`,
 | 
			
		||||
  lime: tw`hover:bg-lime-6 hover:text-white`
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const ActiveTypeStyles: { [key in CapsuleType]: TwStyle } = {
 | 
			
		||||
  info: tw`active:text-white active:bg-blue-5 cursor-pointer`,
 | 
			
		||||
  warn: tw`active:text-white active:bg-orange-8 cursor-pointer`,
 | 
			
		||||
  error: tw`active:text-white active:bg-red-8 cursor-pointer`,
 | 
			
		||||
  success: tw`active:text-white active:bg-green-6 cursor-pointer`,
 | 
			
		||||
  primary: tw`active:text-white active:bg-sggreen-8 cursor-pointer`,
 | 
			
		||||
  plain: tw`active:text-white active:bg-gray-6 cursor-pointer`,
 | 
			
		||||
  gold: tw`active:text-white active:bg-gold-8 cursor-pointer`,
 | 
			
		||||
  silver: tw`active:text-white active:bg-gray-8 cursor-pointer`,
 | 
			
		||||
  green: tw`active:text-white active:bg-green-8 cursor-pointer`,
 | 
			
		||||
  lime: tw`active:text-white active:bg-lime-8 cursor-pointer`
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const SizeStyles: Record<CapsuleSize, TwStyle> = {
 | 
			
		||||
  nano: tw`text-[0.35rem] leading-[0.5rem] px-0.5 py-0.5 rounded`,
 | 
			
		||||
  mini: tw`text-[0.5rem] leading-[0.75rem] px-1 py-0.5 rounded`,
 | 
			
		||||
  small: tw`text-xs px-1 py-0.5 rounded`,
 | 
			
		||||
  normal: tw`text-sm px-1.5 py-1 rounded-md`,
 | 
			
		||||
  large: tw`text-base px-1.5 py-1 rounded-md`,
 | 
			
		||||
  extra: tw`text-lg px-2 py-1.5 rounded-lg`
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const CapsulePanel = styled.div(({ type, size, hover, activable }: Partial<CapsuleProps>) => [
 | 
			
		||||
  tw`select-none`,
 | 
			
		||||
  TypeStyles[type ?? 'plain'],
 | 
			
		||||
  SizeStyles[size ?? 'normal'],
 | 
			
		||||
  (hover ?? false) && HoverTypeStyles[hover ?? 'plain'],
 | 
			
		||||
  (activable ?? false) && (hover ?? false) && ActiveTypeStyles[hover ?? 'plain']
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 胶囊组件的配置属性。
 | 
			
		||||
 */
 | 
			
		||||
export interface CapsuleProps {
 | 
			
		||||
  /**
 | 
			
		||||
   * 胶囊配色类型。
 | 
			
		||||
   */
 | 
			
		||||
  type: CapsuleType;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 配置胶囊是否可以响应鼠标悬停事件。
 | 
			
		||||
   */
 | 
			
		||||
  hover?: CapsuleType | boolean;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 配置胶囊是否可以响应鼠标按下事件,舒斌按下事件所使用的颜色与悬停颜色相同,并且受悬停影响。
 | 
			
		||||
   */
 | 
			
		||||
  activable?: boolean;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 点击胶囊时的回调函数,必须在胶囊设置了 `activable` 属性时才有效。
 | 
			
		||||
   */
 | 
			
		||||
  onClick?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 胶囊大小。
 | 
			
		||||
   */
 | 
			
		||||
  size: CapsuleSize;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 胶囊中的文字内容。
 | 
			
		||||
   */
 | 
			
		||||
  content: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于表示微型状态和提示信息的胶囊组件。
 | 
			
		||||
 * @param props 胶囊组件的配置属性
 | 
			
		||||
 * @returns 用于表示微型状态的胶囊组件。
 | 
			
		||||
 */
 | 
			
		||||
export const Capsule: FC<PropsWithChildren<CapsuleProps>> = (
 | 
			
		||||
  props: PropsWithChildren<CapsuleProps>
 | 
			
		||||
) => {
 | 
			
		||||
  const otherProps = omit(['type', 'hover', 'activable', 'size', 'content', 'onClick'], props);
 | 
			
		||||
 | 
			
		||||
  const handleClickAction = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
 | 
			
		||||
    (props.activable ?? false) && props.onClick && props.onClick(event);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <CapsulePanel
 | 
			
		||||
      type={props.type}
 | 
			
		||||
      size={props.size}
 | 
			
		||||
      hover={props.hover}
 | 
			
		||||
      activable={props.activable}
 | 
			
		||||
      onClick={handleClickAction}
 | 
			
		||||
      {...otherProps}
 | 
			
		||||
    >
 | 
			
		||||
      {props.content}
 | 
			
		||||
    </CapsulePanel>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										15
									
								
								src/components/ui/CentralSpin.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/components/ui/CentralSpin.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
import { Spin } from 'antd';
 | 
			
		||||
import { FC } from 'react';
 | 
			
		||||
import tw from 'twin.macro';
 | 
			
		||||
 | 
			
		||||
const CentralSpinLayout = tw.div`h-full w-full overflow-hidden flex flex-row justify-center items-center`;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 位于区域中央的转圈加载指示组件。
 | 
			
		||||
 * @returns 居中的转圈加载指示组件
 | 
			
		||||
 */
 | 
			
		||||
export const CentralSpin: FC = () => (
 | 
			
		||||
  <CentralSpinLayout>
 | 
			
		||||
    <Spin size="large" />
 | 
			
		||||
  </CentralSpinLayout>
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										7
									
								
								src/components/ui/ContentArea.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/components/ui/ContentArea.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
import Layout from 'antd/lib/layout';
 | 
			
		||||
import tw from 'twin.macro';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 每个实际功能页面中的工作内容区。
 | 
			
		||||
 */
 | 
			
		||||
export const ContentArea = tw(Layout.Content)`bg-white px-4 py-5 min-h-full w-full box-border`;
 | 
			
		||||
							
								
								
									
										40
									
								
								src/components/ui/DynamicStretchPanel.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/components/ui/DynamicStretchPanel.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
import { isNil } from 'ramda';
 | 
			
		||||
import tw, { styled } from 'twin.macro';
 | 
			
		||||
import { Panel } from './Panel';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于定义动态缩放面板的组件属性。
 | 
			
		||||
 */
 | 
			
		||||
export interface DynamicStretchPanelProps {
 | 
			
		||||
  /**
 | 
			
		||||
   * 确定面板当前是否处于展开状态。
 | 
			
		||||
   */
 | 
			
		||||
  extended: boolean;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 确定面板的最小宽度,使用CSS百分比或者具体像素大小描述。
 | 
			
		||||
   */
 | 
			
		||||
  minWidth: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 动态缩放面板组件。
 | 
			
		||||
 */
 | 
			
		||||
export const DynamicStretchPanel = styled(Panel)(({ extended, minWidth }: DynamicStretchPanelProps) => [
 | 
			
		||||
  tw`flex flex-col justify-start items-start space-y-1 p-2`,
 | 
			
		||||
  !isNil(minWidth) && !extended && `max-width: ${minWidth}`,
 | 
			
		||||
  extended && tw`flex-grow`
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 动态缩放面板中使用的垂直布局。
 | 
			
		||||
 */
 | 
			
		||||
export const VerticalLayout = tw.div`flex flex-col justify-start items-stretch w-full h-full`;
 | 
			
		||||
/**
 | 
			
		||||
 * 动态缩放面板中使用的水平布局。
 | 
			
		||||
 */
 | 
			
		||||
export const HorizontalLayout = tw.div`flex flex-row justify-start items-stretch w-full h-full`;
 | 
			
		||||
/**
 | 
			
		||||
 * 动态缩放面板中使用的头部信息条。
 | 
			
		||||
 */
 | 
			
		||||
export const HeadLine = tw.div`flex flex-row justify-start items-center space-x-1`;
 | 
			
		||||
							
								
								
									
										16
									
								
								src/components/ui/Panel.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/components/ui/Panel.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
import tw from 'twin.macro';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 带有一级阴影的空白面板。
 | 
			
		||||
 */
 | 
			
		||||
export const Panel = tw.div`border rounded-sm p-2 bg-white border-gray-3`;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 定义了垂直布局的空白面板。
 | 
			
		||||
 */
 | 
			
		||||
export const VerticalPanel = tw(Panel)`h-full w-full flex flex-col justify-start p-2 space-y-2`;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 定义了水平布局的空白面板。
 | 
			
		||||
 */
 | 
			
		||||
export const HorizontalPanel = tw(Panel)`h-full w-full flex flex-col justify-start p-2 space-x-2`;
 | 
			
		||||
							
								
								
									
										99
									
								
								src/components/ui/SelectRegions.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/components/ui/SelectRegions.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
import {useCallback, useEffect, useState} from 'react';
 | 
			
		||||
import { Region, regions, regionsDetail } from '@q/common';
 | 
			
		||||
import { isCorrectResult } from '@u/asyncs';
 | 
			
		||||
import { App, Cascader } from 'antd';
 | 
			
		||||
import { last, map } from 'ramda';
 | 
			
		||||
import { useQuery } from '@tanstack/react-query';
 | 
			
		||||
 | 
			
		||||
interface Option {
 | 
			
		||||
  value: string;
 | 
			
		||||
  label: string;
 | 
			
		||||
  children?: Option[];
 | 
			
		||||
  isLeaf?: boolean;
 | 
			
		||||
  loading?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 行政区划选择器
 | 
			
		||||
 */
 | 
			
		||||
export function SelectRegions(props: {
 | 
			
		||||
  // 外部应嵌套Form,初始化时Form传递的默认值为string,如果用户修改,则会变为array
 | 
			
		||||
  value?: string | string[];
 | 
			
		||||
  onChange?: (value: string[]) => void;
 | 
			
		||||
}) {
 | 
			
		||||
  const { message } = App.useApp();
 | 
			
		||||
  // 行政区划数据源
 | 
			
		||||
  const [options, setOptions] = useState<Option[]>([]);
 | 
			
		||||
  const [current, setCurrent] = useState<(string | 0)[]>([
 | 
			
		||||
    typeof props.value === 'string' ? 0 : props.value ? last(props.value) : 0
 | 
			
		||||
  ]);
 | 
			
		||||
  // 加载子级行政区划数据
 | 
			
		||||
  const onLoadRegion = useCallback(
 | 
			
		||||
    (selectedOptions?: Option[]) => {
 | 
			
		||||
      // 获取选择的最后的行政区
 | 
			
		||||
      const select = selectedOptions?.[selectedOptions.length - 1];
 | 
			
		||||
      setCurrent(selectedOptions.map(e => e.value));
 | 
			
		||||
      // 如果不是初次加载,则更新点击的项的loading状态
 | 
			
		||||
      if (select) select.loading = true;
 | 
			
		||||
    },
 | 
			
		||||
    [options]
 | 
			
		||||
  );
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
 | 
			
		||||
  }, []);
 | 
			
		||||
  // 手动触发时,加载逻辑
 | 
			
		||||
  useQuery(['select-region', ...current, props.value], () => regions(last(current)), {
 | 
			
		||||
    onSuccess: res => {
 | 
			
		||||
      if (isCorrectResult(res)) {
 | 
			
		||||
        setOptions(state => {
 | 
			
		||||
          if (last(current) === 0) return mapRegionsToOptions(res.regions);
 | 
			
		||||
          let target: Option;
 | 
			
		||||
          current.forEach(e => (target = (target?.children ?? state).find(o => o.value === e)));
 | 
			
		||||
          if (target) {
 | 
			
		||||
            target.children = mapRegionsToOptions(res.regions);
 | 
			
		||||
            target.loading = false;
 | 
			
		||||
          }
 | 
			
		||||
          return [...state];
 | 
			
		||||
        });
 | 
			
		||||
        return null;
 | 
			
		||||
      } else message.error(res.message ?? '加载行政区划失败!');
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // 初始选择的默认值,通过数组还是字符串来判断是否是表单自动填充的
 | 
			
		||||
  const { data: defaultValue, isFetching: defaultLoading } = useQuery(
 | 
			
		||||
    ['select-region-detail', props.value],
 | 
			
		||||
    () => regionsDetail(props.value as string),
 | 
			
		||||
    {
 | 
			
		||||
      enabled: typeof props.value === 'string' && !!props.value,
 | 
			
		||||
      select: res => {
 | 
			
		||||
        if (isCorrectResult(res)) {
 | 
			
		||||
          return {
 | 
			
		||||
            value: [props.value] as string[],
 | 
			
		||||
            label: res.regions
 | 
			
		||||
              .map(e => e.name)
 | 
			
		||||
              .reverse()
 | 
			
		||||
              .join('/')
 | 
			
		||||
          };
 | 
			
		||||
        } else {
 | 
			
		||||
          message.error(res.message ?? '加载行政区信息失败!');
 | 
			
		||||
          return null;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Cascader
 | 
			
		||||
      options={options}
 | 
			
		||||
      loadData={onLoadRegion}
 | 
			
		||||
      loading={defaultLoading}
 | 
			
		||||
      onChange={props.onChange}
 | 
			
		||||
      placeholder="请选择行政区划"
 | 
			
		||||
      value={typeof props.value === 'string' ? [defaultValue?.label] : props.value}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const mapRegionsToOptions = (regions: Region[]) =>
 | 
			
		||||
  map<Region, Option>(e => ({ value: e.code, label: e.name, loading: false, isLeaf: e.level === 3 }), regions);
 | 
			
		||||
							
								
								
									
										6
									
								
								src/components/ui/SpringGap.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/components/ui/SpringGap.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
import tw from 'twin.macro';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 弹性组件,用于在Flex布局中支撑空白内容。
 | 
			
		||||
 */
 | 
			
		||||
export const SpringGap = tw.div`flex-grow`;
 | 
			
		||||
							
								
								
									
										42
									
								
								src/components/ui/StrengthGadget.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/components/ui/StrengthGadget.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
//@ts-nocheck
 | 
			
		||||
import { gte } from 'ramda';
 | 
			
		||||
import { FC } from 'react';
 | 
			
		||||
import tw, { styled } from 'twin.macro';
 | 
			
		||||
 | 
			
		||||
const WeakIndicator = styled.div(({ enabled }) => [
 | 
			
		||||
  tw`flex-grow h-2`,
 | 
			
		||||
  enabled ? tw`bg-red-6` : tw`bg-gray-4`
 | 
			
		||||
]);
 | 
			
		||||
const MediumIndicator = styled.div(({ enabled }) => [
 | 
			
		||||
  tw`flex-grow h-2`,
 | 
			
		||||
  enabled ? tw`bg-yellow-6` : tw`bg-gray-4`
 | 
			
		||||
]);
 | 
			
		||||
const StrongIndicator = styled.div(({ enabled }) => [
 | 
			
		||||
  tw`flex-grow h-2`,
 | 
			
		||||
  enabled ? tw`bg-green-6` : tw`bg-gray-4`
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
interface StrengthGadgetProps {
 | 
			
		||||
  /**
 | 
			
		||||
   * 当前要展示的强度数值。
 | 
			
		||||
   */
 | 
			
		||||
  strength: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const StrengthGadget: FC<StrengthGadgetProps> = ({ strength }) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <div tw="w-full pb-1 flex flex-col justify-start items-center">
 | 
			
		||||
      <div tw="w-full flex flex-row justify-between items-center space-x-0.5">
 | 
			
		||||
        <WeakIndicator enabled={gte(strength, 0)} />
 | 
			
		||||
        <MediumIndicator enabled={gte(strength, 1)} />
 | 
			
		||||
        <MediumIndicator enabled={gte(strength, 2)} />
 | 
			
		||||
        <StrongIndicator enabled={gte(strength, 3)} />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div tw="w-full flex flex-row justify-between items-center text-xs text-gray-6">
 | 
			
		||||
        <div tw="text-left flex-grow">弱</div>
 | 
			
		||||
        <div tw="text-center flex-grow">密码强度</div>
 | 
			
		||||
        <div tw="text-right flex-grow">强</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										6
									
								
								src/components/ui/ToolBar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/components/ui/ToolBar.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
import tw from 'twin.macro';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 单一水平横向布局的工具栏,不支持换行。
 | 
			
		||||
 */
 | 
			
		||||
export const ToolBar = tw.div`flex flex-row justify-start items-center space-x-2`;
 | 
			
		||||
							
								
								
									
										6
									
								
								src/components/ui/WorkArea.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/components/ui/WorkArea.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
import tw from 'twin.macro';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 每个实际功能页面中用于存放包括面包屑导航组件在内的工作区。
 | 
			
		||||
 */
 | 
			
		||||
export const WorkArea = tw.div`relative flex flex-col justify-start items-stretch h-full w-full space-y-2`;
 | 
			
		||||
							
								
								
									
										32
									
								
								src/hooks/useAnswer403Forbidden.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/hooks/useAnswer403Forbidden.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
import { useSessionStore } from '@st/session_store';
 | 
			
		||||
import { notNil } from '@u/funcs';
 | 
			
		||||
import { App } from 'antd';
 | 
			
		||||
import { AxiosError } from 'axios';
 | 
			
		||||
import { equals } from 'ramda';
 | 
			
		||||
import { useNavigate } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于提供对异步请求返回的错误结果的判断,只响应403错误,当出现403错误的时候,
 | 
			
		||||
 * 会直接将用户重定向到登录页面。
 | 
			
		||||
 *
 | 
			
		||||
 * @returns 返回一个判断函数check(),用于判断给定的错误参数是否是403错误,如果是403错误就执行重定向。
 | 
			
		||||
 */
 | 
			
		||||
export function useAnswer403Forbidden() {
 | 
			
		||||
  const { message } = App.useApp();
 | 
			
		||||
  const logout = useSessionStore.use.logout();
 | 
			
		||||
 | 
			
		||||
  const navigate = useNavigate();
 | 
			
		||||
 | 
			
		||||
  function checkError(error: AxiosError) {
 | 
			
		||||
    if (notNil(error) && error.isAxiosError) {
 | 
			
		||||
      if (equals(error.response.status, 403)) {
 | 
			
		||||
        // 这里做错误提示,主要用于提示用户不具有操作权限,并且将会自动结束用户会话。
 | 
			
		||||
        void message.error('你当前会话没有访问指定内容的权限,你的会话已被系统自动结束。', 2.5);
 | 
			
		||||
        logout();
 | 
			
		||||
        navigate('/login');
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return { check: checkError };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								src/hooks/useAuthenticated.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/hooks/useAuthenticated.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
import { norNilOrEmpty } from '@u/funcs';
 | 
			
		||||
import dayjs from 'dayjs';
 | 
			
		||||
import { not } from 'ramda';
 | 
			
		||||
import { useExpiresAt, useToken } from './useSession';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 判断当前用户是否已经通过了认证,处于登录状态,但不保证当前的会话依旧是有效的。
 | 
			
		||||
 * @returns 当前用户是否具有可用的会话令牌,即通过登录的状态。
 | 
			
		||||
 */
 | 
			
		||||
export function useIsLoggedIn(): boolean {
 | 
			
		||||
  const [token] = useToken();
 | 
			
		||||
  return norNilOrEmpty(token);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 判断当前用户的会话是否已经过期。
 | 
			
		||||
 * @returns 当前用户的会话是否无效或者已经过期。
 | 
			
		||||
 */
 | 
			
		||||
export function useIsSessionExpired(): boolean {
 | 
			
		||||
  const [expiresAt] = useExpiresAt();
 | 
			
		||||
  return expiresAt.isBefore(dayjs());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 判断用户是否已经经过了认证,处于登录状态
 | 
			
		||||
 * @returns 当前是否处于已经登录的状态
 | 
			
		||||
 */
 | 
			
		||||
export function useAuthenticated() {
 | 
			
		||||
  const isLoggedIn = useIsLoggedIn();
 | 
			
		||||
  const isExpired = useIsSessionExpired();
 | 
			
		||||
 | 
			
		||||
  return isLoggedIn && not(isExpired);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								src/hooks/useAuthorization.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/hooks/useAuthorization.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
//@ts-nocheck
 | 
			
		||||
import { difference, equals, length, lt } from 'ramda';
 | 
			
		||||
import { useMemo } from 'react';
 | 
			
		||||
import { useSession } from './useSession';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于根据LocalStorage中保存的会话信息判断当前用户是否是管理单位
 | 
			
		||||
 * @returns 当前用户是否是管理单位。
 | 
			
		||||
 */
 | 
			
		||||
export function useIsEnterprise() {
 | 
			
		||||
  const [user] = useSession();
 | 
			
		||||
  return equals(user.type, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于根据LocalStorage中保存的会话信息判断当用户是否是监管部门。
 | 
			
		||||
 * @returns 当前用户是否是监管部门。
 | 
			
		||||
 */
 | 
			
		||||
export function useIsSupervision() {
 | 
			
		||||
  const [user] = useSession();
 | 
			
		||||
  return equals(user.type, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于根据LocalStorage中保存的会话信息判断当用户是否是运维人员。
 | 
			
		||||
 * @returns 当前用户是否是运维人员。
 | 
			
		||||
 */
 | 
			
		||||
export function useIsOPS() {
 | 
			
		||||
  const [user] = useSession();
 | 
			
		||||
  return equals(user.type, 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于判断当前已经登录的用户是否具备指定场景(权限)的Hook。
 | 
			
		||||
 * @returns 返回两个判断函数:hasAll()表示用户需要具有全部列出的权限,hasAny()表示用户需要具备列出的权限之一。
 | 
			
		||||
 */
 | 
			
		||||
export function useAuthorization() {
 | 
			
		||||
  const [user] = useSession();
 | 
			
		||||
  const ownedPrivileges = useMemo(() => [user?.type ?? -1], [user]);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 判断当前登录的用户是否具备所有要求拥有的权限。
 | 
			
		||||
   * @returns 是否全部具备要求拥有的权限
 | 
			
		||||
   * @param requires
 | 
			
		||||
   */
 | 
			
		||||
  function hasAll(...requires: number[]): boolean {
 | 
			
		||||
    const differs = difference(requires, ownedPrivileges);
 | 
			
		||||
    return equals(length(differs), 0);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 判断当前登录的用户是否具备所要求的全部权限中的任意一个。
 | 
			
		||||
   * @param requires 要求拥有的权限
 | 
			
		||||
   * @returns 是否具备要求拥有的权限之一
 | 
			
		||||
   */
 | 
			
		||||
  function hasAny(...requires: number[]): boolean {
 | 
			
		||||
    const originalPrivilegesSize = length(requires);
 | 
			
		||||
    const differs = difference(requires, ownedPrivileges);
 | 
			
		||||
    return lt(length(differs), originalPrivilegesSize);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return { hasAll, hasAny };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										55
									
								
								src/hooks/useAutoAsyncFn.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/hooks/useAutoAsyncFn.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
//@ts-nocheck
 | 
			
		||||
import { equals } from 'ramda';
 | 
			
		||||
import { useCallback, useRef } from 'react';
 | 
			
		||||
import { useMountedState } from 'react-use';
 | 
			
		||||
import { FunctionReturningPromise, PromiseType } from 'react-use/lib/misc/types';
 | 
			
		||||
import { AsyncFnReturn, AsyncState } from 'react-use/lib/useAsyncFn';
 | 
			
		||||
import { useImmer } from 'use-immer';
 | 
			
		||||
import { useAnswer403Forbidden } from './useAnswer403Forbidden';
 | 
			
		||||
 | 
			
		||||
type StateFromFunctionReturningPromise<T extends FunctionReturningPromise> = AsyncState<
 | 
			
		||||
  PromiseType<ReturnType<T>>
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
export function useAutoAsyncFn<T extends FunctionReturningPromise>(
 | 
			
		||||
  fn: T,
 | 
			
		||||
  deps: DependencyList = [],
 | 
			
		||||
  initialState: StateFromFunctionReturningPromise<T> = { loading: false }
 | 
			
		||||
): AsyncFnReturn<T> {
 | 
			
		||||
  const [state, updateState] = useImmer<StateFromFunctionReturningPromise<T>>(initialState);
 | 
			
		||||
  const isMounted = useMountedState();
 | 
			
		||||
  const lastCallId = useRef(0);
 | 
			
		||||
  const { check: check403 } = useAnswer403Forbidden();
 | 
			
		||||
 | 
			
		||||
  const newCallback = useCallback(async (...args: Parameters<T>): Promise<ReturnType<T>> => {
 | 
			
		||||
    const callId = ++lastCallId.current;
 | 
			
		||||
 | 
			
		||||
    if (!state.loading) {
 | 
			
		||||
      updateState(draft => {
 | 
			
		||||
        draft.loading = true;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const result = await fn(...args);
 | 
			
		||||
      if (isMounted() && equals(callId, lastCallId.current)) {
 | 
			
		||||
        updateState(draft => {
 | 
			
		||||
          draft.value = result;
 | 
			
		||||
          draft.loading = false;
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      return result;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      if (isMounted() && equals(callId, lastCallId.current)) {
 | 
			
		||||
        updateState(draft => {
 | 
			
		||||
          draft.error = e;
 | 
			
		||||
          draft.loading = false;
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      check403(e);
 | 
			
		||||
      throw e;
 | 
			
		||||
    }
 | 
			
		||||
  }, deps);
 | 
			
		||||
 | 
			
		||||
  return [state, newCallback as unknown as T];
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								src/hooks/useBreadcrumb.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/hooks/useBreadcrumb.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
import { useBreadcrumbStore } from '@st/breadcrumb_store';
 | 
			
		||||
import { useEffect } from 'react';
 | 
			
		||||
import { useLocation } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
export function useBreadcrumb(label: string, replace = false) {
 | 
			
		||||
  // const link = useHref();
 | 
			
		||||
  const location = useLocation();
 | 
			
		||||
  const pushBreadcrumb = useBreadcrumbStore.use.push();
 | 
			
		||||
  const popBreadcrumb = useBreadcrumbStore.use.pop();
 | 
			
		||||
  const replaceBreadcrumb = useBreadcrumbStore.use.replace();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (replace) replaceBreadcrumb({ label, link: location.pathname + location.search });
 | 
			
		||||
  }, []);
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (!replace) pushBreadcrumb({ label, link: location.pathname + location.search });
 | 
			
		||||
    return () => popBreadcrumb();
 | 
			
		||||
  }, []);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								src/hooks/useCalculatePasswordStrength.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/hooks/useCalculatePasswordStrength.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
//@ts-nocheck
 | 
			
		||||
import { SyncObjectCallback } from '@/shared/foundation';
 | 
			
		||||
import { reduceIndexed } from '@u/funcs';
 | 
			
		||||
import { append, defaultTo, gte, isEmpty, match, min, reduce, reduced, sum } from 'ramda';
 | 
			
		||||
import { useCallback } from 'react';
 | 
			
		||||
 | 
			
		||||
const detectRules = ['[a-z]', '[A-Z]', '[0-9]'];
 | 
			
		||||
const lengthStrengthRules = [0, 6, 8, 10];
 | 
			
		||||
const defaultAllowedSymbols = '!"#$%&\'()*+,-./:;<=>?@[\\\\\\]^_`{|}~';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 返回一个用于检测密码强度的方法。返回的密码强度从0开始表示,0为极弱,4为强。
 | 
			
		||||
 * 密码强度计算根据密码中出现的字符种类和密码整体长度中较弱的一项确定。
 | 
			
		||||
 * @param allowedSymbols 用于指定密码中允许出现的除字母和数字以外的其他符号。不指定将使用默认的符号列表。
 | 
			
		||||
 * @returns 用于密码强度检测的方法。
 | 
			
		||||
 */
 | 
			
		||||
export function useCalculatePasswordStrength(
 | 
			
		||||
  allowedSymbols?: string
 | 
			
		||||
): SyncObjectCallback<string, number> {
 | 
			
		||||
  const finalAllowedSymbols = defaultTo(defaultAllowedSymbols)(allowedSymbols);
 | 
			
		||||
 | 
			
		||||
  const detector = useCallback(
 | 
			
		||||
    (pwd: string) => {
 | 
			
		||||
      const finalDetectRules = append(`[${finalAllowedSymbols}]`, detectRules);
 | 
			
		||||
      const rulesDetectResult = reduce(
 | 
			
		||||
        (acc, elem) => {
 | 
			
		||||
          const matches = match(elem, pwd);
 | 
			
		||||
          return append(isEmpty(matches) ? 0 : 1, acc);
 | 
			
		||||
        },
 | 
			
		||||
        [] as number[],
 | 
			
		||||
        finalDetectRules
 | 
			
		||||
      );
 | 
			
		||||
      const symbolStrengthLevel = sum(rulesDetectResult);
 | 
			
		||||
      const pwdLength = pwd.length;
 | 
			
		||||
      const lengthStrengthLevel = reduceIndexed<number, number>(
 | 
			
		||||
        (acc, elem, index) => (gte(pwdLength, elem) ? index : reduced(acc)),
 | 
			
		||||
        0,
 | 
			
		||||
        lengthStrengthRules
 | 
			
		||||
      );
 | 
			
		||||
      return min(symbolStrengthLevel, lengthStrengthLevel);
 | 
			
		||||
    },
 | 
			
		||||
    [finalAllowedSymbols]
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return detector;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								src/hooks/useLocalStorage.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/hooks/useLocalStorage.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
import { MapFactory, SyncCallback, SyncObjectCallback } from '@/shared/foundation';
 | 
			
		||||
import { isNilOrEmpty, notNil } from '@u/funcs';
 | 
			
		||||
import { equals } from 'ramda';
 | 
			
		||||
import { useCallback } from 'react';
 | 
			
		||||
 | 
			
		||||
type LocalStorageOperates<T> = [T, SyncObjectCallback<T>, SyncCallback];
 | 
			
		||||
type useLocalStorageOption<T> = {
 | 
			
		||||
  raw?: boolean;
 | 
			
		||||
  serializer?: MapFactory<string, T>;
 | 
			
		||||
  deserializer?: MapFactory<T, string>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 重新定义的实时操作单一LocalStorage键的Hook。
 | 
			
		||||
 * @returns 按照顺序返回给定键的值、设置新值方法和删除值的方法。
 | 
			
		||||
 */
 | 
			
		||||
export function useLocalStorage<T>(
 | 
			
		||||
  key: string,
 | 
			
		||||
  defaultValue?: T,
 | 
			
		||||
  option?: useLocalStorageOption<T>
 | 
			
		||||
): LocalStorageOperates<T> {
 | 
			
		||||
  const rawValue = localStorage.getItem(key);
 | 
			
		||||
  const value = isNilOrEmpty(rawValue)
 | 
			
		||||
    ? defaultValue
 | 
			
		||||
    : equals(option?.raw ?? false, true)
 | 
			
		||||
    ? //@ts-ignore
 | 
			
		||||
      (rawValue as T)
 | 
			
		||||
    : notNil(option?.deserializer)
 | 
			
		||||
    ? option.deserializer(rawValue)
 | 
			
		||||
    : (JSON.parse(rawValue) as T);
 | 
			
		||||
  const setValue = useCallback((newValue: T) => {
 | 
			
		||||
    if (equals(option?.raw ?? false, true)) {
 | 
			
		||||
      //@ts-ignore
 | 
			
		||||
      localStorage.setItem(key, newValue);
 | 
			
		||||
    } else {
 | 
			
		||||
      const serialiedValue = notNil(option?.serializer)
 | 
			
		||||
        ? option.serializer(newValue)
 | 
			
		||||
        : JSON.stringify(newValue);
 | 
			
		||||
      //@ts-ignore
 | 
			
		||||
      localStorage.setItem(key, serialiedValue);
 | 
			
		||||
    }
 | 
			
		||||
  }, []);
 | 
			
		||||
  const removeStorage = useCallback(() => localStorage.removeItem(key), []);
 | 
			
		||||
  //@ts-ignore
 | 
			
		||||
  return [value, setValue, removeStorage];
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								src/hooks/useLocationState.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/hooks/useLocationState.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
//@ts-nocheck
 | 
			
		||||
import { notNil } from '@u/funcs';
 | 
			
		||||
import { clone, defaultTo, is, isNil, mergeLeft } from 'ramda';
 | 
			
		||||
import { useLocation } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 从React Router传递的location的State属性中获取指定的内容。
 | 
			
		||||
 * 会根据指定的默认值类型自动处理所取得的值。如果不给定默认值,则会按照获取到的值类型处理。
 | 
			
		||||
 * @param extractor 用于从路由State中获取或者计算获取指定形式的值的函数。
 | 
			
		||||
 * @param defaultValue 在指定内容不存在的时候所要使用的默认值。
 | 
			
		||||
 * @returns 路由State中所需要的内容。
 | 
			
		||||
 */
 | 
			
		||||
export function useLocationState<T, R = T>(extractor?: (T) => R, defaultValue?: R): R {
 | 
			
		||||
  const location = useLocation();
 | 
			
		||||
  const state = location.state as T;
 | 
			
		||||
  const extracted = notNil(extractor) && is(Function, extractor) ? extractor(state) : clone(state);
 | 
			
		||||
 | 
			
		||||
  return isNil(defaultValue)
 | 
			
		||||
    ? extracted
 | 
			
		||||
    : is(Object, defaultValue)
 | 
			
		||||
    ? mergeLeft(extracted, defaultValue)
 | 
			
		||||
    : defaultTo(defaultValue, extracted);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/hooks/useResetStore.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/hooks/useResetStore.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
import { SyncCallback } from '@/shared/foundation';
 | 
			
		||||
import { useUnmount } from 'react-use';
 | 
			
		||||
 | 
			
		||||
//在组件卸载的时候调用指定的方法,主要用来重置组件所使用到的Store。
 | 
			
		||||
export function useResetStore(action?: SyncCallback) {
 | 
			
		||||
  useUnmount(() => action?.());
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								src/hooks/useSelectWithSearch.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/hooks/useSelectWithSearch.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
import { useState } from 'react';
 | 
			
		||||
import { useDebounce } from 'react-use';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 防抖实现输入选择器的基本逻辑
 | 
			
		||||
 */
 | 
			
		||||
export function useSelectWithSearch() {
 | 
			
		||||
  // 用户要搜索的内容
 | 
			
		||||
  const [searchTemp, setSearchTemp] = useState('');
 | 
			
		||||
  const [search, setSearch] = useState('');
 | 
			
		||||
  useDebounce(() => setSearch(searchTemp), 800, [searchTemp]);
 | 
			
		||||
 | 
			
		||||
  return [search, setSearchTemp] as [string, typeof setSearchTemp];
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										99
									
								
								src/hooks/useSession.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/hooks/useSession.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
//@ts-nocheck
 | 
			
		||||
import {SyncCallback, SyncObjectCallback} from '@/shared/foundation';
 | 
			
		||||
import {UserSession} from '@/shared/model-user';
 | 
			
		||||
import {isNilOrEmpty} from '@u/funcs';
 | 
			
		||||
import dayjs, {Dayjs} from 'dayjs';
 | 
			
		||||
import {head, is, isNil, toUpper} from 'ramda';
 | 
			
		||||
import {useCallback, useMemo} from 'react';
 | 
			
		||||
import {useLocalStorage} from './useLocalStorage';
 | 
			
		||||
 | 
			
		||||
type SessionOperation<T, O = T> = [T | undefined, SyncObjectCallback<O>, SyncCallback];
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 提供用于操作用户Token的一系列方法。
 | 
			
		||||
 * @returns 返回用于操作用户操作的获取、设置、删除的方法,按顺序以数组的方式返回。
 | 
			
		||||
 */
 | 
			
		||||
export function useToken(): SessionOperation<string | null> {
 | 
			
		||||
  const [value, set, remove] = useLocalStorage<string | null>('token', null, { raw: true });
 | 
			
		||||
 | 
			
		||||
  return [value, set, remove];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 提供用于操作用户登录会话有效时间的一系列方法。
 | 
			
		||||
 * @returns 返回用于操作用户登录会话的获取、设置、删除方法,按顺序以数组方式返回。
 | 
			
		||||
 */
 | 
			
		||||
export function useExpiresAt(): SessionOperation<Dayjs, string | Dayjs> {
 | 
			
		||||
  const [value, set, remove] = useLocalStorage<Dayjs>('expires', dayjs('2000-01-01 00:00:00'), {
 | 
			
		||||
    serializer: value => value.toISOString(),
 | 
			
		||||
    deserializer: value => dayjs(value)
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const unifiedSet = useCallback((value: string | Dayjs) => {
 | 
			
		||||
    if (is(String, value)) {
 | 
			
		||||
      set(dayjs(value));
 | 
			
		||||
    } else if (dayjs.isDayjs(value)) {
 | 
			
		||||
      set(value);
 | 
			
		||||
    } else {
 | 
			
		||||
      set(null);
 | 
			
		||||
    }
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
  return [value, unifiedSet, remove];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于获取和记录当前应用中已经登录的用户信息,用户信息直接保存在LocalStorage中。
 | 
			
		||||
 * @returns 返回保存在LocalStorage中的用户信息的一系列操作方法。
 | 
			
		||||
 */
 | 
			
		||||
export function useSession(): SessionOperation<UserSession | null> {
 | 
			
		||||
  const [uid, setUserId, removeUserId] = useLocalStorage<number | null>('uid', null, {
 | 
			
		||||
    raw: true
 | 
			
		||||
  });
 | 
			
		||||
  const [userName, setUserName, removeUserName] = useLocalStorage<string | null>('name', null, {
 | 
			
		||||
    raw: true
 | 
			
		||||
  });
 | 
			
		||||
  const [userType, setUserType, removeUserType] = useLocalStorage<boolean>('type', -1);
 | 
			
		||||
  const [userMenu, setUserMenu, removeUserMenu] = useLocalStorage<string[]>('menu', [])
 | 
			
		||||
  const sessionInfo = useMemo((): UserSession | null => {
 | 
			
		||||
    const info: UserSession = {
 | 
			
		||||
      uid: uid,
 | 
			
		||||
      name: userName,
 | 
			
		||||
      type: userType,
 | 
			
		||||
      menu: userMenu
 | 
			
		||||
    };
 | 
			
		||||
    return isNilOrEmpty(uid) ? null : info;
 | 
			
		||||
  }, [uid, userName, userType, userMenu]);
 | 
			
		||||
 | 
			
		||||
  const updateSession = useCallback((value: UserSession) => {
 | 
			
		||||
    setUserId(value.code);
 | 
			
		||||
    setUserName(value.name);
 | 
			
		||||
    setUserType(value.type);
 | 
			
		||||
    setUserMenu(value.menu);
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
  const removeSession = useCallback(() => {
 | 
			
		||||
    removeUserId();
 | 
			
		||||
    removeUserName();
 | 
			
		||||
    removeUserType();
 | 
			
		||||
    removeUserMenu()
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
  return [sessionInfo, updateSession, removeSession];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 生成当前已经登录的用户的名称的第一个字母或者汉字。
 | 
			
		||||
 * @returns 代表当前用户的第一个字母或者汉字。
 | 
			
		||||
 */
 | 
			
		||||
export function useFirstLetterOfUserName(): string {
 | 
			
		||||
  const [user] = useSession();
 | 
			
		||||
 | 
			
		||||
  return useMemo(() => {
 | 
			
		||||
    if (isNil(user)) {
 | 
			
		||||
      return 'A';
 | 
			
		||||
    } else {
 | 
			
		||||
      return toUpper(head(user.name));
 | 
			
		||||
    }
 | 
			
		||||
  }, [user]);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								src/pages/report/components/Card.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/pages/report/components/Card.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
import 'twin.macro'
 | 
			
		||||
 | 
			
		||||
export default function(props) {
 | 
			
		||||
    return <div tw='' style={{marginTop: "20px", marginBottom: "20px",
 | 
			
		||||
        border: '1px solid #ccc', borderRadius: '5px', display: "inline-block", width: '138px', height: '80px', ...(props.style || {}) }}>
 | 
			
		||||
        <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%'}}>
 | 
			
		||||
            <div>
 | 
			
		||||
                { props.children }
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								src/pages/report/components/TopContent.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/pages/report/components/TopContent.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
export default function(props) {
 | 
			
		||||
    return <div style={{fontSize: 14, marginTop: "6px", wordBreak: 'break-all'}}> { props.children } </div>
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								src/pages/report/components/TopTitle.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/pages/report/components/TopTitle.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
export default function(props) {
 | 
			
		||||
    return <div style={{fontSize: 14, color: "#595959"}}> { props.children } </div>
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/pages/report/components/Unit.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/pages/report/components/Unit.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
import 'twin.macro'
 | 
			
		||||
 | 
			
		||||
export default function(props) {
 | 
			
		||||
    return <div tw='pl-3 pr-3 text-center' style={{fontSize: '20px'}}>
 | 
			
		||||
        { props.children }
 | 
			
		||||
    </div>
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										251
									
								
								src/pages/report/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								src/pages/report/index.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,251 @@
 | 
			
		||||
import { ContentArea } from '@c/ui/ContentArea';
 | 
			
		||||
import { useQuery, } from '@tanstack/react-query';
 | 
			
		||||
import { Button, Col, Divider, Row, message } from 'antd';
 | 
			
		||||
import React, {FC, useCallback, useRef, useState} from 'react';
 | 
			
		||||
import 'twin.macro';
 | 
			
		||||
import Logo from 'assets/logo.png'
 | 
			
		||||
import { reportTenementDetail } from '@q/publicity';
 | 
			
		||||
import { isCorrectResult } from '@u/asyncs';
 | 
			
		||||
import Card from './components/Card';
 | 
			
		||||
import Unit from './components/Unit';
 | 
			
		||||
import { outputWithPrecision } from '@u/funcs';
 | 
			
		||||
import html2pdf from "html2pdf.js";
 | 
			
		||||
import ReactToPrint from 'react-to-print';
 | 
			
		||||
import dayjs from "dayjs";
 | 
			
		||||
import TopTitle from './components/TopTitle';
 | 
			
		||||
import TopContent from './components/TopContent';
 | 
			
		||||
// 核心代码
 | 
			
		||||
import { useSearchParams } from 'react-router-dom'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export const UserReport: FC = () => {
 | 
			
		||||
    const [searchParams] = useSearchParams()
 | 
			
		||||
    const tid = searchParams.get("tenement");
 | 
			
		||||
    const rid = searchParams.get("report");
 | 
			
		||||
 | 
			
		||||
    const { data } = useQuery(
 | 
			
		||||
        ['report-tenement-detail', rid, tid],
 | 
			
		||||
        () => reportTenementDetail(rid, tid),
 | 
			
		||||
        {
 | 
			
		||||
            select: res => {
 | 
			
		||||
                if (isCorrectResult(res)) return res.detail;
 | 
			
		||||
                message.error(res.message || '获取商户电费详情失败');
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const [downloadLoading, setDownloadLoading] = useState(false);
 | 
			
		||||
 | 
			
		||||
    const printRef = useRef()
 | 
			
		||||
 | 
			
		||||
    const handlePrint = async () => {
 | 
			
		||||
        const opt = {
 | 
			
		||||
            margin: 0,
 | 
			
		||||
            filename: `${data?.tenement?.fullName || '报表'}.pdf`,
 | 
			
		||||
            image: { type: "jpeg", quality: 0.98, },
 | 
			
		||||
            enableLinks: true,
 | 
			
		||||
            html2canvas: { scale: 3, useCORS: true, allowTaint: false,  },
 | 
			
		||||
            jsPDF: {
 | 
			
		||||
                unit: 'pt', // pt、mm、cm、in
 | 
			
		||||
                format: 'a4',
 | 
			
		||||
                orientation: 'p' // 纵向p,横向l
 | 
			
		||||
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
        setDownloadLoading(true)
 | 
			
		||||
        // eslint-disable-next-line @typescript-eslint/no-unsafe-call
 | 
			
		||||
        await html2pdf(printRef.current, opt);
 | 
			
		||||
        setDownloadLoading(false);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    const renderTable = useCallback(() => {
 | 
			
		||||
        return data?.meters?.map((item, index) => {
 | 
			
		||||
            const finalAmount = Number(item?.overall?.amount || 0) + Number(item?.loss?.amount || 0) + Number(item?.publicAmount || 0)
 | 
			
		||||
            return (
 | 
			
		||||
                <tr key={index}>
 | 
			
		||||
                    <td>{item?.code}</td>
 | 
			
		||||
                    <td>{item?.address}</td>
 | 
			
		||||
                    <td>{outputWithPrecision(item?.startNumber, 2, '-')}</td>
 | 
			
		||||
                    <td>{outputWithPrecision(item?.endNumber, 2, '-')}</td>
 | 
			
		||||
                    <td>{outputWithPrecision(item?.displayRatio, 2, '-')}</td>
 | 
			
		||||
                    <td>{outputWithPrecision(item?.overall?.amount, 2, '-')}</td>
 | 
			
		||||
                    {/* <td>{outputWithPrecision(item?.finalTotal ? (1 / (1 - Number(item?.loss?.amount) / Number(item?.finalTotal)) - 1) * 100 : undefined, 2, '-')} %</td> */}
 | 
			
		||||
                    <td>{outputWithPrecision(item?.loss?.amount, 2, '-')}</td>
 | 
			
		||||
                    <td>{outputWithPrecision(item?.publicAmount, 2, '-')}</td>
 | 
			
		||||
                    <td>{outputWithPrecision(finalAmount, 2, '-')}</td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                )
 | 
			
		||||
        })
 | 
			
		||||
    }, [data?.meters])
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <style>
 | 
			
		||||
        {
 | 
			
		||||
          `
 | 
			
		||||
                        td {
 | 
			
		||||
                            padding: 0.2cm
 | 
			
		||||
                        }
 | 
			
		||||
                        tr td:nth-child(1) {
 | 
			
		||||
                            width: 3.5cm;
 | 
			
		||||
                        }
 | 
			
		||||
                        tr td:nth-child(2) {
 | 
			
		||||
                            width: 4.5cm;
 | 
			
		||||
                        }
 | 
			
		||||
                        tr td:nth-child(3), tr td:nth-child(4), tr td:nth-child(5) {
 | 
			
		||||
                            width: 1.8cm;
 | 
			
		||||
                        }
 | 
			
		||||
                        tr td:nth-child(6), tr td:nth-child(7), tr td:nth-child(8), tr td:nth-child(9) {
 | 
			
		||||
                            width: 2cm;
 | 
			
		||||
                        }
 | 
			
		||||
                        #content, .ant-col {
 | 
			
		||||
                            font-size: 0.34cm;
 | 
			
		||||
                        }
 | 
			
		||||
                    `
 | 
			
		||||
                }
 | 
			
		||||
            </style>
 | 
			
		||||
        <div style={{position: 'fixed',width: '100%', height: '100%', left: 0, right: 0, top: 0, bottom: 0, margin: 'auto', zIndex: 99, background: '#fff' }}>
 | 
			
		||||
            <div>
 | 
			
		||||
                <Button loading={downloadLoading} type='primary' tw='' onClick={() => handlePrint()}> 下载 </Button>
 | 
			
		||||
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div ref={printRef}>
 | 
			
		||||
            <ContentArea>
 | 
			
		||||
                <div id="content">
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <img src={Logo} alt="" width={60} height={60}/>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div tw='mt-4' style={{fontSize: "18px", fontWeight: 600}}>
 | 
			
		||||
                    尊敬的{data?.tenement?.fullName},这是贵公司  
 | 
			
		||||
                              {dayjs(data?.comprehensive?.startDate).format("MM")} 月的电费账单
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div tw='flex mt-6 flex-row' style={{backgroundColor: "#f0f0f0", padding: '18px 20px'}}>
 | 
			
		||||
                            <div tw='flex flex-1 flex-col'>
 | 
			
		||||
                                <Row gutter={16}>
 | 
			
		||||
                                    <Col span={5} style={{display: "flex", flexDirection: "column"}}>
 | 
			
		||||
                                        <div>账单周期</div>
 | 
			
		||||
                                        <div style={{fontSize: "20px", fontWeight: 600, flex: 1, display: "flex", alignItems: "center"}}>
 | 
			
		||||
                                            {data?.comprehensive?.startDate ? dayjs(data?.comprehensive?.startDate).format("YYYY年MM月") : null}
 | 
			
		||||
                                        </div>
 | 
			
		||||
                                        {/* <div> {data?.comprehensive?.startDate} - {data?.comprehensive?.endDate} </div> */}
 | 
			
		||||
                                    </Col>
 | 
			
		||||
                                    <Col span={19}>
 | 
			
		||||
                                        <Row gutter={16}>
 | 
			
		||||
                                            <Col span={6}> <TopTitle> 商户编号 </TopTitle> <TopContent> {data?.tenement?.id} </TopContent> </Col>
 | 
			
		||||
                                            <Col span={6}> <TopTitle>商户名称</TopTitle><TopContent>{data?.tenement?.fullName}</TopContent> </Col>
 | 
			
		||||
                                            <Col span={6}> <TopTitle>用户类型</TopTitle><TopContent>工商业</TopContent> </Col>
 | 
			
		||||
                                            <Col span={6}> <TopTitle>电压等级</TopTitle><TopContent>0.4kv</TopContent> </Col>
 | 
			
		||||
                                        </Row>
 | 
			
		||||
                                        <Divider dashed tw='mt-2 mb-2 flex flex-col w-full' />
 | 
			
		||||
                                        <Row gutter={16}>
 | 
			
		||||
                                            <div tw='mt-3 flex-1 flex flex-row'>
 | 
			
		||||
                                                <Col span={6}> <TopTitle>所属园区</TopTitle> <TopContent> {data?.park?.name} </TopContent> </Col>
 | 
			
		||||
                                                <Col span={6}> <TopTitle>用户地址</TopTitle> <TopContent> {data?.tenement?.address} </TopContent> </Col>
 | 
			
		||||
                                                <Col span={6}> <TopTitle>抄表日期</TopTitle><TopContent>{data?.comprehensive?.endDate}</TopContent> </Col>
 | 
			
		||||
                                                <Col span={6}> <TopTitle>购电方式</TopTitle><TopContent>市场化零售客户</TopContent> </Col>
 | 
			
		||||
                                            </div>
 | 
			
		||||
                                        </Row>
 | 
			
		||||
                                    </Col>
 | 
			
		||||
                                </Row>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div>
 | 
			
		||||
                            <div  tw='mt-6'>
 | 
			
		||||
                                账单信息
 | 
			
		||||
                                <Divider tw='mt-2 mb-2 flex flex-col w-full' />
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <div tw='mt-2'>
 | 
			
		||||
                                <div tw='flex flex-row'>
 | 
			
		||||
                                    <Card>
 | 
			
		||||
                                        <h4  tw='mt-1 mb-1'> 本期电量: </h4>
 | 
			
		||||
                                        <div> {outputWithPrecision(data?.comprehensive?.consumption, 2, '-')}   千瓦时 </div>
 | 
			
		||||
                                    </Card>
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div tw='mt-3'>
 | 
			
		||||
                                    电费构成
 | 
			
		||||
                                    <Divider tw='mt-2 mb-4 flex flex-col w-full' />
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div tw='flex flex-row items-center' style={{height: 'fit-content', alignItems: "stretch", flexGrow: "stratch"   }}>
 | 
			
		||||
                                    <div tw='flex flex-row items-center flex-wrap'>
 | 
			
		||||
                                        <Unit> ( </Unit>
 | 
			
		||||
                                        <Card>
 | 
			
		||||
                                            <h4 tw='mt-1 mb-1'> 本期用电量: </h4>
 | 
			
		||||
                                            <div> {outputWithPrecision(data?.comprehensive?.consumption, 2, '-')}   千瓦时 </div>
 | 
			
		||||
                                        </Card>
 | 
			
		||||
                                        <Unit> + </Unit>
 | 
			
		||||
                                        <Card>
 | 
			
		||||
                                            <h4  tw='mt-1 mb-1'> 本期线损电量: </h4>
 | 
			
		||||
                                            <div> {outputWithPrecision(data?.comprehensive?.lossAmount, 2, '-')}   千瓦时 </div>
 | 
			
		||||
                                        </Card>
 | 
			
		||||
                                        <Unit> + </Unit>
 | 
			
		||||
                                        <Card>
 | 
			
		||||
                                            <h4  tw='mt-1 mb-1'> 本期公摊电量: </h4>
 | 
			
		||||
                                            <div> {outputWithPrecision(data?.comprehensive?.publicAmount, 2, '-')}   千瓦时 </div>
 | 
			
		||||
                                        </Card>
 | 
			
		||||
                                        <Unit> ) </Unit><Unit> * </Unit>
 | 
			
		||||
                                        <Card>
 | 
			
		||||
                                            <h4  tw='mt-1 mb-1'> 用电单价: </h4>
 | 
			
		||||
                                            <div> {outputWithPrecision(data?.comprehensive?.price, 6, '-')}   千瓦时/元 </div>
 | 
			
		||||
                                        </Card>
 | 
			
		||||
                                        <Unit> + </Unit>
 | 
			
		||||
                                        <Card>
 | 
			
		||||
                                            <h4  tw='mt-1 mb-1'> 摊薄基本电费: </h4>
 | 
			
		||||
                                            <div> {outputWithPrecision(data?.comprehensive?.basicPooled, 2, '-')} </div>
 | 
			
		||||
                                        </Card>
 | 
			
		||||
                                        <Unit> + </Unit>
 | 
			
		||||
                                        <Card>
 | 
			
		||||
                                            <h4  tw='mt-1 mb-1'> 摊薄调整电费: </h4>
 | 
			
		||||
                                            <div> {outputWithPrecision(data?.comprehensive?.adjustPooled, 2, '-')} </div>
 | 
			
		||||
                                        </Card>
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                    <div tw='flex flex-row items-center' style={{height: '100%', flex: 1}}>
 | 
			
		||||
                                        <Unit> = </Unit>
 | 
			
		||||
                                        <Card style={{height: 200}}>
 | 
			
		||||
                                            <h4  tw='mt-1 mb-1'> 本期总电费(元): </h4>
 | 
			
		||||
                                            <div> {outputWithPrecision(data?.comprehensive?.total, 2, '-')} </div>
 | 
			
		||||
                                        </Card>
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <div>
 | 
			
		||||
                                <div tw='mt-4'>
 | 
			
		||||
                                    用电明细
 | 
			
		||||
                                    <Divider tw='mt-2 mb-4 flex flex-col w-full' />
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div tw="mt-3" style={{fontSize: 12}}>
 | 
			
		||||
                                    <table border={1} width={"100%"}  cellSpacing="0" >
 | 
			
		||||
                                        <thead>
 | 
			
		||||
                                            <tr>
 | 
			
		||||
                                                <td>电表编号</td>
 | 
			
		||||
                                                <td>电表地址</td>
 | 
			
		||||
                                                <td>起码</td>
 | 
			
		||||
                                                <td>止码</td>
 | 
			
		||||
                                                <td>表倍率</td>
 | 
			
		||||
                                                <td>用户电量</td>
 | 
			
		||||
                                                {/* <td>线损占比</td> */}
 | 
			
		||||
                                                <td>线损电量</td>
 | 
			
		||||
                                                <td>公摊电量</td>
 | 
			
		||||
                                                <td>合计电量</td>
 | 
			
		||||
                                            </tr>
 | 
			
		||||
                                        </thead>
 | 
			
		||||
                                      <tbody>
 | 
			
		||||
                                      {renderTable()}
 | 
			
		||||
                                      </tbody>
 | 
			
		||||
                                    </table>
 | 
			
		||||
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
                </ContentArea>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    </>
 | 
			
		||||
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										159
									
								
								src/queries/accounting.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								src/queries/accounting.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,159 @@
 | 
			
		||||
import type { BaseResponse, Pageable } from '@/shared/model-components';
 | 
			
		||||
import { ajaxEngine } from '@q/axios_instance';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
import { Record, Related, EditAccountingData, Settlement, BalanceOverall } from '@/shared/model-accounting';
 | 
			
		||||
import { downloadFile } from './common';
 | 
			
		||||
import { stringify } from 'qs';
 | 
			
		||||
import qs from 'qs';
 | 
			
		||||
import { UploadExcelError } from '@/shared/model-park';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 查询账务记录
 | 
			
		||||
 * @param park 园区id
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param keyword 关键词
 | 
			
		||||
 * @param  起始时间
 | 
			
		||||
 * @param periodEnd 截止时间
 | 
			
		||||
 * @param tenement 要查询的账务归属商户id
 | 
			
		||||
 */
 | 
			
		||||
export async function accountingList({
 | 
			
		||||
  page,
 | 
			
		||||
  keyword,
 | 
			
		||||
  periodStart,
 | 
			
		||||
  periodEnd,
 | 
			
		||||
  tenement,
 | 
			
		||||
  type,
 | 
			
		||||
  medium,
 | 
			
		||||
  park
 | 
			
		||||
}: {
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword?: string,
 | 
			
		||||
  periodStart?: string,
 | 
			
		||||
  periodEnd?: string,
 | 
			
		||||
  tenement?: string,
 | 
			
		||||
  type?:string,
 | 
			
		||||
  medium?: string,
 | 
			
		||||
    park?: string
 | 
			
		||||
}): Promise<BaseResponse & Pageable & { records: Record[], amount: number }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/accounting?${qs.stringify({
 | 
			
		||||
    page,
 | 
			
		||||
    keyword,
 | 
			
		||||
    periodStart,
 | 
			
		||||
    periodEnd,
 | 
			
		||||
    tenement,
 | 
			
		||||
    type,
 | 
			
		||||
    medium,
 | 
			
		||||
    park,
 | 
			
		||||
  })}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 保存账务记录条目
 | 
			
		||||
 * @param data 信息
 | 
			
		||||
 */
 | 
			
		||||
export async function createAccounting(data: EditAccountingData): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/accounting`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 保存账务记录条目
 | 
			
		||||
 * @param id
 | 
			
		||||
 * @param data 信息
 | 
			
		||||
 */
 | 
			
		||||
export async function updateAccounting(id: string, data: EditAccountingData): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().put(`/accounting/${id}`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 回滚指定账务条目 删除操作
 | 
			
		||||
 * @param id
 | 
			
		||||
 */
 | 
			
		||||
export async function deleteAccounting(id: string): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().delete(`/accounting/${id}`);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/** 下载模板 */
 | 
			
		||||
export function download(pid: string) {
 | 
			
		||||
  downloadFile(`/meter/${pid}/template`);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 获取授权信息(财务审核)
 | 
			
		||||
 */
 | 
			
		||||
export async function approve(data: { username: string, password: string, required: string [] }) {
 | 
			
		||||
  const response = await ajaxEngine().post(`/authorize`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 查询结算记录 */
 | 
			
		||||
export async function settlementList(
 | 
			
		||||
  park: string,
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword?: string,
 | 
			
		||||
  settleStart?: string,
 | 
			
		||||
  settleEnd?: string,
 | 
			
		||||
  tenement?: string,
 | 
			
		||||
  status?: string
 | 
			
		||||
): Promise<BaseResponse & Pageable & { settlements: Settlement[] } > {
 | 
			
		||||
  const response = await ajaxEngine().get(`/settlement/${park}?${stringify({ page, keyword, settleStart, settleEnd, tenement, status } )}`, {
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 查询账务余额 */
 | 
			
		||||
export async function getAccountingBalance({
 | 
			
		||||
  parkId,
 | 
			
		||||
  tenement,
 | 
			
		||||
  shortName,
 | 
			
		||||
  page,
 | 
			
		||||
  code
 | 
			
		||||
}: {
 | 
			
		||||
  parkId: string,
 | 
			
		||||
  tenement?: string,
 | 
			
		||||
  shortName?: string,
 | 
			
		||||
  periodStart?: string,
 | 
			
		||||
  periodEnd?: string,
 | 
			
		||||
  page?: number,
 | 
			
		||||
  code?: string,
 | 
			
		||||
}) :Promise<BaseResponse & { related: Related[], overall: BalanceOverall }>{
 | 
			
		||||
  const response = await ajaxEngine().get(`/accounting/balancing`, {
 | 
			
		||||
    params: { page, tenement, code, parkId, shortName }
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 获取商户下所有的表计
 | 
			
		||||
export async function getMetersByTenement(tenement: string) {
 | 
			
		||||
  const response = await ajaxEngine().get(`/accounting/Meter`, {
 | 
			
		||||
    params: { tenement,  }
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 上传账务初始金额
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param file 文件对象
 | 
			
		||||
 * @param onProgress 进度监听
 | 
			
		||||
 */
 | 
			
		||||
export async function uploadAccountingBalanceFile(
 | 
			
		||||
  pid: string,
 | 
			
		||||
  file: File,
 | 
			
		||||
  onProgress?: (percent: number) => void
 | 
			
		||||
): Promise<BaseResponse & { errors: UploadExcelError[] | null }> {
 | 
			
		||||
  const response = await ajaxEngine().postForm(
 | 
			
		||||
    `/accounting/batch?pid=${pid}`,
 | 
			
		||||
    { data: file },
 | 
			
		||||
    { onUploadProgress: (e: ProgressEvent) => onProgress?.(e.loaded / e.total) }
 | 
			
		||||
  );
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 余额导入模板 */
 | 
			
		||||
export function templateAccountingDownload(pid: string) {
 | 
			
		||||
  return downloadFile(`/accounting/template?park=${pid}`);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										55
									
								
								src/queries/axios_instance.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/queries/axios_instance.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
import { message } from 'antd';
 | 
			
		||||
import axios, { AxiosInstance } from 'axios';
 | 
			
		||||
import decamelizeKeys from 'decamelize-keys';
 | 
			
		||||
import qs from 'qs';
 | 
			
		||||
import { isNil } from 'ramda';
 | 
			
		||||
 | 
			
		||||
//@ts-nocheck
 | 
			
		||||
import { MaybeMapFactory } from '@/shared/foundation';
 | 
			
		||||
 | 
			
		||||
let engineCache: AxiosInstance | null = null;
 | 
			
		||||
export const baseUrl = '/api'
 | 
			
		||||
/**
 | 
			
		||||
 * 应用中所需要使用的AJAX引擎。
 | 
			
		||||
 * @param forceUnauthorized 是否强制丢弃用户会话令牌信息。
 | 
			
		||||
 * @returns AJAX引擎实例。
 | 
			
		||||
 */
 | 
			
		||||
export const ajaxEngine: MaybeMapFactory<AxiosInstance, boolean> = (forceUnauthorized?: boolean) => {
 | 
			
		||||
  const token = localStorage.getItem('token');
 | 
			
		||||
 | 
			
		||||
  if (isNil(engineCache)) {
 | 
			
		||||
    engineCache = axios.create({
 | 
			
		||||
      baseURL: baseUrl,
 | 
			
		||||
      paramsSerializer: params =>
 | 
			
		||||
        qs.stringify(decamelizeKeys(params), { indices: false, filter: (prefix, value) => value ?? '' })
 | 
			
		||||
    });
 | 
			
		||||
    engineCache.interceptors.response.use(undefined, error => {
 | 
			
		||||
      switch(error?.response?.status) {
 | 
			
		||||
        case 403:
 | 
			
		||||
          // alertError("登录信息已失效")
 | 
			
		||||
          // history.go(-1)
 | 
			
		||||
          // window.location.replace("/login")
 | 
			
		||||
          return
 | 
			
		||||
        default:
 | 
			
		||||
      }
 | 
			
		||||
      if (error?.response?.data?.message || error?.response?.data) {
 | 
			
		||||
        message.error(error?.response?.data?.message || error?.response?.data);
 | 
			
		||||
      }
 | 
			
		||||
      return Promise.reject(error?.response?.data ?? error)}
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  if ((forceUnauthorized ?? false) || isNil(token)) {
 | 
			
		||||
    delete engineCache.defaults.headers.common['Authorization'];
 | 
			
		||||
  } else {
 | 
			
		||||
    engineCache.defaults.headers.common['Authorization'] = `Bearer ${token}`;
 | 
			
		||||
  }
 | 
			
		||||
  return engineCache;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const OK = 200
 | 
			
		||||
 | 
			
		||||
export function getToken(): string {
 | 
			
		||||
  return `Bearer ${localStorage.getItem('token')}`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										336
									
								
								src/queries/calculate.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								src/queries/calculate.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,336 @@
 | 
			
		||||
import type { BaseResponse, Pageable } from '@/shared/model-components';
 | 
			
		||||
import { ajaxEngine } from '@q/axios_instance';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
import type {
 | 
			
		||||
  ReportInfo,
 | 
			
		||||
  ReportSteps,
 | 
			
		||||
  SummaryCaculateResult,
 | 
			
		||||
  ReportMaintenance,
 | 
			
		||||
  MeterRecord
 | 
			
		||||
} from '@/shared/model-calculate';
 | 
			
		||||
import type { MaintenanceFormData } from '@q/park';
 | 
			
		||||
import { downloadFile } from '@q/common';
 | 
			
		||||
import type { UploadExcelError } from '@/shared/model-park';
 | 
			
		||||
import { ReportFilled } from '@/shared/model-calculate';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 列出当前所有园区最新的报表
 | 
			
		||||
 * @returns 报表
 | 
			
		||||
 */
 | 
			
		||||
export async function reportList(): Promise<BaseResponse & { parks: ReportInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/reports/with/drafts`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 撤回公示
 | 
			
		||||
 * @param rid 核算记录Id
 | 
			
		||||
 */
 | 
			
		||||
export async function withdraw(rid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/withdraw/${rid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 初始化指定园区的报表
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param period 期数
 | 
			
		||||
 */
 | 
			
		||||
export async function initReport(pid: string, period: string): Promise<BaseResponse & { reportId: string }> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/park/${pid}/report?period=${period}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取指定报表的步骤状态
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 */
 | 
			
		||||
export async function stepState(rid: string): Promise<BaseResponse & { steps: ReportSteps }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/report/${rid}/step/state`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SaveElectricBody {
 | 
			
		||||
  /** 园区ID */
 | 
			
		||||
  parkId: string;
 | 
			
		||||
  /** 核算起始时间 */
 | 
			
		||||
  periodBegin: string;
 | 
			
		||||
  /** 核算结束时间 */
 | 
			
		||||
  periodEnd: string;
 | 
			
		||||
  /** 线损率 */
 | 
			
		||||
  authorizedLossRate: string;
 | 
			
		||||
  /** 调整电费 */
 | 
			
		||||
  adjustFee: string;
 | 
			
		||||
  /** 基本电费 */
 | 
			
		||||
  basicFee: string;
 | 
			
		||||
  /** 有功(尖峰)电量 */
 | 
			
		||||
  critical: string;
 | 
			
		||||
  /** 有功(尖峰)电费 */
 | 
			
		||||
  criticalFee: string;
 | 
			
		||||
  /** 有功(总)电量,总电量 */
 | 
			
		||||
  overall: string;
 | 
			
		||||
  /** 有功(总)电费,总电费 */
 | 
			
		||||
  overallFee: string;
 | 
			
		||||
  /** 有功(峰)电量 */
 | 
			
		||||
  peak: string;
 | 
			
		||||
  /** 有功(峰)电费 */
 | 
			
		||||
  peakFee: string;
 | 
			
		||||
  /** 有功(谷)电量 */
 | 
			
		||||
  valley: string;
 | 
			
		||||
  /** 有功(谷)电费 */
 | 
			
		||||
  valleyFee: string;
 | 
			
		||||
  /** 光伏发电电量 */
 | 
			
		||||
  generateAmount: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 试计算电量电费信息
 | 
			
		||||
 * @param data 需要提交的字段
 | 
			
		||||
 * @return 计算结果
 | 
			
		||||
 */
 | 
			
		||||
export async function calculateElectric(
 | 
			
		||||
  data: SaveElectricBody
 | 
			
		||||
): Promise<BaseResponse & { summary?: SummaryCaculateResult }> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/report/calculate`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 计算并保存填写的园区电量,此操作会记录到数据库并更新步骤状态
 | 
			
		||||
 * @param data 需要提交的字段
 | 
			
		||||
 */
 | 
			
		||||
export async function saveElectric(data: SaveElectricBody): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/report`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 计算并更新填写的园区电量,此操作会记录到数据库并更新步骤状态
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 * @param data 需要提交的字段
 | 
			
		||||
 */
 | 
			
		||||
export async function updateElectric(rid: string, data: SaveElectricBody): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/report/${rid}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 列出目前报表中待摊薄的维护费
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 */
 | 
			
		||||
export async function reportMaintenance(rid: string): Promise<BaseResponse & { fees: ReportMaintenance[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/report/${rid}/maintenance`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除指定维护费条目
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 * @param mid 要删除的维护费ID
 | 
			
		||||
 */
 | 
			
		||||
export async function deleteMaintenance(rid: string, mid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/report/${rid}/maintenance/${mid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 从预置维护表中导入维护费项目
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 */
 | 
			
		||||
export async function importMaintenance(rid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/report/${rid}/maintenance/import`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 更改待摊薄费用编辑步骤状态
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 */
 | 
			
		||||
export async function saveMaintenance(rid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/report/${rid}/step/diluted/fees`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 增加一个临时维护费项目
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 * @param data
 | 
			
		||||
 */
 | 
			
		||||
export async function createTempMaintenance(rid: string, data: MaintenanceFormData): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/report/${rid}/maintenance`, {
 | 
			
		||||
    ...data,
 | 
			
		||||
    period: data.period.format('YYYY')
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改配电维护费的信息
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 * @param mid 配电维护费Id
 | 
			
		||||
 * @param data
 | 
			
		||||
 */
 | 
			
		||||
export async function editMaintenance(
 | 
			
		||||
  rid: string,
 | 
			
		||||
  mid: string,
 | 
			
		||||
  data: { fee?: string; memo?: string; name?: string }
 | 
			
		||||
): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/report/${rid}/maintenance/${mid}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改配电维护费的信息
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 */
 | 
			
		||||
export function downloadMeterTemplate(rid: string) {
 | 
			
		||||
  downloadFile(`/report/${rid}/meter/template`);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 导出计算信息
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 * @param pid
 | 
			
		||||
 * @param periodBegin
 | 
			
		||||
 * @param periodEnd
 | 
			
		||||
 */
 | 
			
		||||
export async function downloadCalculate(rid: string, pid: string, periodBegin, periodEnd) {
 | 
			
		||||
  return downloadFile(`/report/export/${rid}/${pid}?periodBegin=${periodBegin}&periodEnd=${periodEnd}`);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 上传户表抄表记录Excel
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 * @param file 文件对象
 | 
			
		||||
 * @param onProgress 进度监听
 | 
			
		||||
 */
 | 
			
		||||
export async function uploadMeterRecordFile(
 | 
			
		||||
  rid: string,
 | 
			
		||||
  file: File,
 | 
			
		||||
  onProgress?: (percent: number) => void
 | 
			
		||||
): Promise<BaseResponse & { errors: UploadExcelError[] | null }> {
 | 
			
		||||
  const response = await ajaxEngine().postForm(
 | 
			
		||||
    `/report/${rid}/meter/batch`,
 | 
			
		||||
    { data: file },
 | 
			
		||||
    { onUploadProgress: (e: ProgressEvent) => onProgress?.(e.loaded / e.total) }
 | 
			
		||||
  );
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取报表中户表记录列表
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 * @param page
 | 
			
		||||
 * @param keyword
 | 
			
		||||
 */
 | 
			
		||||
export async function meterRecords(
 | 
			
		||||
  rid: string,
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword: string
 | 
			
		||||
): Promise<BaseResponse & Pageable & { meters: MeterRecord[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/report/${rid}/submeter`, { params: { page, keyword } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改指定户表抄表记录
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param mid 表号
 | 
			
		||||
 * @param data
 | 
			
		||||
 */
 | 
			
		||||
export async function editMeterRecords(
 | 
			
		||||
  rid: string,
 | 
			
		||||
  pid: string,
 | 
			
		||||
  mid: string,
 | 
			
		||||
  data: Partial<MeterRecord>
 | 
			
		||||
): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/report/${rid}/submeter/${pid}/${mid}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 更改抄表步骤状态
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 */
 | 
			
		||||
export async function saveMeterStatus(rid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/report/${rid}/step/meter/register`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 对报表中已有的数据进行计算
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 */
 | 
			
		||||
export async function tryCalculate(rid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/report/${rid}/calculate`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 发布指定的电费公示报表
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 */
 | 
			
		||||
export async function publishReport(rid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/report/${rid}/publish`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 列举未发布报表接口
 | 
			
		||||
 */
 | 
			
		||||
export async function reportsDraft(
 | 
			
		||||
  user: string
 | 
			
		||||
): Promise<BaseResponse & Pageable & { reports: (Omit<ReportInfo, 'user'> & { message?: string })[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/report/draft`, { params: { user } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 综合列举报表接口
 | 
			
		||||
 * @param user
 | 
			
		||||
 * @param park
 | 
			
		||||
 * @param page
 | 
			
		||||
 * @param keyword
 | 
			
		||||
 * @param periodStart 报表核算起始日期,格式:yyyy-MM-dd,定义核算起始的时间,之后的都会列出。
 | 
			
		||||
 * @param periodEnd 报表核算的结束日期,格式:yyyy-MM-dd,定义核算最终结束的时间,之前的都会列出。
 | 
			
		||||
 * @param all
 | 
			
		||||
 */
 | 
			
		||||
export async function reports(
 | 
			
		||||
  user: string,
 | 
			
		||||
  park: string,
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword?: string,
 | 
			
		||||
  periodStart?: string,
 | 
			
		||||
  periodEnd?: string,
 | 
			
		||||
  all = 0
 | 
			
		||||
): Promise<BaseResponse & Pageable & { reports: ReportInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/reports`, {
 | 
			
		||||
    params: { user, park, page, keyword, periodStart, periodEnd, all }
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 执行核算报表的计算
 | 
			
		||||
 * @param rid 记录Id
 | 
			
		||||
 */
 | 
			
		||||
export async function calculate(rid: string) {
 | 
			
		||||
  return unwrap(await ajaxEngine().put(`/report/${rid}/calculate`));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 发布指定的电费公示报表
 | 
			
		||||
 * @param rid 记录Id
 | 
			
		||||
 */
 | 
			
		||||
export async function publish(rid: string) {
 | 
			
		||||
  return unwrap(await ajaxEngine().post(`/report/${rid}/publish`));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取已填写的园区电量信息
 | 
			
		||||
 */
 | 
			
		||||
export async function getReportFilled(rid: string): Promise<BaseResponse & { summary: ReportFilled }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/report/${rid}/summary/filled`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										114
									
								
								src/queries/charge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/queries/charge.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
			
		||||
import type { BaseResponse, Pageable } from '@/shared/model-components';
 | 
			
		||||
import { ajaxEngine } from '@q/axios_instance';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
import { ChargeInfo } from '@/shared/model-charge';
 | 
			
		||||
import qs from 'qs';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取符合条件的商户充值记录
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param keyword 关键词
 | 
			
		||||
 * @param startDate 起始时间
 | 
			
		||||
 * @param endDate 截止时间
 | 
			
		||||
 * @param typeNumber
 | 
			
		||||
 */
 | 
			
		||||
export async function chargeList(
 | 
			
		||||
  pid: string,
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword?: string,
 | 
			
		||||
  startDate?: string,
 | 
			
		||||
  endDate?: string,
 | 
			
		||||
  typeNumber?: number
 | 
			
		||||
): Promise<BaseResponse & Pageable & { topUps: ChargeInfo[], amount: number }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/topup/${pid}?${qs.stringify({ page, keyword, startDate, endDate, type: typeNumber })}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除一个充值记录
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param tid 充值记录Id
 | 
			
		||||
 */
 | 
			
		||||
export async function cancelCharge(pid: string, tid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/topup/${pid}/${tid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取用于下拉列表的商户列表
 | 
			
		||||
 * @param park 园区Id
 | 
			
		||||
 * @param keyword 检索关键字
 | 
			
		||||
 */
 | 
			
		||||
export async function tenementSearchChoice(
 | 
			
		||||
  park: string,
 | 
			
		||||
  keyword: string
 | 
			
		||||
): Promise<BaseResponse & { tenements: { fullName: string; id: string; park: string; shortName: string; parkName: string }[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get('/tenement/choice', { params: { park, keyword, limit: 10 } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取用于下拉列表的商户列表
 | 
			
		||||
 * @param keyword 检索关键字
 | 
			
		||||
 */
 | 
			
		||||
export async function tenementSearchChoiceByName(
 | 
			
		||||
  keyword: string
 | 
			
		||||
): Promise<BaseResponse & { tenements: { fullName: string; id: string; park: string; shortName: string; parkName: string }[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get('/tenement/choice', { params: { keyword, limit: 10 } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取用于下拉列表的商户列表,根据用户简称搜索
 | 
			
		||||
 * @param parkid
 | 
			
		||||
 * @param name
 | 
			
		||||
 */
 | 
			
		||||
export async function tenementSearchChoiceByShortName(
 | 
			
		||||
  parkid: string,
 | 
			
		||||
  name: string,
 | 
			
		||||
): Promise<BaseResponse & { tenements: { fullName: string; id: string; park: string; shortName: string }[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get('/tenement/name', { params: { parkid, name, limit: 10 } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 创建一个新的充值记录
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param data
 | 
			
		||||
 */
 | 
			
		||||
export async function createCharge(pid: string, data: { 
 | 
			
		||||
  amount: string; 
 | 
			
		||||
  meter: string; 
 | 
			
		||||
  tenement: string; 
 | 
			
		||||
  paymentType: number, 
 | 
			
		||||
  voucherNo: string, 
 | 
			
		||||
  type: "0" | "1" | "2",
 | 
			
		||||
  flowType: number,
 | 
			
		||||
  fileList?: string[]
 | 
			
		||||
}) {
 | 
			
		||||
  const response = await ajaxEngine().post(`/topup/${pid}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改一个新的充值记录
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param tid 记录id
 | 
			
		||||
 * @param data
 | 
			
		||||
 */
 | 
			
		||||
export async function updateCharge(tid: string, data: { 
 | 
			
		||||
  amount: string; 
 | 
			
		||||
  meter: string; 
 | 
			
		||||
  tenement: string; 
 | 
			
		||||
  paymentType: number, 
 | 
			
		||||
  voucherNo: string, 
 | 
			
		||||
  type: "0" | "1" | "2",
 | 
			
		||||
  flowType: number,
 | 
			
		||||
  fileList?: string[]
 | 
			
		||||
}) {
 | 
			
		||||
  const response = await ajaxEngine().put(`/topup/${tid}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										119
									
								
								src/queries/common.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								src/queries/common.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
import type { BaseResponse } from '@/shared/model-components';
 | 
			
		||||
import { ajaxEngine } from '@q/axios_instance';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
import {alertError} from "@/utils";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 行政区划
 | 
			
		||||
 */
 | 
			
		||||
export interface Region {
 | 
			
		||||
  /** 行政区划编号 */
 | 
			
		||||
  code: string;
 | 
			
		||||
  /** 行政区划级别 [0-3] */
 | 
			
		||||
  level: number;
 | 
			
		||||
  /** 行政区划名称 */
 | 
			
		||||
  name: string;
 | 
			
		||||
  /** 父级行政区划编号 */
 | 
			
		||||
  parent: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取行政区划下的子级行政区划。
 | 
			
		||||
 * @param rid 父级行政区划编号,0:顶级行政区划
 | 
			
		||||
 */
 | 
			
		||||
export async function regions(rid: string | 0): Promise<BaseResponse & { regions: Region[] }> {
 | 
			
		||||
  const response = await ajaxEngine(true).get(`/region/${rid || 0}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取指定行政区划所在的所有区划信息。
 | 
			
		||||
 * @param rid 行政区划编号
 | 
			
		||||
 */
 | 
			
		||||
export async function regionsDetail(rid: string): Promise<BaseResponse & { regions: Region[] }> {
 | 
			
		||||
  const response = await ajaxEngine(true).get(`/regions/${rid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 下载文件函数封装
 | 
			
		||||
 * @param url 文件地址
 | 
			
		||||
 */
 | 
			
		||||
export function downloadFile(url: string) {
 | 
			
		||||
  return fetch(ajaxEngine().defaults.baseURL + url, {
 | 
			
		||||
    headers: { ...ajaxEngine().defaults.headers.common, Accept: 'application/octet-stream' }
 | 
			
		||||
  })
 | 
			
		||||
    .then(async response => {
 | 
			
		||||
      const content = response.headers.get('content-disposition')
 | 
			
		||||
 | 
			
		||||
      if (content == null) {
 | 
			
		||||
        alertError("服务错误")
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      const fileName = content.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)[1];
 | 
			
		||||
      return { file: await response.blob(), name: decodeURI(fileName) };
 | 
			
		||||
    })
 | 
			
		||||
    .then(res => {
 | 
			
		||||
      const link = document.createElement('a');
 | 
			
		||||
      link.href = URL.createObjectURL(res.file);
 | 
			
		||||
      link.download = res.name;
 | 
			
		||||
      link.click();
 | 
			
		||||
      URL.revokeObjectURL(link.href);
 | 
			
		||||
    })
 | 
			
		||||
    .catch(error => {
 | 
			
		||||
      console.error('Error downloading file:', error);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用户服务期限查询。
 | 
			
		||||
 */
 | 
			
		||||
export async function expiration(): Promise<BaseResponse & { expiration: string }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/expiration`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 待审核内容数量。
 | 
			
		||||
 */
 | 
			
		||||
export async function audits(): Promise<BaseResponse & { amounts: { withdraw: number } }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/audits`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface StatisticResponse {
 | 
			
		||||
  // 企业用户数量
 | 
			
		||||
  enterprises: number;
 | 
			
		||||
  // 园区数量
 | 
			
		||||
  parks: number;
 | 
			
		||||
  reports: {
 | 
			
		||||
    // 园区ID
 | 
			
		||||
    id: string;
 | 
			
		||||
    // 园区名称
 | 
			
		||||
    name: string;
 | 
			
		||||
    // 最新期数
 | 
			
		||||
    period: null | string;
 | 
			
		||||
  }[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 统计当前系统中的报表
 | 
			
		||||
 */
 | 
			
		||||
export async function statistic(): Promise<BaseResponse & { statistics: StatisticResponse }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/stat/reports`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 获取系统中定义的基准核定线损率
 | 
			
		||||
 */
 | 
			
		||||
export async function normLossRate(): Promise<BaseResponse & { normAuthorizedLossRate: string }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/norm/authorized/loss/rate`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 获取系统中定义的基准核定税率
 | 
			
		||||
 */
 | 
			
		||||
export async function normLossTax(): Promise<BaseResponse & { normAuthorizedTaxRate: string }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/norm/authorized/tax`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										385
									
								
								src/queries/equipment.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										385
									
								
								src/queries/equipment.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,385 @@
 | 
			
		||||
import qs from 'qs';
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
    BatchMeterResult,
 | 
			
		||||
    BatchModeForm,
 | 
			
		||||
    BatchParamsForm,
 | 
			
		||||
    BatchSwitchForm,
 | 
			
		||||
  BatchTroubleForm,
 | 
			
		||||
  BatchWarningForm,
 | 
			
		||||
  BindCardForm,
 | 
			
		||||
  BindProtocolForm,
 | 
			
		||||
  CardForm,
 | 
			
		||||
  CardListItem,
 | 
			
		||||
  CardListQuery,
 | 
			
		||||
  ChangeMeterEnabledForm,
 | 
			
		||||
  FactoryForm,
 | 
			
		||||
  FactoryListItem,
 | 
			
		||||
  FactoryListQuery,
 | 
			
		||||
  MeterOperateListItem,
 | 
			
		||||
  MeterOperateListQuery,
 | 
			
		||||
  MeterSettingForm,
 | 
			
		||||
  MeterSettingListItem,
 | 
			
		||||
  MeterSettingListQuery,
 | 
			
		||||
  NestedMeterForm,
 | 
			
		||||
  NestedMeterListItem,
 | 
			
		||||
  ProtocolForm,
 | 
			
		||||
  ProtocolListItem,
 | 
			
		||||
  ProtocolListQuery
 | 
			
		||||
} from '@/shared/equipment';
 | 
			
		||||
import type {
 | 
			
		||||
  BaseResponse,
 | 
			
		||||
  Pageable
 | 
			
		||||
} from '@/shared/model-components';
 | 
			
		||||
import { UploadExcelError } from '@/shared/model-park';
 | 
			
		||||
import { ajaxEngine } from '@q/axios_instance';
 | 
			
		||||
import { downloadFile } from '@q/common';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
import { Key } from 'react';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取卡列表
 | 
			
		||||
 * @param query CardListQuery
 | 
			
		||||
 */
 | 
			
		||||
export async function getCardList(query: CardListQuery): Promise<BaseResponse & Pageable & { data: CardListItem[], amount: number }> {
 | 
			
		||||
    const response = await ajaxEngine().get(`/equipment/getCardList?${qs.stringify(query)}`, {});
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 创建卡
 | 
			
		||||
 * @param data CardForm
 | 
			
		||||
 */
 | 
			
		||||
export async function createCard(data: CardForm): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().post(`/equipment/createCard`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改卡
 | 
			
		||||
 * @param data CardForm
 | 
			
		||||
 * @param id string
 | 
			
		||||
 */
 | 
			
		||||
export async function updateCard(data: CardForm, id: string): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().put(`/equipment/updateCard/${id}`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除卡
 | 
			
		||||
 * @param id string
 | 
			
		||||
 */
 | 
			
		||||
export async function deleteCard(id: string): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().delete(`/equipment/deleteCard/${id}`);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 上传卡
 | 
			
		||||
 * @param park 园区id
 | 
			
		||||
 * @param file 文件对象
 | 
			
		||||
 * @param onProgress 进度监听
 | 
			
		||||
 */
 | 
			
		||||
export async function uploadCard(
 | 
			
		||||
    park: string,
 | 
			
		||||
    file: File,
 | 
			
		||||
    onProgress?: (percent: number) => void
 | 
			
		||||
): Promise<BaseResponse & { errors: UploadExcelError[] | null }> {
 | 
			
		||||
    const response = await ajaxEngine().postForm(
 | 
			
		||||
        `/equipment/uploadCard/${park}`,
 | 
			
		||||
        { data: file },
 | 
			
		||||
        { onUploadProgress: (e: ProgressEvent) => onProgress?.(e.loaded / e.total) }
 | 
			
		||||
    );
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 导出卡模板
 | 
			
		||||
 */
 | 
			
		||||
export async function downloadCardTemplate() {
 | 
			
		||||
    return downloadFile(`/equipment/exportCardTemplate`);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 导出卡数据
 | 
			
		||||
 */
 | 
			
		||||
export async function downloadCard(park: string, query: any) {
 | 
			
		||||
    return downloadFile(`/equipment/exportCard/${park}?${qs.stringify(query)}`);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 获取通讯协议列表
 | 
			
		||||
 * @param query CardListQuery
 | 
			
		||||
 */
 | 
			
		||||
export async function getProtocolList(query: ProtocolListQuery): Promise<BaseResponse & Pageable & { data: ProtocolListItem[] }> {
 | 
			
		||||
    const response = await ajaxEngine().get(`/equipment/getProtocolList?${qs.stringify(query)}`, {});
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 导出通讯协议模板
 | 
			
		||||
 */
 | 
			
		||||
export async function downloadProtocolTemplate() {
 | 
			
		||||
    return downloadFile(`/equipment/exportProtocolTemplate`);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 导出通讯协议数据
 | 
			
		||||
 */
 | 
			
		||||
export async function downloadProtocol(park: string, query: any) {
 | 
			
		||||
    return downloadFile(`/equipment/exportCard/${park}?${qs.stringify(query)}`);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 上传通讯协议
 | 
			
		||||
 * @param park 园区id
 | 
			
		||||
 * @param file 文件对象
 | 
			
		||||
 * @param onProgress 进度监听
 | 
			
		||||
 */
 | 
			
		||||
export async function uploadProtocol(
 | 
			
		||||
    park: string,
 | 
			
		||||
    file: File,
 | 
			
		||||
    onProgress?: (percent: number) => void
 | 
			
		||||
): Promise<BaseResponse & { errors: UploadExcelError[] | null }> {
 | 
			
		||||
    const response = await ajaxEngine().postForm(
 | 
			
		||||
        `/equipment/uploadCard/${park}`,
 | 
			
		||||
        { data: file },
 | 
			
		||||
        { onUploadProgress: (e: ProgressEvent) => onProgress?.(e.loaded / e.total) }
 | 
			
		||||
    );
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 创建通讯协议
 | 
			
		||||
 * @param data CardForm
 | 
			
		||||
 */
 | 
			
		||||
export async function createProtocol(data: ProtocolForm): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().post(`/equipment/createProtocol`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改通讯协议
 | 
			
		||||
 * @param data CardForm
 | 
			
		||||
 * @param id string
 | 
			
		||||
 */
 | 
			
		||||
export async function updateProtocol(data: ProtocolForm, id: string): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().put(`/equipment/updateProtocol/${id}`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除通讯协议
 | 
			
		||||
 * @param id string
 | 
			
		||||
 */
 | 
			
		||||
export async function deleteProtocol(id: string): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().delete(`/equipment/deleteProtocol/${id}`);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取厂家列表
 | 
			
		||||
 * @param query FactoryListQuery
 | 
			
		||||
 */
 | 
			
		||||
export async function getFactoryList(query: FactoryListQuery): Promise<BaseResponse & Pageable & { data: FactoryListItem[] }> {
 | 
			
		||||
    const response = await ajaxEngine().get(`/equipment/getManufacturersList?${qs.stringify(query)}`, {});
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 创建厂家
 | 
			
		||||
 * @param data CardForm
 | 
			
		||||
 */
 | 
			
		||||
export async function createFactory(data: FactoryForm): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().post(`/equipment/createManufacturers`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 修改厂家
 | 
			
		||||
 * @param data CardForm
 | 
			
		||||
 * @param id string
 | 
			
		||||
 */
 | 
			
		||||
export async function updateFactory(data: FactoryForm, id: string): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().put(`/equipment/updateManufacturers/${id}`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除厂家
 | 
			
		||||
 * @param id string
 | 
			
		||||
 */
 | 
			
		||||
export async function deleteFactory(id: string): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().delete(`/equipment/deleteManufacturers/${id}`);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 导出厂家模板
 | 
			
		||||
 */
 | 
			
		||||
export async function downloadFactoryTemplate() {
 | 
			
		||||
    return downloadFile(`/equipment/exportManufacturersTemplate`);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 导出通讯协议数据
 | 
			
		||||
 */
 | 
			
		||||
export async function downloadFactory(park: string, query: any) {
 | 
			
		||||
    return downloadFile(`/equipment/exportManufacturers/${park}?${qs.stringify(query)}`);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 上传通讯协议
 | 
			
		||||
 * @param park 园区id
 | 
			
		||||
 * @param file 文件对象
 | 
			
		||||
 * @param onProgress 进度监听
 | 
			
		||||
 */
 | 
			
		||||
export async function uploadFactory(
 | 
			
		||||
    park: string,
 | 
			
		||||
    file: File,
 | 
			
		||||
    onProgress?: (percent: number) => void
 | 
			
		||||
): Promise<BaseResponse & { errors: UploadExcelError[] | null }> {
 | 
			
		||||
    const response = await ajaxEngine().postForm(
 | 
			
		||||
        `/equipment/uploadCard/${park}`,
 | 
			
		||||
        { data: file },
 | 
			
		||||
        { onUploadProgress: (e: ProgressEvent) => onProgress?.(e.loaded / e.total) }
 | 
			
		||||
    );
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取电表设置列表
 | 
			
		||||
 * @param query MeterSettingListQuery
 | 
			
		||||
 */
 | 
			
		||||
export async function getMeterSettingList(query: MeterSettingListQuery): Promise<BaseResponse & Pageable & { data: MeterSettingListItem[] }> {
 | 
			
		||||
    const response = await ajaxEngine().get(`/equipment/getMeterSettingList?${qs.stringify(query)}`, {});
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 绑定网关
 | 
			
		||||
 * @param data BindProtocolForm
 | 
			
		||||
 */
 | 
			
		||||
export async function bindProtocol(data: BindProtocolForm): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().post(`/equipment/bindProtocol`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 新增电表设置
 | 
			
		||||
 * @param data BindProtocolForm
 | 
			
		||||
 */
 | 
			
		||||
export async function createMeterSetting(pid: string, data: MeterSettingForm): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().post(`/meter/${pid}`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 编辑电表设置
 | 
			
		||||
 * @param data BindProtocolForm
 | 
			
		||||
 */
 | 
			
		||||
export async function updateMeterSetting(pid: string, id: string, data: MeterSettingForm): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().put(`/meter/${pid}/${id}`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 绑定卡
 | 
			
		||||
 * @param data BindProtocolForm
 | 
			
		||||
 */
 | 
			
		||||
export async function bindCard(data: BindCardForm): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().post(`/equipment/bindCard`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 批量设置电表参数
 | 
			
		||||
 * @param data BindProtocolForm
 | 
			
		||||
 */
 | 
			
		||||
export async function batchSetMeterParams(data: BatchParamsForm): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().put(`/equipment/setMeterParams`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取电表操作列表
 | 
			
		||||
 * @param query MeterSettingListQuery
 | 
			
		||||
 */
 | 
			
		||||
export async function getMeterOperateList(query: MeterOperateListQuery): Promise<BaseResponse & Pageable & { data: MeterOperateListItem[] }> {
 | 
			
		||||
    const response = await ajaxEngine().get(`/equipment/getOperateMeterList?${qs.stringify(query)}`, {});
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 批量拉,合闸
 | 
			
		||||
 * @param data BindProtocolForm
 | 
			
		||||
 */
 | 
			
		||||
export async function batchSwtich(data: BatchSwitchForm): Promise<BaseResponse & { data: BatchMeterResult[] }> {
 | 
			
		||||
    const response = await ajaxEngine().put(`/equipment/batchSwtich`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 批量下发预警短信
 | 
			
		||||
 * @param data BindProtocolForm
 | 
			
		||||
 */
 | 
			
		||||
export async function batchSendMessage(data: {ids: Key[]}): Promise<BaseResponse & { data: BatchMeterResult[] }> {
 | 
			
		||||
    const response = await ajaxEngine().put(`/equipment/batchSendMessage`, data);
 | 
			
		||||
    return unwrap(response);    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 批量设置强控和预付费
 | 
			
		||||
 * @param data BindProtocolForm
 | 
			
		||||
 */
 | 
			
		||||
export async function batchMode(data: BatchModeForm): Promise<BaseResponse  & { data: BatchMeterResult[] }> {
 | 
			
		||||
    const response = await ajaxEngine().put(`/equipment/batchSetMode`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 批量设置告警
 | 
			
		||||
 * @param data BindProtocolForm
 | 
			
		||||
 */
 | 
			
		||||
export async function batchSetWarning(data: BatchWarningForm): Promise<BaseResponse  & { data: BatchMeterResult[] }> {
 | 
			
		||||
    const response = await ajaxEngine().put(`/equipment/batchSetWarning`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 批量故障申报
 | 
			
		||||
 * @param data BindProtocolForm
 | 
			
		||||
 */
 | 
			
		||||
export async function batchSetTrouble(data: BatchTroubleForm): Promise<BaseResponse  & { data: BatchMeterResult[] }> {
 | 
			
		||||
    const response = await ajaxEngine().put(`/equipment/setTrouble`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取套表列表
 | 
			
		||||
 * @param query MeterSettingListQuery
 | 
			
		||||
 */
 | 
			
		||||
export async function getNestedMeterList(park: string, query: { page: number }): Promise<BaseResponse & Pageable & { data: NestedMeterListItem[] }> {
 | 
			
		||||
    const response = await ajaxEngine().get(`/equipment/getNestedMeterList/${park}?${qs.stringify(query)}`, {});
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 新增套表
 | 
			
		||||
 * @param data BindProtocolForm
 | 
			
		||||
 */
 | 
			
		||||
export async function addNestedMeter(data: NestedMeterForm): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().post(`/equipment/addNestedMeter`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 设置表停,启用
 | 
			
		||||
 * @param data BindProtocolForm
 | 
			
		||||
 */
 | 
			
		||||
export async function changeMeterEnabled(data: ChangeMeterEnabledForm): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().put(`/equipment/changeMeterEnabled`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 新增套表
 | 
			
		||||
 * @param data BindProtocolForm
 | 
			
		||||
 */
 | 
			
		||||
export async function deleteNestedMeter(id: string): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().delete(`/equipment/deleteNestedMeter/${id}`);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 编辑套表
 | 
			
		||||
 * @param data BindProtocolForm
 | 
			
		||||
 */
 | 
			
		||||
export async function updateNestedMeter(id: string, data: NestedMeterForm): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().put(`/equipment/updateNestedMeter/${id}`, data);
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								src/queries/flow.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/queries/flow.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
import { ajaxEngine } from "./axios_instance"
 | 
			
		||||
import {unwrap} from "@u/asyncs";
 | 
			
		||||
import qs from "qs";
 | 
			
		||||
import {BaseResponse} from "@/shared/model-components";
 | 
			
		||||
import {ApproveListQuery, DisposeFlow, FlowDetail, FlowForm, FlowListItem} from "@/shared/model-flow";
 | 
			
		||||
import {BaseUserInfo} from "@/shared/model-user";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取审批流程列表
 | 
			
		||||
 * */
 | 
			
		||||
export async function getFlowList() : Promise<BaseResponse & { data: FlowListItem[], total: number }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/flow/list`)
 | 
			
		||||
  return unwrap(response)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 新建审批流程
 | 
			
		||||
 * */
 | 
			
		||||
export async function createFlow(data: FlowForm) : Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/flow/create`, data)
 | 
			
		||||
  return unwrap(response)
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 获取审批流程列表
 | 
			
		||||
 * */
 | 
			
		||||
export async function getApproveList(data: ApproveListQuery) : Promise<BaseResponse & { data: FlowListItem[], total: number }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/flow/getDisposeList?${qs.stringify(data)}`)
 | 
			
		||||
  return unwrap(response)
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 更新审批流程
 | 
			
		||||
 * */
 | 
			
		||||
export async function updateFlow(id: string, data: FlowForm) : Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/flow/${id}/update`, data)
 | 
			
		||||
  return unwrap(response)
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 删除审批流程
 | 
			
		||||
 * */
 | 
			
		||||
export async function deleteFlow(id: string) : Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/flow/${id}/delete`)
 | 
			
		||||
  return unwrap(response)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取可审核的所有用户
 | 
			
		||||
 * */
 | 
			
		||||
export async function getApproveUserList() : Promise<BaseResponse & { data: BaseUserInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/flow/allUser`)
 | 
			
		||||
  return unwrap(response)
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 处理当前申请
 | 
			
		||||
 * */
 | 
			
		||||
export async function disposeFlow(id: string, data: DisposeFlow) : Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/flow/${id}/dispose`, data)
 | 
			
		||||
  return unwrap(response)
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 删除文件
 | 
			
		||||
 * */
 | 
			
		||||
export async function deleteFile(url: string) : Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/file/delete?path=${url}`)
 | 
			
		||||
  return unwrap(response)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取当前审批的详情
 | 
			
		||||
 * */
 | 
			
		||||
export async function getApproveDetail(id: string) : Promise<BaseResponse & { data: FlowDetail }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/flow/${id}/detail`)
 | 
			
		||||
  return unwrap(response)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										182
									
								
								src/queries/god_mode.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								src/queries/god_mode.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,182 @@
 | 
			
		||||
import type { BaseResponse } from '@/shared/model-components';
 | 
			
		||||
import { ajaxEngine } from '@q/axios_instance';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求重置指定报表的园区总计部分。
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 * @param rid 要做重置处理的报表ID
 | 
			
		||||
 * @returns 报表的重置操作处理结果。
 | 
			
		||||
 */
 | 
			
		||||
export async function resetReportSummary(rid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/report/${rid}/summary`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求删除指定报表的维护费部分。
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 * @param rid 要做重置处理的报表ID
 | 
			
		||||
 * @returns 报表的重置操作处理结果。
 | 
			
		||||
 */
 | 
			
		||||
export async function removeReportMaintenanceFees(rid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/report/${rid}/maintenance`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求重置指定报表的抄表记录部分。
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 * @param rid 要做重置处理的报表ID
 | 
			
		||||
 * @returns 报表的重置操作处理结果。
 | 
			
		||||
 */
 | 
			
		||||
export async function resetReportEndUserRegister(rid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/report/${rid}/meters`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求重新同步指定报表的抄表记录的基本档案。
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 * @param rid 要做重新同步处理的报表ID
 | 
			
		||||
 * @returns 报表的重新同步操作处理结果。
 | 
			
		||||
 */
 | 
			
		||||
export async function resynchronizeReportEndUserRegister(rid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/gm/report/${rid}/meters`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求重置指定报表的全部内容。
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 * @param rid 要做重置处理的报表ID
 | 
			
		||||
 * @returns 报表的重置操作处理结果。
 | 
			
		||||
 */
 | 
			
		||||
export async function resetReport(rid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/report/${rid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求强制删除指定报表。
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 * @param rid 要做删除处理的报表ID
 | 
			
		||||
 * @returns 报表的删除操作处理结果。
 | 
			
		||||
 */
 | 
			
		||||
export async function forceRemoveReport(pid: string, rid: string[]): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/report`, { params: { park: pid, reports: rid } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求删除指定园区中的指定配电维护费。
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 * @param pid 要做处理的园区ID
 | 
			
		||||
 * @param mid 要删除的指定维护费ID
 | 
			
		||||
 * @returns 园区配电维护费删除操作处理结果。
 | 
			
		||||
 */
 | 
			
		||||
export async function removeSpecificMaintenanceFeeInPark(pid: string, mid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/park/${pid}/maintenance/${mid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求删除指定园区中的全部配电维护费。
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 * @param id 要做处理的园区ID
 | 
			
		||||
 * @returns 园区配电维护费删除操作处理结果。
 | 
			
		||||
 */
 | 
			
		||||
export async function removeParkMaintenance(pid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/park/${pid}/maintenance`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求删除指定园区中的全部终端用户档案。
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 * @param id 要做处理的园区ID
 | 
			
		||||
 * @returns 园区终端用户档案删除操作处理结果。
 | 
			
		||||
 */
 | 
			
		||||
export async function removeParkMeters(pid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/park/${pid}/meters`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求强制删除指定园区。
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 * @param pid 要做删除处理的园区ID
 | 
			
		||||
 * @returns 园区的删除操作处理结果。
 | 
			
		||||
 */
 | 
			
		||||
export async function forceRemovePark(pid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/park/${pid}/force`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求强制删除指定企业用户。
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 * @param uid 要做删除处理的用户ID
 | 
			
		||||
 * @returns 用户的删除操作处理结果。
 | 
			
		||||
 */
 | 
			
		||||
export async function forceRemoveEnterprise(uid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/enterprise/${uid}/force`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除符合指定条件的表计公摊关系
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 */
 | 
			
		||||
export async function forceDelPoolMeters(park: string, meters: string[] = []): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/meter/pooling`, { params: { park, meters } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除与符合指定条件的商户绑定的表计关系
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 */
 | 
			
		||||
export async function forceDelTenementMeters(
 | 
			
		||||
  park: string,
 | 
			
		||||
  tenements: string[] = [],
 | 
			
		||||
  meters: string[] = []
 | 
			
		||||
): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/tenement/meter`, { params: { park, meters, tenements } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除符合给定条件的抄表记录
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 */
 | 
			
		||||
export async function forceDelReading(
 | 
			
		||||
  park: string,
 | 
			
		||||
  meters: string[] = [],
 | 
			
		||||
  read_at: string[] = []
 | 
			
		||||
): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/reading`, { params: { park, meters, read_at } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除符合给定条件的抄表记录
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 */
 | 
			
		||||
export async function forceDelTenements(park: string, tenements: string[] = []): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/tenement`, { params: { park, tenements } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除符合给定条件的抄表记录
 | 
			
		||||
 * ! 天神模式方法,切勿随意调用。
 | 
			
		||||
 */
 | 
			
		||||
export async function forceDelInvoices(
 | 
			
		||||
  park: string,
 | 
			
		||||
  invoices: string[] = [],
 | 
			
		||||
  tenements: string[] = []
 | 
			
		||||
): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/gm/invoice`, { params: { park, invoices, tenements } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										162
									
								
								src/queries/invoice.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								src/queries/invoice.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,162 @@
 | 
			
		||||
import type { BaseResponse, Pageable } from '@/shared/model-components';
 | 
			
		||||
import { ajaxEngine } from '@q/axios_instance';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
import {cover, InvoiceDetail, InvoiceInfo, TaxMethod, UninvoiceData} from '@/shared/model-invoice';
 | 
			
		||||
import qs from 'qs';
 | 
			
		||||
import { downloadFile } from './common';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取已开具的发票记录列表
 | 
			
		||||
 * @param park
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param keyword 关键词
 | 
			
		||||
 * @param startDate 起始时间
 | 
			
		||||
 * @param endDate 截止时间
 | 
			
		||||
 * @param tenement
 | 
			
		||||
 */
 | 
			
		||||
export async function invoiceList(
 | 
			
		||||
  park: string,
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword?: string,
 | 
			
		||||
  startDate?: string,
 | 
			
		||||
  endDate?: string,
 | 
			
		||||
  tenement?: string,
 | 
			
		||||
): Promise<BaseResponse & Pageable & { invoices: InvoiceInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/invoice`, { params: { park, page, keyword, startDate, endDate, tenement } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除指定发票记录
 | 
			
		||||
 * @param code 发票号码
 | 
			
		||||
 */
 | 
			
		||||
export async function deleteInvoice(code: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/invoice/${code}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 发票详情
 | 
			
		||||
 * @param code 发票编号
 | 
			
		||||
 */
 | 
			
		||||
export async function invoiceDetail(code: string): Promise<BaseResponse & { detail: InvoiceDetail }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/invoice/${code}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取指定用户的未开票核算记录
 | 
			
		||||
 * @param tid 未开票核算信息
 | 
			
		||||
 */
 | 
			
		||||
export async function uninvoicedTenement({
 | 
			
		||||
  page,
 | 
			
		||||
  code,
 | 
			
		||||
  parkId,
 | 
			
		||||
  startDate,
 | 
			
		||||
  endDate,
 | 
			
		||||
  shortName,
 | 
			
		||||
  tenement
 | 
			
		||||
}: {
 | 
			
		||||
  page: number,
 | 
			
		||||
  code: string,
 | 
			
		||||
  parkId?: string,
 | 
			
		||||
  startDate: string,
 | 
			
		||||
  endDate: string,
 | 
			
		||||
  shortName: string,
 | 
			
		||||
  tenement: string,
 | 
			
		||||
}): Promise<BaseResponse & { records: UninvoiceData[], total: number }> {
 | 
			
		||||
 | 
			
		||||
  const response = await ajaxEngine().get(`/uninvoiced/tenement/report?${qs.stringify({ page, code, parkId, startDate, endDate, shortName, tenement })}`, );
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface PrecalculateInvoiceData {
 | 
			
		||||
  /** 覆盖核算报表,列举已选择的核算报表ID */
 | 
			
		||||
  covers: cover[];
 | 
			
		||||
  /** 园区ID */
 | 
			
		||||
  park: string;
 | 
			
		||||
  /** 计税方式,0:核算电费含税,1:核算电费未税 */
 | 
			
		||||
  // taxMethod: TaxMethod;
 | 
			
		||||
  taxMethod: '0' | '1' | '';
 | 
			
		||||
  /** 税率 */
 | 
			
		||||
  // taxRate: number;
 | 
			
		||||
  taxRate: string;
 | 
			
		||||
  /** 商户ID */
 | 
			
		||||
  tenement: string;
 | 
			
		||||
  /** 要核算的表号 */
 | 
			
		||||
  // codes: string [];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 试算发票的票面信息
 | 
			
		||||
 * @param data 预计算信息
 | 
			
		||||
 */
 | 
			
		||||
export async function precalculateInvoice(
 | 
			
		||||
  data: PrecalculateInvoiceData
 | 
			
		||||
): Promise<BaseResponse & { cargos: InvoiceDetail['cargos']; total: string }> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/invoice/precalculate`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface CreateInvoiceData {
 | 
			
		||||
  /** 覆盖核算报表,列举已选择的核算报表ID */
 | 
			
		||||
  covers: cover[];
 | 
			
		||||
  /** 发票号码 */
 | 
			
		||||
  invoiceNo: string;
 | 
			
		||||
  /** 发票类型 */
 | 
			
		||||
  invoiceType: string;
 | 
			
		||||
  /** 园区ID */
 | 
			
		||||
  park: string;
 | 
			
		||||
  /** 计税方式,0:核算电费含税,1:核算电费未税 */
 | 
			
		||||
  taxMethod: TaxMethod;
 | 
			
		||||
  /** 税率 */
 | 
			
		||||
  taxRate: number;
 | 
			
		||||
  /** 商户ID */
 | 
			
		||||
  tenement: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface coverItem {
 | 
			
		||||
  rid: string,
 | 
			
		||||
  code: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface CreateInvoice {
 | 
			
		||||
  /** 覆盖核算报表,列举已选择的核算报表ID */
 | 
			
		||||
  covers: coverItem[];
 | 
			
		||||
  /** 发票号码 */
 | 
			
		||||
  invoiceNo: string;
 | 
			
		||||
  /** 发票类型 */
 | 
			
		||||
  invoiceType: string;
 | 
			
		||||
  /** 园区ID */
 | 
			
		||||
  park: string;
 | 
			
		||||
  /** 计税方式,0:核算电费含税,1:核算电费未税 */
 | 
			
		||||
  taxMethod: '0' | '1';
 | 
			
		||||
  /** 税率 */
 | 
			
		||||
  taxRate: string;
 | 
			
		||||
  /** 商户ID */
 | 
			
		||||
  tenement: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 保存发票开具记录
 | 
			
		||||
 * @param data 信息
 | 
			
		||||
 */
 | 
			
		||||
export async function createInvoice(data: CreateInvoice): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/invoice`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 更新发票号
 | 
			
		||||
 */
 | 
			
		||||
export async function updateInvoiceNo(id: string, invoiceNo: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/invoice`, { "invoice_id": id, "invoice_no": invoiceNo});
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 已开发票
 | 
			
		||||
 */
 | 
			
		||||
export async function downloadInvoice(query) {
 | 
			
		||||
  return downloadFile(`/invoice/export?${qs.stringify(query)}`);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								src/queries/log.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/queries/log.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
import { ajaxEngine } from "./axios_instance"
 | 
			
		||||
import {unwrap} from "@u/asyncs";
 | 
			
		||||
import qs from "qs";
 | 
			
		||||
import type {BaseResponse} from "@/shared/model-components";
 | 
			
		||||
import {Log} from "@/shared/model-log";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除指定的电费退补记录
 | 
			
		||||
 *
 | 
			
		||||
 * */
 | 
			
		||||
export async function getLogList(page: number, startDate: string, endDate: string, type: number): Promise<BaseResponse & { data: Log[], total: number }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/logs/list?${qs.stringify({
 | 
			
		||||
    page, startDate, endDate, type
 | 
			
		||||
  })}`)
 | 
			
		||||
  return unwrap(response)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										634
									
								
								src/queries/park.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										634
									
								
								src/queries/park.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,634 @@
 | 
			
		||||
import type { BaseResponse, Pageable } from '@/shared/model-components';
 | 
			
		||||
import type {
 | 
			
		||||
  ElectrCategory,
 | 
			
		||||
  MaintenanceInfo,
 | 
			
		||||
  MaintenanceSummary,
 | 
			
		||||
  Meter04KvInfo,
 | 
			
		||||
  Meter04KvType, MeterBox,
 | 
			
		||||
  ParkInfo,
 | 
			
		||||
  UploadExcelError
 | 
			
		||||
} from '@/shared/model-park';
 | 
			
		||||
import {
 | 
			
		||||
  ExchangeFormData,
 | 
			
		||||
  MeterChoiceData,
 | 
			
		||||
  MeterPooled,
 | 
			
		||||
  MeterReading,
 | 
			
		||||
  MeterType,
 | 
			
		||||
  ParkBuilding,
 | 
			
		||||
  TenementInfo
 | 
			
		||||
} from '@/shared/model-park';
 | 
			
		||||
import { ajaxEngine } from '@q/axios_instance';
 | 
			
		||||
import { downloadFile } from '@q/common';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
import { Dayjs } from 'dayjs';
 | 
			
		||||
import qs from 'qs';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求园区列表
 | 
			
		||||
 * @param keyword 查询园区名称的关键字
 | 
			
		||||
 * @returns 园区列表
 | 
			
		||||
 */
 | 
			
		||||
export async function parkList(keyword: string): Promise<BaseResponse & { parks: ParkInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/park`, {
 | 
			
		||||
    params: { keyword }
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 请求指定用户的园区列表
 | 
			
		||||
 * @param uid 用户id
 | 
			
		||||
 * @returns 园区列表
 | 
			
		||||
 */
 | 
			
		||||
export async function userParkList(uid: string): Promise<BaseResponse & { parks: ParkInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/park/belongs/${uid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 更改园区启用状态
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param enabled 是否启用
 | 
			
		||||
 */
 | 
			
		||||
export async function changeParkStatus(pid: string, enabled: boolean): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/park/${pid}/enabled`, { enabled });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除园区
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 */
 | 
			
		||||
export async function deletePark(pid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/park/${pid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取指定园区的信息
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 */
 | 
			
		||||
export async function parkDetail(pid: string): Promise<BaseResponse & { park: ParkInfo }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/park/${pid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取指定用户下的所有园区
 | 
			
		||||
 * @param uid 用户Id
 | 
			
		||||
 */
 | 
			
		||||
export async function enterpriseParkList(uid: string): Promise<BaseResponse & { parks: ParkInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/park/belongs/${uid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ChangeParkInfoParams {
 | 
			
		||||
  address?: string;
 | 
			
		||||
  area?: string;
 | 
			
		||||
  capacity?: string;
 | 
			
		||||
  category: ElectrCategory;
 | 
			
		||||
  contact?: string;
 | 
			
		||||
  name: string;
 | 
			
		||||
  phone?: string;
 | 
			
		||||
  region?: string;
 | 
			
		||||
  submeter: Meter04KvType;
 | 
			
		||||
  tenement?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 创建园区
 | 
			
		||||
 * @param data 创建的园区信息
 | 
			
		||||
 */
 | 
			
		||||
export async function createPark(data: Required<ChangeParkInfoParams>): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/park`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改园区信息
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param data 修改的园区信息
 | 
			
		||||
 */
 | 
			
		||||
export async function changeParkInfo(pid: string, data: ChangeParkInfoParams): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/park/${pid}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求指定园区下的所有0.4kv表计
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param keyword 查询园区名称的关键字
 | 
			
		||||
 * @param meterType 类型
 | 
			
		||||
 * @returns 园区列表
 | 
			
		||||
 */
 | 
			
		||||
export async function meter04List(
 | 
			
		||||
  pid: string,
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword: string,
 | 
			
		||||
  meterType?: MeterType
 | 
			
		||||
): Promise<BaseResponse & Pageable & { meters: Meter04KvInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/meter/${pid}`, { params: { page, keyword, type: meterType } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 下载0.4KV表计档案模板
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 */
 | 
			
		||||
export function template04Download(pid: string) {
 | 
			
		||||
  return downloadFile(`/meter/${pid}/template`);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 创建0.4Kv表计
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param data 创建的0.4Kv表计信息
 | 
			
		||||
 */
 | 
			
		||||
export async function create04KvMeter(pid: string, data: Meter04KvInfo): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/meter/${pid}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改0.4Kv表计信息
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param data 修改0.4Kv表计信息
 | 
			
		||||
 */
 | 
			
		||||
export async function change04KvMeterInfo(pid: string, data: Meter04KvInfo): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/meter/${pid}/${data.code}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 换表
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param code 原表号
 | 
			
		||||
 * @param data 新表计信息
 | 
			
		||||
 */
 | 
			
		||||
export async function exchangeMeter(pid: string, code: string, data: ExchangeFormData): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().patch(`/meter/${pid}/${code}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取指定0.4kv表计的详细信息
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param code 表号
 | 
			
		||||
 */
 | 
			
		||||
export async function getMeterInfo(pid: string, code: string): Promise<BaseResponse & { meter?: Meter04KvInfo }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/meter/${pid}/${code}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 上传Excel文件
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param file 文件对象
 | 
			
		||||
 * @param onProgress 进度监听
 | 
			
		||||
 */
 | 
			
		||||
export async function upload04MeterFile(
 | 
			
		||||
  pid: string,
 | 
			
		||||
  file: File,
 | 
			
		||||
  onProgress?: (percent: number) => void
 | 
			
		||||
): Promise<BaseResponse & { errors: UploadExcelError[] | null }> {
 | 
			
		||||
  const response = await ajaxEngine().postForm(
 | 
			
		||||
    `/meter/${pid}/batch`,
 | 
			
		||||
    { data: file },
 | 
			
		||||
    { onUploadProgress: (e: ProgressEvent) => onProgress?.(e.loaded / e.total) }
 | 
			
		||||
  );
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求指定园区下的配电维护费
 | 
			
		||||
 * @param page 请求的页码
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param period 请求检索的月份
 | 
			
		||||
 * @returns 维护费列表
 | 
			
		||||
 */
 | 
			
		||||
export async function maintenanceList(
 | 
			
		||||
  page: number,
 | 
			
		||||
  pid?: string,
 | 
			
		||||
  period?: string
 | 
			
		||||
): Promise<BaseResponse & Pageable & { fees: MaintenanceInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/maintenance/fee`, {
 | 
			
		||||
    params: { page, park: pid, period }
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除配电维护费项
 | 
			
		||||
 * @param mid 记录id
 | 
			
		||||
 */
 | 
			
		||||
export async function deleteMaintenance(mid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/maintenance/fee/${mid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改配电维护费的启用状态
 | 
			
		||||
 * @param mid 记录id
 | 
			
		||||
 * @param enabled 是否启用
 | 
			
		||||
 */
 | 
			
		||||
export async function changeMaintenance(mid: string, enabled: boolean): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/maintenance/fee/${mid}/enabled`, { enabled });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MaintenanceFormData {
 | 
			
		||||
  fee: string;
 | 
			
		||||
  memo: string;
 | 
			
		||||
  name: string;
 | 
			
		||||
  period: Dayjs;
 | 
			
		||||
  parkId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 创建配电维护费
 | 
			
		||||
 * @param data 创建的配电维护费信息
 | 
			
		||||
 */
 | 
			
		||||
export async function createMaintenance(data: MaintenanceFormData): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/maintenance/fee`, {
 | 
			
		||||
    ...data,
 | 
			
		||||
    period: data.period.format('YYYY')
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改配电维护费信息
 | 
			
		||||
 * @param mid 记录id
 | 
			
		||||
 * @param data 修改配电维护费信息
 | 
			
		||||
 */
 | 
			
		||||
export async function changeMaintenanceInfo(
 | 
			
		||||
  mid: string,
 | 
			
		||||
  data: { fee: string; memo: string; name: string }
 | 
			
		||||
): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/maintenance/fee/${mid}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 从服务端获取物业附加费的统计
 | 
			
		||||
 * @param page 请求页码
 | 
			
		||||
 * @param uid 附加费所属的企业用户ID
 | 
			
		||||
 * @param pid 附加费所属的园区ID
 | 
			
		||||
 * @param period 附加费所属的年份
 | 
			
		||||
 * @param keyword 用于对用户信息和园区信息进行检索的关键字
 | 
			
		||||
 * @returns 从服务端获取到的物业附加费的统计。
 | 
			
		||||
 */
 | 
			
		||||
export async function retrieveAdditionalChargeStatistics(
 | 
			
		||||
  page: number,
 | 
			
		||||
  uid?: string,
 | 
			
		||||
  pid?: string,
 | 
			
		||||
  period?: string,
 | 
			
		||||
  keyword?: string
 | 
			
		||||
): Promise<BaseResponse & Pageable & { charges?: MaintenanceSummary[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get('/additional/charges', {
 | 
			
		||||
    params: {
 | 
			
		||||
      page,
 | 
			
		||||
      user: uid ?? '',
 | 
			
		||||
      park: pid ?? '',
 | 
			
		||||
      period: period ?? '',
 | 
			
		||||
      keyword: keyword ?? ''
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 园区的建筑物列表
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param keyword
 | 
			
		||||
 */
 | 
			
		||||
export async function getParkBuildings(pid: string, keyword?: string): Promise<BaseResponse & { buildings?: ParkBuilding[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/park/${pid}/building`, { params: { keyword } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 启用、禁用园区建筑物
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param bid 建筑物id
 | 
			
		||||
 * @param enabled
 | 
			
		||||
 */
 | 
			
		||||
export async function changeBuildingStatus(pid: string, bid: string, enabled: boolean): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/park/${pid}/building/${bid}/enabled`, { enabled });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改园区建筑信息
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param bid 建筑物id
 | 
			
		||||
 * @param info
 | 
			
		||||
 */
 | 
			
		||||
export async function changeBuildingInfo(
 | 
			
		||||
  pid: string,
 | 
			
		||||
  bid: string,
 | 
			
		||||
  info: { name: string; floors: string }
 | 
			
		||||
): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/park/${pid}/building/${bid}`, info);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改园区建筑信息
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param info
 | 
			
		||||
 */
 | 
			
		||||
export async function createBuilding(pid: string, info: { name: string; floors: string }): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/park/${pid}/building`, info);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除园区建筑物
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param bid 建筑物id
 | 
			
		||||
 */
 | 
			
		||||
export async function deleteBuilding(pid: string, bid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/park/${pid}/building/${bid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 列出指定园区中的所有公摊表计
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param keyword 检索公摊表计的关键词
 | 
			
		||||
 * @returns 表计列表
 | 
			
		||||
 */
 | 
			
		||||
export async function meterPooledList(
 | 
			
		||||
  pid: string,
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword: string
 | 
			
		||||
): Promise<BaseResponse & Pageable & { meters: MeterPooled[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/meter/${pid}/pooled`, { params: { page, keyword } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取用于下拉列表的表计列表
 | 
			
		||||
 * @param park
 | 
			
		||||
 * @param keyword 检索公摊表计的关键词
 | 
			
		||||
 * @param limit
 | 
			
		||||
 * @returns 表计列表
 | 
			
		||||
 */
 | 
			
		||||
export async function pooledChoiceList(
 | 
			
		||||
  park: string,
 | 
			
		||||
  keyword: string,
 | 
			
		||||
  limit?: number
 | 
			
		||||
): Promise<BaseResponse & { meters: MeterChoiceData[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get('/meter/choice', { params: { park, keyword, limit: limit || 6 } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除关联表计
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param mcode 要解除关联的父级表计编号
 | 
			
		||||
 * @param scode 要解除关联的子级表计编号
 | 
			
		||||
 */
 | 
			
		||||
export async function unBindMeter(pid: string, mcode: string, scode: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/meter/${pid}/${mcode}/binding/${scode}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 向分摊表计中绑定一个新的表计
 | 
			
		||||
 * @param pid 要绑定的表计所在园区id
 | 
			
		||||
 * @param code 要绑定的父级表计编号
 | 
			
		||||
 * @param meters 绑定的表计编号列表
 | 
			
		||||
 */
 | 
			
		||||
export async function bindMeters(pid: string, code: string, meters: string[]): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/meter/${pid}/${code}/binding`, meters);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 列出园区中的商户
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param keyword 关键词
 | 
			
		||||
 * @param state 状态:0入住1迁出
 | 
			
		||||
 * @param building 选择的建筑
 | 
			
		||||
 * @param startDate
 | 
			
		||||
 * @param endDate 截止时间
 | 
			
		||||
 * @param code
 | 
			
		||||
 */
 | 
			
		||||
export async function tenementList(
 | 
			
		||||
  pid: string,
 | 
			
		||||
  page: number,
 | 
			
		||||
  state: 0 | 1,
 | 
			
		||||
  keyword?: string,
 | 
			
		||||
  building?: string,
 | 
			
		||||
  startDate?: string,
 | 
			
		||||
  endDate?: string,
 | 
			
		||||
  code?: string,
 | 
			
		||||
): Promise<BaseResponse & Pageable & { tenements: TenementInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/tenement/${pid}`, {
 | 
			
		||||
    params: { page, keyword, building, startDate, endDate, state, code }
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 列出指定商户下的所有表计
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param tid 商户id
 | 
			
		||||
 * @param code
 | 
			
		||||
 */
 | 
			
		||||
// 2023-10-26 17:15,后端需要一个code参数,在商户查询绑定表计的时候传一个非空字符串,其他情况传空字符串
 | 
			
		||||
export async function tenementMeters(
 | 
			
		||||
  pid: string,
 | 
			
		||||
  tid: string,
 | 
			
		||||
  code?: string
 | 
			
		||||
): Promise<BaseResponse & Pageable & { meters: Meter04KvInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/tenement/${pid}/${tid}/meter`,{ params: { code } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 解除商户与指定表计的关联
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param tid 商户Id
 | 
			
		||||
 * @param code 表计编号
 | 
			
		||||
 * @param data 解绑数据
 | 
			
		||||
 */
 | 
			
		||||
export async function unbindTenementMeter(
 | 
			
		||||
  pid: string,
 | 
			
		||||
  tid: string,
 | 
			
		||||
  code: string,
 | 
			
		||||
  data: MeterReading
 | 
			
		||||
): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/tenement/${pid}/${tid}/binding/${code}/unbind`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 迁出时每个表计数据
 | 
			
		||||
 */
 | 
			
		||||
export interface MoveOutFormData extends MeterReading {
 | 
			
		||||
  code: string;
 | 
			
		||||
  readAt: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 迁出指定商户
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param tid 商户Id
 | 
			
		||||
 * @param data 迁出数据
 | 
			
		||||
 */
 | 
			
		||||
export async function moveOutTenement(pid: string, tid: string, data: MoveOutFormData[]): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/tenement/${pid}/${tid}/move/out`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取用于商户绑定下拉列表的表计列表
 | 
			
		||||
 * @param park 园区Id
 | 
			
		||||
 * @param keyword
 | 
			
		||||
 */
 | 
			
		||||
export async function unBindTenementMeters(park: string, keyword: string): Promise<BaseResponse & { meters: MeterChoiceData[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/meter/choice/tenement`, { params: { keyword, park } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 给商户绑定一个表计
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param tid 商户Id
 | 
			
		||||
 * @param data 绑定数据
 | 
			
		||||
 */
 | 
			
		||||
export async function bindTenementMeter(pid: string, tid: string, data: MoveOutFormData): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/tenement/${pid}/${tid}/binding`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface CreateTenement {
 | 
			
		||||
  /** 开户账号,发票用 */
 | 
			
		||||
  account: string;
 | 
			
		||||
  /** 联系地址 */
 | 
			
		||||
  address: string;
 | 
			
		||||
  /** 开户行名称,发票用 */
 | 
			
		||||
  bank: string;
 | 
			
		||||
  /** 所在建筑ID */
 | 
			
		||||
  building: string;
 | 
			
		||||
  /** 联系人 */
 | 
			
		||||
  contact: string;
 | 
			
		||||
  /** 注册地址,发票用 */
 | 
			
		||||
  invoiceAddress: string;
 | 
			
		||||
  /** 注册电话,发票用 */
 | 
			
		||||
  invoicePhone: string;
 | 
			
		||||
  /** 商户的名称 */
 | 
			
		||||
  name: string;
 | 
			
		||||
  /** 所在建筑层数 */
 | 
			
		||||
  onFloor: string;
 | 
			
		||||
  /** 联系电话 */
 | 
			
		||||
  phone: string;
 | 
			
		||||
  /** 商户简称 */
 | 
			
		||||
  shortName: string;
 | 
			
		||||
  /** 社会统一信用代码,发票用 */
 | 
			
		||||
  usci: string;
 | 
			
		||||
  /** 入住日期 */
 | 
			
		||||
  moveIn: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 增加一个商户
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param data 绑定数据
 | 
			
		||||
 */
 | 
			
		||||
export async function createTenement(pid: string, data: CreateTenement): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/tenement/${pid}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改商户信息
 | 
			
		||||
 * @param pid 园区Id
 | 
			
		||||
 * @param tid 商户Id
 | 
			
		||||
 * @param data 修改数据
 | 
			
		||||
 */
 | 
			
		||||
export async function updateTenement(pid: string, tid: string, data: CreateTenement): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/tenement/${pid}/${tid}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface TenementInvoiceInfo {
 | 
			
		||||
  /** 开户账号 */
 | 
			
		||||
  account: string;
 | 
			
		||||
  /** 注册地址 */
 | 
			
		||||
  address: string;
 | 
			
		||||
  /** 开户行名称 */
 | 
			
		||||
  bank: string;
 | 
			
		||||
  /** 开票人 */
 | 
			
		||||
  name: string;
 | 
			
		||||
  /** 注册电话 */
 | 
			
		||||
  phone: string;
 | 
			
		||||
  /** 开票人社会统一信用代码 */
 | 
			
		||||
  usci: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取指定商户的详细信息
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param tid 商户id
 | 
			
		||||
 */
 | 
			
		||||
export async function tenementDetail(
 | 
			
		||||
  pid: string,
 | 
			
		||||
  tid: string
 | 
			
		||||
): Promise<BaseResponse & { tenement: TenementInfo & { invoiceInfo?: TenementInvoiceInfo } }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/tenement/${pid}/${tid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 导出表计
 | 
			
		||||
 */
 | 
			
		||||
export async function downloadMeterRecords(query) {
 | 
			
		||||
  return downloadFile(`/meter/export?${qs.stringify(query)}`);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 导出商户
 | 
			
		||||
 */
 | 
			
		||||
export async function downloadTenementRecords(query) {
 | 
			
		||||
  return downloadFile(`/tenement/export?${qs.stringify(query)}`);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 导出商户表计关系
 | 
			
		||||
 */
 | 
			
		||||
export async function downloadTenementMeterRecords(query) {
 | 
			
		||||
  return downloadFile(`/tenementMeter/export?${qs.stringify(query)}`);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 创建电表箱
 | 
			
		||||
 */
 | 
			
		||||
export async function createMeterBox(data: MeterBox): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/box`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 修改电表箱
 | 
			
		||||
 */
 | 
			
		||||
export async function updateMeterBox(data: MeterBox): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/box/batch`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除电表箱
 | 
			
		||||
 */
 | 
			
		||||
export async function deleteMeterBox(id:string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/box/${id}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 查询电表箱
 | 
			
		||||
 */
 | 
			
		||||
export async function getMeterBoxList(pid:string, page: number, keyword: string, building: string): Promise<BaseResponse & { data: MeterBox[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/box/${pid}`,{ params: {page, keyword, building} });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								src/queries/permission.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/queries/permission.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
import { BaseResponse } from "@/shared/model-components";
 | 
			
		||||
import { ajaxEngine } from "./axios_instance";
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 查询角色所拥有权限
 | 
			
		||||
 * @param role 角色
 | 
			
		||||
 */
 | 
			
		||||
export async function getRolePermission(
 | 
			
		||||
    role: string
 | 
			
		||||
): Promise<BaseResponse & { data: string[], forbid_list: string[] }> {
 | 
			
		||||
    const response = await ajaxEngine().get(`/permission/${role}`);
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-unsafe-call
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改角色所拥有权限
 | 
			
		||||
 * @param role 角色
 | 
			
		||||
 * @param data 权限列表
 | 
			
		||||
 */
 | 
			
		||||
export async function updateRolePermission(
 | 
			
		||||
    role: string,
 | 
			
		||||
    data: string[],
 | 
			
		||||
): Promise<BaseResponse> {
 | 
			
		||||
    const response = await ajaxEngine().put(`/permission`, {
 | 
			
		||||
        role,data
 | 
			
		||||
    });
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-unsafe-call
 | 
			
		||||
    return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										188
									
								
								src/queries/publicity.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								src/queries/publicity.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,188 @@
 | 
			
		||||
import { Consumption } from '@/shared/model-calculate';
 | 
			
		||||
import type { BaseResponse, Pageable } from '@/shared/model-components';
 | 
			
		||||
import type { BasePublicityInfo, PublicityEndUserPeriodStatistics, ReportTenement, errorMessageItem } from '@/shared/model-publicity';
 | 
			
		||||
import { ParkSummary, PublicPooled, ReportTenementDetail } from '@/shared/model-publicity';
 | 
			
		||||
import { ajaxEngine } from '@q/axios_instance';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
import {downloadFile} from "@q/common";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求审核列表
 | 
			
		||||
 * @param page
 | 
			
		||||
 * @param keyword 查询的关键字
 | 
			
		||||
 * @returns 审核列表
 | 
			
		||||
 */
 | 
			
		||||
export async function auditList(
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword: string
 | 
			
		||||
): Promise<BaseResponse & Pageable & { records: BasePublicityInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/withdraw`, { params: { keyword } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通过/不通过审核
 | 
			
		||||
 * @param rid 审核记录Id
 | 
			
		||||
 * @param audit 审核操作
 | 
			
		||||
 */
 | 
			
		||||
export async function auditReport(rid: string, audit: boolean): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/withdraw/${rid}`, { audit });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取指定报表的全部内容
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 */
 | 
			
		||||
export async function reportDetail(
 | 
			
		||||
  rid: string
 | 
			
		||||
): Promise<BaseResponse & { detail: Omit<BasePublicityInfo, 'user'> & { enterprise: BasePublicityInfo['user'] } }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/report/${rid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取指定报表的园区概况
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 */
 | 
			
		||||
export async function reportParkDetail(rid: string): Promise<BaseResponse & { summary: ParkSummary }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/report/${rid}/summary`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取公共表计电费情况
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 * @param page
 | 
			
		||||
 * @param keyword
 | 
			
		||||
 */
 | 
			
		||||
export async function reportPublicFee(
 | 
			
		||||
  rid: string,
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword?: string
 | 
			
		||||
): Promise<BaseResponse & Pageable & { public: (PublicPooled & { adjustLoss: Consumption })[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/report/${rid}/publics`, { params: { page, keyword } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取公摊表计电费情况
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 * @param page
 | 
			
		||||
 * @param keyword
 | 
			
		||||
 */
 | 
			
		||||
export async function reportPublicPooled(
 | 
			
		||||
  rid: string,
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword?: string
 | 
			
		||||
): Promise<BaseResponse & Pageable & { pooled: PublicPooled[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/report/${rid}/pooled`, { params: { page, keyword } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取指定公摊表计下的摊薄表计详细
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 * @param code 表号
 | 
			
		||||
 */
 | 
			
		||||
export async function reportPooledSubmeter(
 | 
			
		||||
  rid: string,
 | 
			
		||||
  code: string
 | 
			
		||||
): Promise<BaseResponse & { meters: PublicPooled[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/report/${rid}/pooled/${code}/submeter`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取指定商户的核算详细
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 * @param tid 商户Id
 | 
			
		||||
 */
 | 
			
		||||
export async function reportTenementDetail(
 | 
			
		||||
  rid: string,
 | 
			
		||||
  tid: string
 | 
			
		||||
): Promise<BaseResponse & { detail: ReportTenementDetail, amount: string }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/report/${rid}/tenement/${tid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取商户电量电费列表
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 * @param page 页数
 | 
			
		||||
 * @param keyword 关键字
 | 
			
		||||
 */
 | 
			
		||||
export async function reportTenement(
 | 
			
		||||
  rid: string,
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword?: string
 | 
			
		||||
): Promise<BaseResponse & Pageable & { tenements: ReportTenement[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/report/${rid}/tenement`, { params: { page, keyword } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 综合列举报表接口
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param keyword 关键字
 | 
			
		||||
 * @param period 期数
 | 
			
		||||
 * @param park 园区
 | 
			
		||||
 * @param user 管理单位
 | 
			
		||||
 */
 | 
			
		||||
export async function reportList(
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword: string,
 | 
			
		||||
  user: string,
 | 
			
		||||
  park: string,
 | 
			
		||||
  period: string
 | 
			
		||||
): Promise<BaseResponse & Pageable & { reports: BasePublicityInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/reports`, {
 | 
			
		||||
    params: { page, keyword, user, park, periodStart: period, periodEnd: period, all: 1 }
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 从服务端查询一段时间之内的终端用户调整费用统计。
 | 
			
		||||
 * @param uid 指定要查询的企业用户ID
 | 
			
		||||
 * @param pid 指定要查询的园区ID
 | 
			
		||||
 * @param start 统计开始日期,格式:YYYY-MM,指定日期包含
 | 
			
		||||
 * @param end 统计结束的日期,格式:YYYY-MM,指定日期包含
 | 
			
		||||
 */
 | 
			
		||||
export async function retrieveEndUserStat(
 | 
			
		||||
  uid?: string,
 | 
			
		||||
  pid?: string,
 | 
			
		||||
  start?: string,
 | 
			
		||||
  end?: string
 | 
			
		||||
): Promise<BaseResponse & { details?: PublicityEndUserPeriodStatistics[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/end/user/adjusts`, {
 | 
			
		||||
    params: {
 | 
			
		||||
      user: uid ?? '',
 | 
			
		||||
      park: pid ?? '',
 | 
			
		||||
      start: start ?? '',
 | 
			
		||||
      end: end ?? ''
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取报表核算的错误列表(如果没有返回的是空列表)
 | 
			
		||||
 * @param rid 报表id
 | 
			
		||||
 * */
 | 
			
		||||
export async function getErrorList(
 | 
			
		||||
  rid: string,
 | 
			
		||||
): Promise<BaseResponse & {errType: number} & { message: errorMessageItem[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/report/error/list?rid=${rid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 导出计算信息
 | 
			
		||||
 * @param rid 报表Id
 | 
			
		||||
 * @param pid
 | 
			
		||||
 */
 | 
			
		||||
export async function downloadReport(rid: string, pid: string) {
 | 
			
		||||
  return downloadFile(`/report/export/user/${rid}/${pid}`);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								src/queries/query_client.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/queries/query_client.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
import { QueryClient } from '@tanstack/react-query';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * React Query的查询客户端。
 | 
			
		||||
 */
 | 
			
		||||
export const queryClient = new QueryClient({
 | 
			
		||||
  defaultOptions: {
 | 
			
		||||
    queries: {
 | 
			
		||||
      refetchOnWindowFocus: true,
 | 
			
		||||
      refetchOnReconnect: true
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										146
									
								
								src/queries/reading.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								src/queries/reading.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,146 @@
 | 
			
		||||
import type { BaseResponse, Pageable } from '@/shared/model-components';
 | 
			
		||||
import { ajaxEngine } from '@q/axios_instance';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
import {ReadingInfo, Refund, RefundForm} from '@/shared/model-reading';
 | 
			
		||||
import { MeterChoiceData, MeterType, UploadExcelError } from '@/shared/model-park';
 | 
			
		||||
import { downloadFile } from '@q/common';
 | 
			
		||||
import qs from "qs";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 查询符合指定条件的抄表记录
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param keyword 关键词
 | 
			
		||||
 * @param building 选择的建筑
 | 
			
		||||
 * @param startDate 开始时间
 | 
			
		||||
 * @param endDate 截止时间
 | 
			
		||||
 * @param type
 | 
			
		||||
 */
 | 
			
		||||
export async function readingList(
 | 
			
		||||
  pid: string,
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword?: string,
 | 
			
		||||
  building?: string,
 | 
			
		||||
  startDate?: string,
 | 
			
		||||
  endDate?: string,
 | 
			
		||||
  type: MeterType = undefined
 | 
			
		||||
): Promise<BaseResponse & Pageable & { records: ReadingInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/reading/${pid}`, {
 | 
			
		||||
    params: { page, keyword, building, startDate, endDate, type }
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取用于增加抄表记录时下拉列表的表计列表
 | 
			
		||||
 * @returns 表计列表
 | 
			
		||||
 * @param park
 | 
			
		||||
 * @param keyword
 | 
			
		||||
 */
 | 
			
		||||
export async function meterChoiceList(
 | 
			
		||||
  park: string,
 | 
			
		||||
  keyword: string
 | 
			
		||||
): Promise<BaseResponse & { meters: MeterChoiceData[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/reading/${park}/choice`, { params: { keyword, limit: 10 } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type CreateReadingData = ReadingInfo & { code: string; readAt: string };
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 新建一条抄表记录
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param data
 | 
			
		||||
 */
 | 
			
		||||
export async function createReading(pid: string, data: CreateReadingData) {
 | 
			
		||||
  const response = await ajaxEngine().post(`/reading/${pid}/${data.code}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 新建一条抄表记录
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param readAtTimestamp 抄表记录的时间戳
 | 
			
		||||
 * @param data
 | 
			
		||||
 */
 | 
			
		||||
export async function updateReading(pid: string, readAtTimestamp: string, data: CreateReadingData) {
 | 
			
		||||
  const response = await ajaxEngine().put(`/reading/${pid}/${data.code}/${readAtTimestamp}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 下载抄表记录批量填写模板
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 */
 | 
			
		||||
export function downloadReadingTemplate(pid: string) {
 | 
			
		||||
  downloadFile(`/reading/${pid}/template`);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 上传批量抄表记录档案
 | 
			
		||||
 * @param pid 园区id
 | 
			
		||||
 * @param file 文件对象
 | 
			
		||||
 * @param onProgress 进度监听
 | 
			
		||||
 */
 | 
			
		||||
export async function uploadReadingTemplateFile(
 | 
			
		||||
  pid: string,
 | 
			
		||||
  file: File,
 | 
			
		||||
  onProgress?: (percent: number) => void
 | 
			
		||||
): Promise<BaseResponse & { errors: UploadExcelError[] | null }> {
 | 
			
		||||
  const response = await ajaxEngine().postForm(
 | 
			
		||||
    `/reading/${pid}/batch`,
 | 
			
		||||
    { data: file },
 | 
			
		||||
    { onUploadProgress: (e: ProgressEvent) => onProgress?.(e.loaded / e.total) }
 | 
			
		||||
  );
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取退补电费列表
 | 
			
		||||
 * @param park
 | 
			
		||||
 * @param page
 | 
			
		||||
 * @param startDate
 | 
			
		||||
 * @param endDate
 | 
			
		||||
 * @param keyword
 | 
			
		||||
 */
 | 
			
		||||
export async function getRefundList(page: number, park?:string,  startDate?:string, endDate?:string, keyword?: string): Promise<BaseResponse & {data: Refund[], total: number}> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/read/${park}/electric?${qs.stringify({
 | 
			
		||||
    page,
 | 
			
		||||
    park,
 | 
			
		||||
    start: startDate,
 | 
			
		||||
    end: endDate,
 | 
			
		||||
    keyword
 | 
			
		||||
  })}`, );
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 获取退补电费列表
 | 
			
		||||
 * @param park
 | 
			
		||||
 * @param data
 | 
			
		||||
 */
 | 
			
		||||
export async function createRefund(park: string, data: RefundForm): Promise<BaseResponse & {data: Refund[]}> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/read/${park}/electric`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 查询退补电量可选周期
 | 
			
		||||
 * @param park
 | 
			
		||||
 * @param year 某个年份不能选
 | 
			
		||||
 */
 | 
			
		||||
export async function getDisabledMonth(park: string, year: number): Promise<BaseResponse & {data: string[]}> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/read/${park}/period`, {
 | 
			
		||||
    params: {
 | 
			
		||||
      year
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除指定的电费退补记录
 | 
			
		||||
 * */
 | 
			
		||||
export async function deleteRefund(id: string) {
 | 
			
		||||
  const response = await ajaxEngine().delete(`/read/${id}`)
 | 
			
		||||
  return unwrap(response)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								src/queries/session.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/queries/session.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
import { BaseResponse } from '@/shared/model-components';
 | 
			
		||||
import { UserSession } from '@/shared/model-user';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
import { ajaxEngine } from './axios_instance';
 | 
			
		||||
import { privilege } from '@/shared/model-sonaccount';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用户登录请求的响应结构。
 | 
			
		||||
 */
 | 
			
		||||
export interface LoginResponse extends BaseResponse {
 | 
			
		||||
  /**
 | 
			
		||||
   * 用户是否需要重置密码。
 | 
			
		||||
   */
 | 
			
		||||
  needReset: boolean;
 | 
			
		||||
  /**
 | 
			
		||||
   * 服务端返回的用户会话信息。
 | 
			
		||||
   */
 | 
			
		||||
  session?: UserSession | null;
 | 
			
		||||
  /** 角色 */
 | 
			
		||||
  privileges?: privilege[],
 | 
			
		||||
  /** 权限列表 */
 | 
			
		||||
  roles?: []
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 执行用户在页面上发起的登录请求。
 | 
			
		||||
 * @param username 用户名。
 | 
			
		||||
 * @param password 用户的登录密码或重置用验证码。
 | 
			
		||||
 * @param type 用户所使用的登录表单类型,也算是用户类型。0:企业表单,1:监管及运维表单。
 | 
			
		||||
 * @returns 服务端返回的登录请求响应。
 | 
			
		||||
 */
 | 
			
		||||
export async function login(
 | 
			
		||||
  username: string,
 | 
			
		||||
  password: string,
 | 
			
		||||
  type: number
 | 
			
		||||
): Promise<LoginResponse> {
 | 
			
		||||
  const response = await ajaxEngine(true).post<LoginResponse>(`/login`, {
 | 
			
		||||
    uname: username,
 | 
			
		||||
    upass: password,
 | 
			
		||||
    type
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 执行用户或系统发起的登出请求。
 | 
			
		||||
 * @returns 服务端返回的登出请求处理结果。
 | 
			
		||||
 */
 | 
			
		||||
export async function logout(): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().delete<BaseResponse>(`/login`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										83
									
								
								src/queries/son_account.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/queries/son_account.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
import { BaseResponse, Pageable } from '@/shared/model-components';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
import { ajaxEngine } from './axios_instance';
 | 
			
		||||
import { UserType } from '@/shared/model-user';
 | 
			
		||||
import { SonAccountItem, SubmitSonAccount } from '@/shared/model-sonaccount';
 | 
			
		||||
 | 
			
		||||
export interface SonAccountResponse extends BaseResponse, Pageable {
 | 
			
		||||
  accounts: SonAccountItem[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SonAccountListQuery {
 | 
			
		||||
    keyword?: string, type?: UserType, page?: number, state?: boolean
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求系统账号列表
 | 
			
		||||
 * @returns 系统账号列表
 | 
			
		||||
 * @param params
 | 
			
		||||
 */
 | 
			
		||||
export async function getSonAccountList(
 | 
			
		||||
    params: SonAccountListQuery
 | 
			
		||||
): Promise<SonAccountResponse> {
 | 
			
		||||
  const response = await ajaxEngine().get<SonAccountResponse>(`/subaccount`, { params });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 更改用户可用性状态
 | 
			
		||||
 * @param uid 账号Id
 | 
			
		||||
 * @param enabled 是否启用
 | 
			
		||||
 */
 | 
			
		||||
export async function changeSonAccountStatus(uid: string, enabled: boolean): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/subaccount/${uid}/enabled`, {
 | 
			
		||||
    enabled
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 重置密码
 | 
			
		||||
 * @param uid 账号Id
 | 
			
		||||
 * @return 验证码
 | 
			
		||||
 */
 | 
			
		||||
export async function resetPassword(uid: string) {
 | 
			
		||||
  const response = await ajaxEngine().delete<BaseResponse & { verify: string }>(`/subaccount/${uid}/password`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ChangeUserInfoParams {
 | 
			
		||||
  username?: string;
 | 
			
		||||
  contact?: string;
 | 
			
		||||
  name?: string;
 | 
			
		||||
  phone?: string;
 | 
			
		||||
  region?: string;
 | 
			
		||||
  unitServiceFee?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改用户信息。
 | 
			
		||||
 * @param uid
 | 
			
		||||
 * @param data 修改后的用户信息
 | 
			
		||||
 */
 | 
			
		||||
export async function changeUserInfo(uid: string, data: SonAccountItem): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/subaccount/${uid}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 创建子账号。
 | 
			
		||||
 * @param data 创建的用户信息
 | 
			
		||||
 */
 | 
			
		||||
export async function createUser(data: SubmitSonAccount): Promise<BaseResponse & { verify: string }> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/subaccount`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取所有可以选择的角色
 | 
			
		||||
 */
 | 
			
		||||
export async function getPrivileges(): Promise<BaseResponse & { privileges: SonAccountItem['privileges'] }> {
 | 
			
		||||
  const response = await ajaxEngine().get<BaseResponse & { privileges: SonAccountItem['privileges'] }>(`/privileges`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										153
									
								
								src/queries/statement.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								src/queries/statement.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,153 @@
 | 
			
		||||
import type { BaseResponse, Pageable } from '@/shared/model-components';
 | 
			
		||||
import { ajaxEngine } from '@q/axios_instance';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
import qs from 'qs';
 | 
			
		||||
import {
 | 
			
		||||
  AccountingStatement,
 | 
			
		||||
  DefaultQuery,
 | 
			
		||||
  ElectricDetailStatement,
 | 
			
		||||
  ElectricStatement, InvoiceStatement,
 | 
			
		||||
  RechargeStatement, TenementStatement
 | 
			
		||||
} from '@/shared/model-statement';
 | 
			
		||||
import {downloadFile} from "@q/common";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 查询充值记录报表
 | 
			
		||||
 * @param park 园区id
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param startDate 开始时间
 | 
			
		||||
 * @param endDate 结束时间
 | 
			
		||||
 */
 | 
			
		||||
export async function rechargeStatement({
 | 
			
		||||
                                       page,
 | 
			
		||||
                                       startDate,
 | 
			
		||||
                                       endDate,
 | 
			
		||||
                                       park,
 | 
			
		||||
 | 
			
		||||
                                     }: DefaultQuery): Promise<BaseResponse & Pageable & { data: RechargeStatement[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/statement/recharge?${qs.stringify({
 | 
			
		||||
    page,
 | 
			
		||||
    startDate,
 | 
			
		||||
    endDate,
 | 
			
		||||
    park,
 | 
			
		||||
  })}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 查询用电情况报表
 | 
			
		||||
 * @param park 园区id
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param startDate 开始时间
 | 
			
		||||
 * @param endDate 结束时间
 | 
			
		||||
 */
 | 
			
		||||
export async function electricStatement({
 | 
			
		||||
                                          page,
 | 
			
		||||
                                          startDate,
 | 
			
		||||
                                          endDate,
 | 
			
		||||
                                          park,
 | 
			
		||||
 | 
			
		||||
                                        }: DefaultQuery): Promise<BaseResponse & Pageable & { data: ElectricStatement[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/statement/electric?${qs.stringify({
 | 
			
		||||
    page,
 | 
			
		||||
    startDate,
 | 
			
		||||
    endDate,
 | 
			
		||||
    park,
 | 
			
		||||
  })}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 查询用电详情报表
 | 
			
		||||
 * @param park 园区id
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param startDate 开始时间
 | 
			
		||||
 * @param endDate 结束时间
 | 
			
		||||
 */
 | 
			
		||||
export async function electricDetailStatement({
 | 
			
		||||
                                          page,
 | 
			
		||||
                                          startDate,
 | 
			
		||||
                                          endDate,
 | 
			
		||||
                                          park,
 | 
			
		||||
                                        }: DefaultQuery): Promise<BaseResponse & Pageable & { data: ElectricDetailStatement[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/statement/electricDetail?${qs.stringify({
 | 
			
		||||
    page,
 | 
			
		||||
    startDate,
 | 
			
		||||
    endDate,
 | 
			
		||||
    park,
 | 
			
		||||
  })}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 查询账务记录报表
 | 
			
		||||
 * @param park 园区id
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param startDate 开始时间
 | 
			
		||||
 * @param endDate 结束时间
 | 
			
		||||
 */
 | 
			
		||||
export async function accountingStatement({
 | 
			
		||||
                                                page,
 | 
			
		||||
                                                startDate,
 | 
			
		||||
                                                endDate,
 | 
			
		||||
                                                park,
 | 
			
		||||
                                              }: DefaultQuery): Promise<BaseResponse & Pageable & { data: AccountingStatement[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/statement/accounting?${qs.stringify({
 | 
			
		||||
    page,
 | 
			
		||||
    startDate,
 | 
			
		||||
    endDate,
 | 
			
		||||
    park,
 | 
			
		||||
  })}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 查询发票记录报表
 | 
			
		||||
 * @param park 园区id
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param startDate 开始时间
 | 
			
		||||
 * @param endDate 结束时间
 | 
			
		||||
 */
 | 
			
		||||
export async function invoiceStatement({
 | 
			
		||||
                                            page,
 | 
			
		||||
                                            startDate,
 | 
			
		||||
                                            endDate,
 | 
			
		||||
                                            park,
 | 
			
		||||
                                          }: DefaultQuery): Promise<BaseResponse & Pageable & { data: InvoiceStatement[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/statement/invoice?${qs.stringify({
 | 
			
		||||
    page,
 | 
			
		||||
    startDate,
 | 
			
		||||
    endDate,
 | 
			
		||||
    park,
 | 
			
		||||
  })}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 查询商户记录报表
 | 
			
		||||
 * @param park 园区id
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param startDate 开始时间
 | 
			
		||||
 * @param endDate 结束时间
 | 
			
		||||
 */
 | 
			
		||||
export async function tenementStatement({
 | 
			
		||||
                                         page,
 | 
			
		||||
                                         startDate,
 | 
			
		||||
                                         endDate,
 | 
			
		||||
                                         park,
 | 
			
		||||
                                       }: DefaultQuery): Promise<BaseResponse & Pageable & { data: TenementStatement[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/statement/tenement?${qs.stringify({
 | 
			
		||||
    page,
 | 
			
		||||
    startDate,
 | 
			
		||||
    endDate,
 | 
			
		||||
    park,
 | 
			
		||||
  })}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 报表导出
 | 
			
		||||
 * @param park 报表Id
 | 
			
		||||
 * @param type 类型
 | 
			
		||||
 */
 | 
			
		||||
export function downloadStatement(park: string, type: number) {
 | 
			
		||||
  downloadFile(`/statement/export?park=${park}&type=${type}`).then(() => {});
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										92
									
								
								src/queries/sync.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/queries/sync.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
			
		||||
import type { BaseResponse, Pageable } from '@/shared/model-components';
 | 
			
		||||
import { ajaxEngine } from '@q/axios_instance';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
import {ParkSync, ReadingInterval, ReadingRetryAlgorithm, ReadingType, SyncTask} from '@/shared/model-sync';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 同步列表
 | 
			
		||||
 * @param page
 | 
			
		||||
 * @param keyword 关键词
 | 
			
		||||
 */
 | 
			
		||||
export async function syncList(
 | 
			
		||||
  page: number,
 | 
			
		||||
  keyword?: string,
 | 
			
		||||
): Promise<BaseResponse & Pageable & { tasks: SyncTask[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/synchronize/task`, { params: {  keyword, page } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 暂停同步任务
 | 
			
		||||
 */
 | 
			
		||||
export async function pauseSyncTask(pid: string, tid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/synchronize/task/${pid}/${tid}/pause`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 将指定任务列入执行队列
 | 
			
		||||
 */
 | 
			
		||||
export async function startSyncTask(pid: string, tid: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/synchronize/task/${pid}/${tid}/enqueue`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SyncSettingData {
 | 
			
		||||
  /** 企业ID */
 | 
			
		||||
  entId: string;
 | 
			
		||||
  /** 采集系统型号 */
 | 
			
		||||
  imrs: string;
 | 
			
		||||
  /** 同步登录账号 */
 | 
			
		||||
  imrsAccount: string;
 | 
			
		||||
  /** 同步登录私钥,Base64或者私钥文件内容 */
 | 
			
		||||
  imrsKey: string;
 | 
			
		||||
  /** 同步登录密钥,加盐双向加密 */
 | 
			
		||||
  imrsSecret: string;
 | 
			
		||||
  /** 采集周期,0:每小时,1:每日,2:每周,3:每月 */
 | 
			
		||||
  interval: ReadingInterval;
 | 
			
		||||
  /** 最大重试次数 */
 | 
			
		||||
  maxRetries: string;
 | 
			
		||||
  /** 园区ID */
 | 
			
		||||
  parkId: string;
 | 
			
		||||
  /** 采集方式,0:自动+人工,1:自动,2:人工 */
 | 
			
		||||
  readingType: ReadingType;
 | 
			
		||||
  /** 重试间隔算法,0:指数退避,1:2倍线性间隔,2:3倍线性间隔,3:固定间隔 */
 | 
			
		||||
  retryAlgorithm: ReadingRetryAlgorithm;
 | 
			
		||||
  /** 重试间隔,基础间隔时间,根据间隔算法不同会产生不同的间隔 */
 | 
			
		||||
  retryInterval: string;
 | 
			
		||||
  /** 采集时间,格式:HH:mm */
 | 
			
		||||
  collectAt: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 更新指定用户的同步配置
 | 
			
		||||
 */
 | 
			
		||||
export async function changeSyncSetting(uid: string, data: SyncSettingData): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/synchronize/configuration`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取用户的同步配置
 | 
			
		||||
 */
 | 
			
		||||
export async function getSyncSetting(pid: string, uid: string): Promise<BaseResponse & { setup: SyncSettingData }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/synchronize/configuration`, { params: { user: uid, park: pid } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取某个园区充值记录校验
 | 
			
		||||
 */
 | 
			
		||||
export async function getSyncRechargeRecords(pid: string, pageNum: number): Promise<BaseResponse & { data: ParkSync[], total: number }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/synchronize/task/${pid}/getRechargeRecords?pageNum=${pageNum}`,);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 获取某个园区充值记录校验
 | 
			
		||||
 */
 | 
			
		||||
export async function resetSync(id: string): Promise<BaseResponse & { setup: SyncSettingData }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/synchronize/task/${id}/resetSync`,);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										213
									
								
								src/queries/user.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								src/queries/user.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,213 @@
 | 
			
		||||
import { BaseResponse, Pageable } from '@/shared/model-components';
 | 
			
		||||
import { unwrap } from '@u/asyncs';
 | 
			
		||||
import { ajaxEngine } from './axios_instance';
 | 
			
		||||
import { BaseUserInfo, UserInfo, UserType } from '@/shared/model-user';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用户请求重设密码。
 | 
			
		||||
 * @param username 要重设密码的用户账号。
 | 
			
		||||
 * @param verify 用于验证重设操作的验证码。
 | 
			
		||||
 * @param password 要设置成的新密码。
 | 
			
		||||
 * @returns 服务端进行重设密码操作以后的操作结果。
 | 
			
		||||
 */
 | 
			
		||||
export async function repassword(username: string, verify: string, password: string): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine(true).put(`/password`, {
 | 
			
		||||
    uname: username,
 | 
			
		||||
    verifyCode: verify,
 | 
			
		||||
    newPass: password
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AccountsResponse extends BaseResponse, Pageable {
 | 
			
		||||
  accounts: BaseUserInfo[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求系统账号列表
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param query
 | 
			
		||||
 * @param query.keyword 查询用户账号、用户名的关键字
 | 
			
		||||
 * @param query.type 查询用户账号、用户名的关键字
 | 
			
		||||
 * @param query.state 账号是否启用
 | 
			
		||||
 * @returns 系统账号列表
 | 
			
		||||
 */
 | 
			
		||||
export async function userAccounts(
 | 
			
		||||
  page: number,
 | 
			
		||||
  query?: { keyword?: string; type?: UserType; state?: boolean }
 | 
			
		||||
): Promise<AccountsResponse> {
 | 
			
		||||
  const response = await ajaxEngine().get<AccountsResponse>(`/account`, { params: { page, ...query } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 更改用户可用性状态
 | 
			
		||||
 * @param uid 账号Id
 | 
			
		||||
 * @param enabled 是否启用
 | 
			
		||||
 */
 | 
			
		||||
export async function changeAccountStatus(uid: string, enabled: boolean): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/account/enabled/state`, {
 | 
			
		||||
    uid,
 | 
			
		||||
    enabled
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 重置密码
 | 
			
		||||
 * @param uid 账号Id
 | 
			
		||||
 * @return 验证码
 | 
			
		||||
 */
 | 
			
		||||
export async function resetPassword(uid: string) {
 | 
			
		||||
  const response = await ajaxEngine().delete<BaseResponse & { verify: string }>(`/password/${uid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ChangeUserInfoParams {
 | 
			
		||||
  address?: string;
 | 
			
		||||
  contact?: string;
 | 
			
		||||
  name?: string;
 | 
			
		||||
  phone?: string;
 | 
			
		||||
  region?: string;
 | 
			
		||||
  unitServiceFee?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改用户信息。
 | 
			
		||||
 * @param uid
 | 
			
		||||
 * @param data 修改后的用户信息
 | 
			
		||||
 */
 | 
			
		||||
export async function changeUserInfo(uid: string, data: ChangeUserInfoParams): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/account/${uid}`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 创建非企业账号。
 | 
			
		||||
 * @param data 创建的用户信息
 | 
			
		||||
 */
 | 
			
		||||
export async function createUser(data: BaseUserInfo): Promise<BaseResponse & { verify: string }> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/account`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 创建企业账号。
 | 
			
		||||
 * @param data 创建的企业信息
 | 
			
		||||
 */
 | 
			
		||||
export async function createEnterprise(
 | 
			
		||||
  data: Required<ChangeUserInfoParams> & { username: string }
 | 
			
		||||
): Promise<BaseResponse & { verify: string }> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/enterprise`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取用户的完整信息。
 | 
			
		||||
 * @param uid 用户Id
 | 
			
		||||
 */
 | 
			
		||||
export async function userDetail(uid: string): Promise<BaseResponse & { user: UserInfo }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/account/${uid}`);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ChargeListResponse extends BaseResponse, Pageable {
 | 
			
		||||
  records: ChargeRecord[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 计费记录
 | 
			
		||||
 */
 | 
			
		||||
export interface ChargeRecord {
 | 
			
		||||
  /** 记录索引号,可用来排序 */
 | 
			
		||||
  seq: number;
 | 
			
		||||
  /** 最终合计费用 */
 | 
			
		||||
  amount: null | number;
 | 
			
		||||
  /** 计费时间,不是收到费用的时间,是费用可以维持服务到达的时间。格式 yyyy-MM-ddTHH:mm:ss.SSSSSSZ */
 | 
			
		||||
  chargeTo: string;
 | 
			
		||||
  /** 条目创建时间 */
 | 
			
		||||
  createdAt: string;
 | 
			
		||||
  /** 折扣,即减掉的百分比 */
 | 
			
		||||
  discount: number;
 | 
			
		||||
  /** 基本费用 */
 | 
			
		||||
  fee: number;
 | 
			
		||||
  /** 是否起效 */
 | 
			
		||||
  settled: boolean;
 | 
			
		||||
  /** 起效时间 */
 | 
			
		||||
  settledAt: null | string;
 | 
			
		||||
  /** 是否已取消 */
 | 
			
		||||
  cancelled: boolean;
 | 
			
		||||
  /** 取消时间 */
 | 
			
		||||
  cancelledAt: null | string;
 | 
			
		||||
  /** 所属用户ID */
 | 
			
		||||
  userId: string;
 | 
			
		||||
  /** 所属用户名称 */
 | 
			
		||||
  name: string;
 | 
			
		||||
  /** 所属用户账号 */
 | 
			
		||||
  username: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 请求计费记录
 | 
			
		||||
 * @param page 页码
 | 
			
		||||
 * @param query
 | 
			
		||||
 * @param query.keyword 查询用户账号、用户名的关键字
 | 
			
		||||
 * @param query.begin 起始时间
 | 
			
		||||
 * @param query.end 截止时间
 | 
			
		||||
 * @returns 计费记录列表
 | 
			
		||||
 */
 | 
			
		||||
export async function chargeList(
 | 
			
		||||
  page: number,
 | 
			
		||||
  query?: { keyword?: string; begin: string; end: string }
 | 
			
		||||
): Promise<ChargeListResponse> {
 | 
			
		||||
  const response = await ajaxEngine().get<ChargeListResponse>(`/charge`, { params: { page, ...query } });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 撤销计费记录
 | 
			
		||||
 * @param uid 账号Id
 | 
			
		||||
 * @param seq 记录索引
 | 
			
		||||
 */
 | 
			
		||||
export async function cancelRecord(uid: string, seq: number): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().put(`/charge/${uid}/${seq}`, { cancelled: true });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ChargeListResponse extends BaseResponse, Pageable {
 | 
			
		||||
  records: ChargeRecord[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 搜索企业
 | 
			
		||||
 * @param keyword	关键词
 | 
			
		||||
 * @returns 企业列表
 | 
			
		||||
 */
 | 
			
		||||
export async function searchEnterprise(keyword: string): Promise<BaseResponse & { users: UserInfo[] }> {
 | 
			
		||||
  const response = await ajaxEngine().get(`/enterprise/quick/search`, {
 | 
			
		||||
    params: { keyword }
 | 
			
		||||
  });
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface CreateRecord {
 | 
			
		||||
  // 关联的企业用户Id
 | 
			
		||||
  userId: string;
 | 
			
		||||
  // 计费日期至
 | 
			
		||||
  chargeTo: string;
 | 
			
		||||
  // 应计金额
 | 
			
		||||
  fee: null | string;
 | 
			
		||||
  // 应收金额
 | 
			
		||||
  amount: null | string;
 | 
			
		||||
  // 折扣
 | 
			
		||||
  discount: null | string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 创建计费记录
 | 
			
		||||
 * @param data 计费信息
 | 
			
		||||
 */
 | 
			
		||||
export async function createRecord(data: CreateRecord): Promise<BaseResponse> {
 | 
			
		||||
  const response = await ajaxEngine().post(`/charge`, data);
 | 
			
		||||
  return unwrap(response);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										668
									
								
								src/shared/equipment.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										668
									
								
								src/shared/equipment.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,668 @@
 | 
			
		||||
// noinspection JSNonASCIINames
 | 
			
		||||
 | 
			
		||||
import { Key } from "react";
 | 
			
		||||
 | 
			
		||||
export enum Operator {
 | 
			
		||||
    "移动",
 | 
			
		||||
    "联通",
 | 
			
		||||
    "电信",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum MeterStatus {
 | 
			
		||||
    "在库",
 | 
			
		||||
    "运行",
 | 
			
		||||
    "待校",
 | 
			
		||||
    "故障",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum MeterLevel {
 | 
			
		||||
    "总表",
 | 
			
		||||
    "主表",
 | 
			
		||||
    "从表",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum CommunicationProtocol {
 | 
			
		||||
    "TcpServer模式",
 | 
			
		||||
    "TcpClient模式",
 | 
			
		||||
    "NB网关模式",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum Collector {
 | 
			
		||||
    "低压采集器",
 | 
			
		||||
    "采集终端",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum MessageWay {
 | 
			
		||||
    "载波",
 | 
			
		||||
    "无线",
 | 
			
		||||
    "4G",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum Bps {
 | 
			
		||||
    "1200bps",
 | 
			
		||||
    "2400bps",
 | 
			
		||||
    "4800bps",
 | 
			
		||||
    "9600bps",
 | 
			
		||||
    "19200bps",
 | 
			
		||||
    "38400bps",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum SN {
 | 
			
		||||
    "TcpClient模式",
 | 
			
		||||
    "NB网关模式",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通讯协议
 | 
			
		||||
 * */
 | 
			
		||||
export interface ProtocolItem {
 | 
			
		||||
    /**
 | 
			
		||||
     * 波特率,0- 1200bps , 1- 2400bps 2- 4800bps, 3- 9600bps, 4- 19200bps , 5- 38400bps
 | 
			
		||||
     */
 | 
			
		||||
    bps: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * IP地址
 | 
			
		||||
     */
 | 
			
		||||
    harvester_ip: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 采集器类型,0:低压采集器 - 1:采集终端
 | 
			
		||||
     */
 | 
			
		||||
    harvester_type: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * imei
 | 
			
		||||
     */
 | 
			
		||||
    imei: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 端口
 | 
			
		||||
     */
 | 
			
		||||
    port: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 通讯协议,0-TcpServer模式, 1-TcpClient模式, 2-NB网关模式
 | 
			
		||||
     */
 | 
			
		||||
    protocol: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 网关SN
 | 
			
		||||
     */
 | 
			
		||||
    sn: string;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 卡管理
 | 
			
		||||
 */
 | 
			
		||||
export interface CardItem {
 | 
			
		||||
    /**
 | 
			
		||||
     * 运营商,- 0:移动 - 1:联通 - 2:电信
 | 
			
		||||
     */
 | 
			
		||||
    operator: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 手机卡号
 | 
			
		||||
     */
 | 
			
		||||
    sim_number: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * SIN码
 | 
			
		||||
     */
 | 
			
		||||
    sin: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 状态,- 0:在库 - 1:运行 - 2:待校验 - 3:故障
 | 
			
		||||
     */
 | 
			
		||||
    type: number;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 厂家
 | 
			
		||||
 */
 | 
			
		||||
export interface CommunicationItem {
 | 
			
		||||
    /**
 | 
			
		||||
     * 通讯方式,- 0:载波 - 1:无线 - 2:4  G
 | 
			
		||||
     */
 | 
			
		||||
    communication_mode: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 厂家名称
 | 
			
		||||
     */
 | 
			
		||||
    manufacturers_name: string;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
export interface FactoryListItem extends CommunicationItem {
 | 
			
		||||
    id: string,
 | 
			
		||||
    created_at: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FactoryForm extends CommunicationItem {
 | 
			
		||||
    id: string,
 | 
			
		||||
    created_at: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 卡管理列表 */
 | 
			
		||||
export interface CardListItem extends CardItem {
 | 
			
		||||
    created_at: string;
 | 
			
		||||
    delete_at: string;
 | 
			
		||||
    id: string;
 | 
			
		||||
    last_modify_at: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 卡编辑表单 */
 | 
			
		||||
export interface CardForm {
 | 
			
		||||
    /**
 | 
			
		||||
     * 运营商,- 0:移动 - 1:联通 - 2:电信
 | 
			
		||||
     */
 | 
			
		||||
    operator: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 园区id
 | 
			
		||||
     */
 | 
			
		||||
    // park?: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 手机卡号
 | 
			
		||||
     */
 | 
			
		||||
    sim_number: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * SIN码
 | 
			
		||||
     */
 | 
			
		||||
    sin: string;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface CardListQuery {
 | 
			
		||||
    /**
 | 
			
		||||
     * 结束时间
 | 
			
		||||
     */
 | 
			
		||||
    endDate?: string;
 | 
			
		||||
    page?: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 园区id
 | 
			
		||||
     */
 | 
			
		||||
    // park: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 手机号
 | 
			
		||||
     */
 | 
			
		||||
    phone?: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * sin卡号
 | 
			
		||||
     */
 | 
			
		||||
    sinCard?: string;
 | 
			
		||||
    keyword?: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 开始时间
 | 
			
		||||
     */
 | 
			
		||||
    startDate?: string;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
/** 通讯协议列表 */
 | 
			
		||||
export interface ProtocolListItem extends ProtocolItem {
 | 
			
		||||
    id: string
 | 
			
		||||
}
 | 
			
		||||
/** 通讯协议搜索表单 */
 | 
			
		||||
export interface ProtocolListQuery {
 | 
			
		||||
    /**
 | 
			
		||||
     * 关键字
 | 
			
		||||
     */
 | 
			
		||||
    keyword?: string;
 | 
			
		||||
    page: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 园区id
 | 
			
		||||
     */
 | 
			
		||||
    // park: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 通讯协议   0-TcpServer模式, 1-TcpClient模式, 2-NB网关模式
 | 
			
		||||
     */
 | 
			
		||||
    protocol?: number;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
/** 通讯协议表单 */
 | 
			
		||||
export interface ProtocolForm {
 | 
			
		||||
    /**
 | 
			
		||||
     * 波特率,0- 1200bps , 1- 2400bps 2- 4800bps, 3- 9600bps, 4- 19200bps , 5- 38400bps
 | 
			
		||||
     */
 | 
			
		||||
    bps: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * IP地址
 | 
			
		||||
     */
 | 
			
		||||
    harvester_ip: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 采集器类型,0:低压采集器 - 1:采集终端
 | 
			
		||||
     */
 | 
			
		||||
    harvester_type: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * imei
 | 
			
		||||
     */
 | 
			
		||||
    imei: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 园区id
 | 
			
		||||
     */
 | 
			
		||||
    // park: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 端口
 | 
			
		||||
     */
 | 
			
		||||
    port: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 通讯协议,0-TcpServer模式, 1-TcpClient模式, 2-NB网关模式
 | 
			
		||||
     */
 | 
			
		||||
    protocol: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 网关SN
 | 
			
		||||
     */
 | 
			
		||||
    sn: string;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
/** 厂家列表搜索 */
 | 
			
		||||
export interface FactoryListQuery {
 | 
			
		||||
    /**
 | 
			
		||||
     * 名字
 | 
			
		||||
     */
 | 
			
		||||
    name?: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 页码
 | 
			
		||||
     */
 | 
			
		||||
    page: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 园区id
 | 
			
		||||
     */
 | 
			
		||||
    // park: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 通讯方式   - 0:载波 - 1:无线 - 2:4  G
 | 
			
		||||
     */
 | 
			
		||||
    way?: number;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 表计设置列表 */
 | 
			
		||||
export interface MeterSettingListItem {
 | 
			
		||||
    /**
 | 
			
		||||
     * 表计地址
 | 
			
		||||
     */
 | 
			
		||||
    address: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 建筑
 | 
			
		||||
     */
 | 
			
		||||
    building: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 表号
 | 
			
		||||
     */
 | 
			
		||||
    code: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 启用状态
 | 
			
		||||
     */
 | 
			
		||||
    enabled: boolean;
 | 
			
		||||
    /**
 | 
			
		||||
     * 楼层
 | 
			
		||||
     */
 | 
			
		||||
    floor: string;
 | 
			
		||||
    id: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 抄表序号
 | 
			
		||||
     */
 | 
			
		||||
    index: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 表级别,(- 0:总表 - 1:主表 - 2:从表)
 | 
			
		||||
     */
 | 
			
		||||
    level: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 电表箱
 | 
			
		||||
     */
 | 
			
		||||
    meterBox: string;
 | 
			
		||||
    boxId: string,
 | 
			
		||||
    boxAddress: string,
 | 
			
		||||
    /**
 | 
			
		||||
     * 手机卡号
 | 
			
		||||
     */
 | 
			
		||||
    phone: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 通讯协议
 | 
			
		||||
     */
 | 
			
		||||
    protocol: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 倍率
 | 
			
		||||
     */
 | 
			
		||||
    rate: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 状态,- 0:在库 - 1:运行 - 2:待校验 - 3:故障
 | 
			
		||||
     */
 | 
			
		||||
    status: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 类型,(- 0:商户表- 1:园区表- 2:公摊表)
 | 
			
		||||
     */
 | 
			
		||||
    type: number;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export interface MeterSettingListQuery {
 | 
			
		||||
    /**
 | 
			
		||||
     * 表号
 | 
			
		||||
     */
 | 
			
		||||
    code?: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否启用
 | 
			
		||||
     */
 | 
			
		||||
    enabled?: boolean;
 | 
			
		||||
    /**
 | 
			
		||||
     * 表级别(- 0:总表 - 1:主表 - 2:从表)
 | 
			
		||||
     */
 | 
			
		||||
    level?: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 状态
 | 
			
		||||
     * - 0:在库
 | 
			
		||||
     * - 1:运行
 | 
			
		||||
     * - 2:待校验
 | 
			
		||||
     * - 3:故障
 | 
			
		||||
     */
 | 
			
		||||
    status?: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 类型(- 0:商户表- 1:园区表- 2:公摊表)
 | 
			
		||||
     */
 | 
			
		||||
    type?: number;
 | 
			
		||||
    keyword?:string;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BindProtocolForm {
 | 
			
		||||
    /**
 | 
			
		||||
     * 表计code列表
 | 
			
		||||
     */
 | 
			
		||||
    ids: string[];
 | 
			
		||||
 | 
			
		||||
    protocol: string;
 | 
			
		||||
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export interface BindCardForm {
 | 
			
		||||
    /**
 | 
			
		||||
     * 卡号id
 | 
			
		||||
     */
 | 
			
		||||
    cardId: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 表号
 | 
			
		||||
     */
 | 
			
		||||
    codeId: string;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export interface MeterOperateListQuery {
 | 
			
		||||
    /**
 | 
			
		||||
     * 表号
 | 
			
		||||
     */
 | 
			
		||||
    code?: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 园区
 | 
			
		||||
     */
 | 
			
		||||
    park?: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 当前状态,(0-告警1,1-告警2,2-强制模式,3-预付费模式,4-拉闸,5-合闸,6-失联,7-欠费,8-开户,9-未开户,10-正常)
 | 
			
		||||
     */
 | 
			
		||||
    status?: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 商户id
 | 
			
		||||
     */
 | 
			
		||||
    tenement?: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 0:商户表计,1:园区表计,2:公摊表计
 | 
			
		||||
     */
 | 
			
		||||
    type?: number;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export interface MeterOperateListItem {
 | 
			
		||||
    /**
 | 
			
		||||
     * 地址
 | 
			
		||||
     */
 | 
			
		||||
    address: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 电表总量
 | 
			
		||||
     */
 | 
			
		||||
    amount: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否可连接
 | 
			
		||||
     */
 | 
			
		||||
    canConnect: boolean;
 | 
			
		||||
    /**
 | 
			
		||||
     * 表号
 | 
			
		||||
     */
 | 
			
		||||
    code: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否开户
 | 
			
		||||
     */
 | 
			
		||||
    isOpen: boolean;
 | 
			
		||||
    /**
 | 
			
		||||
     * 0-预付费,1-强控
 | 
			
		||||
     */
 | 
			
		||||
    mode: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 剩余金额
 | 
			
		||||
     */
 | 
			
		||||
    money: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 合闸状态,0-合闸,1-拉闸
 | 
			
		||||
     */
 | 
			
		||||
    onPosition: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 实时功率
 | 
			
		||||
     */
 | 
			
		||||
    realTimePower: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 采集时间
 | 
			
		||||
     */
 | 
			
		||||
    time: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 表计类型,0:商户表计,1:园区表计,2:公摊表计
 | 
			
		||||
     */
 | 
			
		||||
    type: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 告警1
 | 
			
		||||
     */
 | 
			
		||||
    warning1: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 告警2
 | 
			
		||||
     */
 | 
			
		||||
    warning2: string;
 | 
			
		||||
    id: string;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BatchSwitchForm {
 | 
			
		||||
    /**
 | 
			
		||||
     * 表号id列表
 | 
			
		||||
     */
 | 
			
		||||
    ids: Key[];
 | 
			
		||||
    /**
 | 
			
		||||
     * 0-合闸,1-拉闸
 | 
			
		||||
     */
 | 
			
		||||
    status: number;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 电表批量操作结果
 | 
			
		||||
 */
 | 
			
		||||
export interface BatchMeterResult {
 | 
			
		||||
    /**
 | 
			
		||||
     * 表号
 | 
			
		||||
     */
 | 
			
		||||
    code: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 表id
 | 
			
		||||
     */
 | 
			
		||||
    id: string;
 | 
			
		||||
    address: string,
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否操作成功
 | 
			
		||||
     */
 | 
			
		||||
    succcess: boolean;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export interface BatchModeForm {
 | 
			
		||||
    /**
 | 
			
		||||
     * 表号id列表
 | 
			
		||||
     */
 | 
			
		||||
    ids: Key[];
 | 
			
		||||
    /**
 | 
			
		||||
     * 0-预付费,1-强控
 | 
			
		||||
     */
 | 
			
		||||
    mode: number;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BatchWarningForm {
 | 
			
		||||
    /**
 | 
			
		||||
     * 表号id列表
 | 
			
		||||
     */
 | 
			
		||||
    ids: Key[];
 | 
			
		||||
    /**
 | 
			
		||||
     * 告警1
 | 
			
		||||
     */
 | 
			
		||||
    warning1: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 告警2
 | 
			
		||||
     */
 | 
			
		||||
    warning2: number;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BatchTroubleForm {
 | 
			
		||||
    /**
 | 
			
		||||
     * 表计id列表
 | 
			
		||||
     */
 | 
			
		||||
    ids: string[];
 | 
			
		||||
    /**
 | 
			
		||||
     * 类型,0-故障申报,1-故障确认,2-恢复正常
 | 
			
		||||
     */
 | 
			
		||||
    type: number;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BatchParamsForm {
 | 
			
		||||
    /**
 | 
			
		||||
     * 赊欠
 | 
			
		||||
     */
 | 
			
		||||
    credit: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 尖
 | 
			
		||||
     */
 | 
			
		||||
    critical: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 平
 | 
			
		||||
     */
 | 
			
		||||
    flat: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 峰
 | 
			
		||||
     */
 | 
			
		||||
    peak: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 谷
 | 
			
		||||
     */
 | 
			
		||||
    valley: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 告警1
 | 
			
		||||
     */
 | 
			
		||||
    warning1: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 告警2
 | 
			
		||||
     */
 | 
			
		||||
    warning2: number;
 | 
			
		||||
    ids: string[],
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface NestedMeterListItem {
 | 
			
		||||
    /**
 | 
			
		||||
     * 主表地址
 | 
			
		||||
     */
 | 
			
		||||
    address: string;
 | 
			
		||||
    childrenCodes: NestedMeterListItemChild[];
 | 
			
		||||
    /**
 | 
			
		||||
     * 主表编号
 | 
			
		||||
     */
 | 
			
		||||
    code: string;
 | 
			
		||||
    id: string;
 | 
			
		||||
    codeId: string,
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface NestedMeterListItemChild {
 | 
			
		||||
    /**
 | 
			
		||||
     * 套表地址
 | 
			
		||||
     */
 | 
			
		||||
    address: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 套表表号
 | 
			
		||||
     */
 | 
			
		||||
    code: string;
 | 
			
		||||
    id: string,
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface NestedMeterForm {
 | 
			
		||||
    /**
 | 
			
		||||
     * 从表
 | 
			
		||||
     */
 | 
			
		||||
    childrenCode: string[];
 | 
			
		||||
    /**
 | 
			
		||||
     * 主表号
 | 
			
		||||
     */
 | 
			
		||||
    mainCode: string;
 | 
			
		||||
    park?: string;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MeterSettingForm {
 | 
			
		||||
    /**
 | 
			
		||||
     * 表址
 | 
			
		||||
     */
 | 
			
		||||
    address: null | string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 所辖面积
 | 
			
		||||
     */
 | 
			
		||||
    area: null | string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 电表箱
 | 
			
		||||
     */
 | 
			
		||||
    boxId: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 所在建筑ID
 | 
			
		||||
     */
 | 
			
		||||
    building: null | string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 表计表号
 | 
			
		||||
     */
 | 
			
		||||
    code: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 表级别, 0:总表 - 1:主表 - 2:从表
 | 
			
		||||
     */
 | 
			
		||||
    level: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * 所在建筑楼层
 | 
			
		||||
     */
 | 
			
		||||
    onFloor: null | string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 倍率
 | 
			
		||||
     */
 | 
			
		||||
    ratio: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 表计类型,0:商户表计,1:园区表计,2:公摊表计
 | 
			
		||||
     */
 | 
			
		||||
    type: number;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ChangeMeterEnabledForm {
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否启用
 | 
			
		||||
     */
 | 
			
		||||
    enabled: boolean;
 | 
			
		||||
    /**
 | 
			
		||||
     * 表id
 | 
			
		||||
     */
 | 
			
		||||
    ids: Key[];
 | 
			
		||||
    /**
 | 
			
		||||
     * 停用时间
 | 
			
		||||
     */
 | 
			
		||||
    time?: string;
 | 
			
		||||
    [property: string]: any;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										249
									
								
								src/shared/foundation.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								src/shared/foundation.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,249 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 不需要任何参数即可以生成指定类型对象的工厂函数类型。
 | 
			
		||||
 */
 | 
			
		||||
export type Factory<T> = () => T;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 接受一个参数来生成一个指定类型的新对象的工厂函数类型。
 | 
			
		||||
 */
 | 
			
		||||
export type MapFactory<T, P = any> = (obj: P) => T;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 可能接受一个参数也可以不使用任何参数来生成指定类型新对象的工厂函数类型。
 | 
			
		||||
 */
 | 
			
		||||
export type MaybeMapFactory<T, P = any> = (obj?: P) => T;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 可能接受一组任意类型的参数集合来生成指定类型新对象的工厂函数类型。
 | 
			
		||||
 */
 | 
			
		||||
export type ParamsFactory<T, P = any> = (...args: P[]) => T;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 接受一个对象(默认是字符串)作为参数的回调函数,可以是同步函数也可以是异步函数。
 | 
			
		||||
 */
 | 
			
		||||
export type ObjectCallback<P = string, T = void> = (obj: P) => T | Promise<T>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 接受一个对象(默认是字符串)作为参数的回调函数,仅可以是同步函数。
 | 
			
		||||
 */
 | 
			
		||||
export type SyncObjectCallback<P = string, T = void> = (obj: P) => T;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 接受一个对象(默认是字符串)或者零个对象作为参数的回调函数,可以是同步函数也可以是异步函数。
 | 
			
		||||
 */
 | 
			
		||||
export type MaybeObjectCallback<P = string, T = void> = ObjectCallback<P | undefined, T>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 接受一个对象(默认是字符串)或者零个对象作为参数的回调函数,仅可以是同步函数。
 | 
			
		||||
 */
 | 
			
		||||
export type SyncMaybeObjectCallback<P = string, T = void> = SyncObjectCallback<P | undefined, T>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 接受一个对象数组(默认是字符串数组)作为参数的回调函数,可以是同步函数也可以是异步函数。
 | 
			
		||||
 */
 | 
			
		||||
export type ObjectsCallback<P = string, T = void> = ObjectCallback<P[], T>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 接受一个对象数组(默认是字符串数组)作为参数的回调函数,仅可以是同步函数。
 | 
			
		||||
 */
 | 
			
		||||
export type SyncObjectsCallback<P = string, T = void> = SyncObjectCallback<P[], T>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 接收一个对象数组(默认是字符串数组)或者零个对象作为参数的回调函数,可以是同步函数也可以是异步函数。
 | 
			
		||||
 */
 | 
			
		||||
export type MaybeObjectsCallback<P = string, T = void> = ObjectCallback<P[] | undefined, T>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 接收一个对象数组(默认是字符串数组)或者零个对象作为参数的回调函数,仅可以是同步函数。
 | 
			
		||||
 */
 | 
			
		||||
export type SyncMaybeObjectsCallback<P = string, T = void> = SyncObjectCallback<P[] | undefined, T>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 可以接受任意数量任意参数类型的回调函数。
 | 
			
		||||
 */
 | 
			
		||||
export type ExtendParamCallback<P = unknown, T = void> = (...args: P[]) => T | Promise<T>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 可以接受任意数量任意参数类型的仅支持同步的回调函数。
 | 
			
		||||
 */
 | 
			
		||||
export type SyncExtendParamCallback<P = unknown, T = void> = (...args: P[]) => T;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 不接受任何参数内容的回调函数,可以是同步函数也可以是异步函数。
 | 
			
		||||
 */
 | 
			
		||||
export type Callback<T = void> = () => T | Promise<T>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 不接受任何参数内容的回调函数,仅可以是同步函数。
 | 
			
		||||
 */
 | 
			
		||||
export type SyncCallback<T = void> = () => T;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在Store中定义状态操作Action的无参同步Action类型。
 | 
			
		||||
 */
 | 
			
		||||
export type SyncAction = SyncCallback<void>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在Store中定义状态操作Action的无参可异步Action类型。
 | 
			
		||||
 */
 | 
			
		||||
export type AsyncAction = Callback<void>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在Store中定义状态操作Action的单一参数同步Action类型。
 | 
			
		||||
 */
 | 
			
		||||
export type SyncParamAction<T> = SyncObjectCallback<T, void>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在Store中定义状态操作Action的单一参数可异步Action类型。
 | 
			
		||||
 */
 | 
			
		||||
export type AsyncParamAction<T> = ObjectCallback<T, void>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在Store中定义状态操作Action的不定参同步Action类型。
 | 
			
		||||
 */
 | 
			
		||||
export type SyncMaybeAction<T> = SyncMaybeObjectCallback<T>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在Store中定义状态操作Action的不定参可异步Action类型。
 | 
			
		||||
 */
 | 
			
		||||
export type AsyncMaybeAction<T> = MaybeObjectCallback<T>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在Store中定义状态操作Action的展开参同步Action类型。
 | 
			
		||||
 */
 | 
			
		||||
export type SyncExtendParamAction<T> = SyncExtendParamCallback<T>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在Store中定义状态操作Action的展开参可异步Action类型。
 | 
			
		||||
 */
 | 
			
		||||
export type AsyncExtendParamAction<T> = ExtendParamCallback<T>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于定义可以接受重置事件的Ref组件。
 | 
			
		||||
 */
 | 
			
		||||
export interface Resetable {
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件可以接受的重置方法。
 | 
			
		||||
   */
 | 
			
		||||
  reset: Callback;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于定义可执行打开动作的Ref组件。
 | 
			
		||||
 */
 | 
			
		||||
export interface Openable {
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件可以接受的打开方法。
 | 
			
		||||
   */
 | 
			
		||||
  open: Callback;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于定义可执行关闭动作的Ref组件。
 | 
			
		||||
 */
 | 
			
		||||
export interface Closeable {
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件可以接受的关闭方法。
 | 
			
		||||
   */
 | 
			
		||||
  close: Callback;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于定义可以执行特定动作的Ref组件。
 | 
			
		||||
 * 组件所执行的动作可以接受任意数量的参数,但不会返回任何结果。
 | 
			
		||||
 */
 | 
			
		||||
export interface Actionable<T = unknown> {
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件可以接受的执行特定动作的方法。
 | 
			
		||||
   */
 | 
			
		||||
  action?: ExtendParamCallback<T>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 定义可以执行步骤控制事件的Ref组件类型。
 | 
			
		||||
 */
 | 
			
		||||
export interface SteppingEvents<T = unknown, R = void> {
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件可以执行的确认事件方法。
 | 
			
		||||
   */
 | 
			
		||||
  onConfirm?: ExtendParamCallback<T, R>;
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件可以执行的取消事件方法。
 | 
			
		||||
   */
 | 
			
		||||
  onCancel?: ExtendParamCallback<T, R>;
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件可以执行的上一步事件方法。
 | 
			
		||||
   */
 | 
			
		||||
  onPrevious?: ExtendParamCallback<T, R>;
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件可以执行的下一步事件方法。
 | 
			
		||||
   */
 | 
			
		||||
  onNext?: ExtendParamCallback<T, R>;
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件可以执行的跳过一定数量的步骤的方法。
 | 
			
		||||
   */
 | 
			
		||||
  onSkip?: ExtendParamCallback<T, R>;
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件可以执行的跳转至制定步骤的方法。
 | 
			
		||||
   */
 | 
			
		||||
  onMoveTo?: ExtendParamCallback<T, R>;
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件可以执行的重置步骤的方法。
 | 
			
		||||
   */
 | 
			
		||||
  onReset?: ExtendParamCallback<T, R>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 定义导航链接可以接受的State,主要用于在导航过程中以非明文的形式携带更多的信息。
 | 
			
		||||
 */
 | 
			
		||||
export interface NavigationState {
 | 
			
		||||
  /**
 | 
			
		||||
   * 表示当前导航链接是否由主菜单点击的。
 | 
			
		||||
   */
 | 
			
		||||
  fromMainMenu?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于定义仅接受分页页码信息的React Query查询键
 | 
			
		||||
 */
 | 
			
		||||
export type PageableQueryKey = [key: string, page: number];
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于定义可编辑Table中列需要使用的控件类型。
 | 
			
		||||
 */
 | 
			
		||||
export type FormItemType = 'input' | 'password' | 'number' | 'checkbox' | 'radio' | 'select';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于记录可以发生修改的脏数据。
 | 
			
		||||
 */
 | 
			
		||||
export interface DirtyableValue<T> {
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录数据当前的值。
 | 
			
		||||
   */
 | 
			
		||||
  value: T;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录数据在修改前的值。
 | 
			
		||||
   */
 | 
			
		||||
  lastValue: T;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录数据是否发生了更改。
 | 
			
		||||
   */
 | 
			
		||||
  dirty: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 转换一般的数据记录类型成为可记录修改的脏数据类型。
 | 
			
		||||
 */
 | 
			
		||||
export type Dirtyable<T> = { [P in keyof T]: DirtyableValue<T[P]> };
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于可编辑表格反馈更改后数据时携带的元信息。
 | 
			
		||||
 */
 | 
			
		||||
export interface EditableCellMeta {
 | 
			
		||||
  /**
 | 
			
		||||
   * 元信息。
 | 
			
		||||
   */
 | 
			
		||||
  meta: string;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										324
									
								
								src/shared/model-accounting.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										324
									
								
								src/shared/model-accounting.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,324 @@
 | 
			
		||||
import { Meter04KvInfo, TenementInfo } from './model-park'
 | 
			
		||||
import { ChargeInfo, SyncStatus } from './model-charge'
 | 
			
		||||
import { InvoiceInfo } from './model-invoice'
 | 
			
		||||
 | 
			
		||||
// 账务列表每一项
 | 
			
		||||
export interface Record {
 | 
			
		||||
    /** 账务记录条目ID */
 | 
			
		||||
    id: string,
 | 
			
		||||
    /** 发生时间 */
 | 
			
		||||
    occurredAt?: string,
 | 
			
		||||
    /** 账目类型 */
 | 
			
		||||
    type?: string,
 | 
			
		||||
    /** 收入 */
 | 
			
		||||
    income?: number,
 | 
			
		||||
    /**支出 */
 | 
			
		||||
    expenditure?: number,
 | 
			
		||||
    /** 余额 */
 | 
			
		||||
    balance?: number,
 | 
			
		||||
    /** 发生方式 */
 | 
			
		||||
    transfer?: string,
 | 
			
		||||
    /** 账目元信息 */
 | 
			
		||||
    meta?: Meta,
 | 
			
		||||
    /** 操作员名称 */
 | 
			
		||||
    operator?: string,
 | 
			
		||||
    /** 审核员ID */
 | 
			
		||||
    auditor?: string,
 | 
			
		||||
    /** 审核员名称 */
 | 
			
		||||
    auditorName?: string,
 | 
			
		||||
    /** 审核时间 */
 | 
			
		||||
    auditedAt?: string,
 | 
			
		||||
    tenement?: string,
 | 
			
		||||
    // 账目元信息
 | 
			
		||||
    topUpMeta?: TopUpMeta,
 | 
			
		||||
    /** 金额 */
 | 
			
		||||
    money: number,
 | 
			
		||||
    /** 同步状态 */
 | 
			
		||||
    syncStatus: SyncStatus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface TopUpMeta {
 | 
			
		||||
    /** 备注 */
 | 
			
		||||
    remark?: string,
 | 
			
		||||
    /** 附加操作 */
 | 
			
		||||
    appendOperation?: string,
 | 
			
		||||
    /** 账目方向 */
 | 
			
		||||
    direction?: string,
 | 
			
		||||
    /** 账目金额 */
 | 
			
		||||
    amount?: number,
 | 
			
		||||
    /** 附加操作记录表号 */
 | 
			
		||||
    code?: string,
 | 
			
		||||
    /** 回滚id */
 | 
			
		||||
    sid?: string,
 | 
			
		||||
    /** 表号 */
 | 
			
		||||
    meters: string [],
 | 
			
		||||
    /** 凭证号 */
 | 
			
		||||
    vouchNo: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 账目元信息
 | 
			
		||||
export interface Meta {
 | 
			
		||||
    /** 关联表计信息 */
 | 
			
		||||
    meter?: Meter,
 | 
			
		||||
    /** 关联重置记录ID */
 | 
			
		||||
    chargeRecord?: ChargeInfo | null,
 | 
			
		||||
    /** 关联重置写表任务ID */
 | 
			
		||||
    chargeTask?: ChargeTask | null,
 | 
			
		||||
    /** 关联商户信息 */
 | 
			
		||||
    tenement?: TenementInfo,
 | 
			
		||||
    /** 已开具发票记录 */
 | 
			
		||||
    invoice?: InvoiceInfo
 | 
			
		||||
    /** 对应code */
 | 
			
		||||
    code ?: string
 | 
			
		||||
    /** 备注 */
 | 
			
		||||
    remark?: string
 | 
			
		||||
    direction?: number
 | 
			
		||||
    appendOperation: number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 关联表计信息
 | 
			
		||||
export interface Meter extends Meter04KvInfo {
 | 
			
		||||
    /** 表计表显倍率 */
 | 
			
		||||
    displayRatio: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 关联重置写表任务ID
 | 
			
		||||
export interface ChargeTask {
 | 
			
		||||
    /** 同步任务ID */
 | 
			
		||||
    id: string,
 | 
			
		||||
    /** 归属企业ID */
 | 
			
		||||
    userId: string,
 | 
			
		||||
    /** 归属园区ID */
 | 
			
		||||
    parkId: string,
 | 
			
		||||
    /** 任务简报 */
 | 
			
		||||
    briefing: string,
 | 
			
		||||
    /** 计划执行时间 */
 | 
			
		||||
    scheduleAt: string,
 | 
			
		||||
    /** 上次执行时间 */
 | 
			
		||||
    lastDispatchedAt: string | null,
 | 
			
		||||
    /** 执行耗时 单位:毫秒 */
 | 
			
		||||
    executionCost: number,
 | 
			
		||||
    /** 尝试次数 */
 | 
			
		||||
    attempts: number,
 | 
			
		||||
    /** 当前状态 */
 | 
			
		||||
    status: ChargeTaskStatus,
 | 
			
		||||
    /** 锁定状态 */
 | 
			
		||||
    lockDown: ChargeTaskLockDown,
 | 
			
		||||
    /** 任务元信息 */
 | 
			
		||||
    meta: ChargeTaskMeta,
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum AccountDirection {
 | 
			
		||||
    in,
 | 
			
		||||
    out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum AppendOperate {
 | 
			
		||||
    '充值',
 | 
			
		||||
    '冲正',
 | 
			
		||||
    '退费',
 | 
			
		||||
    '电费发行',
 | 
			
		||||
    "结算"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum GenerateWay {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum ChargeTaskStatus {
 | 
			
		||||
    /** 队列中 */
 | 
			
		||||
    queue,
 | 
			
		||||
    /** 执行中 */
 | 
			
		||||
    execution,
 | 
			
		||||
    /** 成功 */
 | 
			
		||||
    success,
 | 
			
		||||
    fail,
 | 
			
		||||
    cancel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum ChargeTaskLockDown {
 | 
			
		||||
    /** 未锁定 */
 | 
			
		||||
    unlocked,
 | 
			
		||||
    /** 系统锁定 */
 | 
			
		||||
    systemLock,
 | 
			
		||||
    /** 人工锁定 */
 | 
			
		||||
    artificialLock
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ChargeTaskMeta {
 | 
			
		||||
    /** 任务目标 */
 | 
			
		||||
    objective: string,
 | 
			
		||||
    /** 表计编号 */
 | 
			
		||||
    meterCode: string,
 | 
			
		||||
    /** 远程平台代号 */
 | 
			
		||||
    imrs: string,
 | 
			
		||||
    /** 远程平台名称 */
 | 
			
		||||
    imrsName: string,
 | 
			
		||||
    /** 远程平台URL 如果是原生平台则采用自定义URL Scheme */
 | 
			
		||||
    imrsUrl: string,
 | 
			
		||||
    /** 最大重试次数 */
 | 
			
		||||
    maxRetries: number,
 | 
			
		||||
    /** 重试间隔算法 */
 | 
			
		||||
    intervalAlgorithm: IntervalAlgorithm,
 | 
			
		||||
    /** 重试基础间隔 */
 | 
			
		||||
    interval: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum IntervalAlgorithm {
 | 
			
		||||
    /** 指数退避 */
 | 
			
		||||
    /** 2倍线性间隔 */
 | 
			
		||||
    /** 3倍线性间隔 */
 | 
			
		||||
    /** 固定间隔 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export interface Related {
 | 
			
		||||
    index?: number,
 | 
			
		||||
    /** 汇算记录ID */
 | 
			
		||||
    id: string,
 | 
			
		||||
    /** 汇算起始日期 */
 | 
			
		||||
    settlingStart: string,
 | 
			
		||||
    /** 汇算结束日期 */
 | 
			
		||||
    settlingEnd: string,
 | 
			
		||||
    /** 账务主体ID */
 | 
			
		||||
    tenement: string,
 | 
			
		||||
    /** 账务简称 */
 | 
			
		||||
    tenementName: string,
 | 
			
		||||
    /** 商户全称 */
 | 
			
		||||
    tenementFullName: string,
 | 
			
		||||
    /** 总收入 */
 | 
			
		||||
    totalIncome: number,
 | 
			
		||||
    /** 总支出 */
 | 
			
		||||
    totalExpenditure: number,
 | 
			
		||||
    /** 汇算期初余额 */
 | 
			
		||||
    initialBalance: number,
 | 
			
		||||
    /** 汇算余额 */
 | 
			
		||||
    balance: number,
 | 
			
		||||
    /** 汇算类型 */
 | 
			
		||||
    type: number,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Overall {
 | 
			
		||||
    /** 汇算记录ID */
 | 
			
		||||
    id: string,
 | 
			
		||||
    /** 汇算起始日期 */
 | 
			
		||||
    settlingStart: string,
 | 
			
		||||
    /** 汇算结束日期 */
 | 
			
		||||
    settlingEnd: string,
 | 
			
		||||
    /** 账务主体ID */
 | 
			
		||||
    tenement: string,
 | 
			
		||||
    /** 账务主体名称 */
 | 
			
		||||
    tenementName: string,
 | 
			
		||||
    /** 总收入 */
 | 
			
		||||
    totalIncome: string,
 | 
			
		||||
    /** 总支出 */
 | 
			
		||||
    totalExpenditure: string,
 | 
			
		||||
    /** 汇算期初余额 */
 | 
			
		||||
    initialBalance: string,
 | 
			
		||||
    /** 汇算余额 */
 | 
			
		||||
    balance: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface EditAccountingDataMeta {
 | 
			
		||||
    remark?: string;
 | 
			
		||||
    appendOperation?: number;
 | 
			
		||||
    code?: string;
 | 
			
		||||
    direction?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface EditAccountingData {
 | 
			
		||||
    /** 账目类型 */
 | 
			
		||||
    type: string,
 | 
			
		||||
    /** 转账类型 */
 | 
			
		||||
    paymentType: string,
 | 
			
		||||
    /** 发生金额 */
 | 
			
		||||
    amount: string,
 | 
			
		||||
    /** 账务条目发生时间 */
 | 
			
		||||
    occurredAt: string,
 | 
			
		||||
    /** 附属元信息 */
 | 
			
		||||
    // meta: string,
 | 
			
		||||
    meta: EditAccountingDataMeta,
 | 
			
		||||
    /** 账务条目主体ID */
 | 
			
		||||
    tenement: string,
 | 
			
		||||
    /** 园区id */
 | 
			
		||||
    parkId: string,
 | 
			
		||||
    /** 凭证号 */
 | 
			
		||||
    vouchNo: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// export interface CreateAccountingData extends UpdateAccountingData {
 | 
			
		||||
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export interface Settlement {
 | 
			
		||||
    /** 结算记录ID */
 | 
			
		||||
    id: string,
 | 
			
		||||
    /** 结算日期 */
 | 
			
		||||
    settledAt: string,
 | 
			
		||||
    /** 账务主体ID */
 | 
			
		||||
    tenement: string,
 | 
			
		||||
    /** 账务主体名称 */
 | 
			
		||||
    tenementName: string,
 | 
			
		||||
    /** 表计编号 */
 | 
			
		||||
    meterCode: string,
 | 
			
		||||
    /** 合计充值 */
 | 
			
		||||
    totalIncome: number,
 | 
			
		||||
    /** 合计消费 */
 | 
			
		||||
    totalExpenditure: number,
 | 
			
		||||
    /** 结算状态 */
 | 
			
		||||
    status: string,
 | 
			
		||||
    /** 清算余额 */
 | 
			
		||||
    balance: string,
 | 
			
		||||
    /** 操作员 */
 | 
			
		||||
    operator: string,
 | 
			
		||||
    /** 审核员 */
 | 
			
		||||
    auditor: string | null
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 支付类型
 | 
			
		||||
export enum AccountingType {
 | 
			
		||||
    '现金',
 | 
			
		||||
    '银行卡',
 | 
			
		||||
    '支付宝',
 | 
			
		||||
    '微信',
 | 
			
		||||
    '云闪付',
 | 
			
		||||
    '对公转账',
 | 
			
		||||
    "C端-微信"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 发生方式
 | 
			
		||||
export enum HappenWay {
 | 
			
		||||
    '充值',
 | 
			
		||||
    '冲正',
 | 
			
		||||
    '电费',
 | 
			
		||||
    "退费",
 | 
			
		||||
  "初始化余额"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 汇算类型
 | 
			
		||||
export enum SettleAccountType {
 | 
			
		||||
    '阶段汇算',
 | 
			
		||||
    '结算',
 | 
			
		||||
    '终算',
 | 
			
		||||
    '实时汇算'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BalanceOverall {
 | 
			
		||||
    /** 商户全称 */
 | 
			
		||||
    tenementFullName: string,
 | 
			
		||||
    /** 商户简称 */
 | 
			
		||||
    tenementName: string,
 | 
			
		||||
    /** 商户电表数量 */
 | 
			
		||||
    metersCount: number,
 | 
			
		||||
    /** 商户汇算起始金额 */
 | 
			
		||||
    initialBalance: number,
 | 
			
		||||
    /** 商户已使用金额 */
 | 
			
		||||
    totalExpenditure: number,
 | 
			
		||||
    /** 商户充值总金额 */
 | 
			
		||||
    totalIncome: number,
 | 
			
		||||
    /** 余额 */
 | 
			
		||||
    balance: number,
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										192
									
								
								src/shared/model-calculate.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								src/shared/model-calculate.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,192 @@
 | 
			
		||||
import { BasePublicityInfo } from '@/shared/model-publicity';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 电费计算报表信息
 | 
			
		||||
 */
 | 
			
		||||
export type ReportInfo = BasePublicityInfo;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 公示报表步骤状态
 | 
			
		||||
 */
 | 
			
		||||
export interface ReportSteps {
 | 
			
		||||
  /** 试计算步骤 */
 | 
			
		||||
  calculate: boolean;
 | 
			
		||||
  /** 预览报表步骤 */
 | 
			
		||||
  preview: boolean;
 | 
			
		||||
  /** 发布步骤 */
 | 
			
		||||
  publish: boolean;
 | 
			
		||||
  /** 户表抄表填写 */
 | 
			
		||||
  submeter: boolean;
 | 
			
		||||
  /** 园区总表填写状态 */
 | 
			
		||||
  summary: boolean;
 | 
			
		||||
  /** 待摊薄填报状态 */
 | 
			
		||||
  willDiluted: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 公示记录已填写的总电量
 | 
			
		||||
 */
 | 
			
		||||
export interface ReportElectricSummary {
 | 
			
		||||
  /** 核算报表Id */
 | 
			
		||||
  reportId: string;
 | 
			
		||||
  /** 总消耗电度 */
 | 
			
		||||
  overall: Consumption;
 | 
			
		||||
  /** 总建筑面积 */
 | 
			
		||||
  area: string;
 | 
			
		||||
  /** 基本电费 */
 | 
			
		||||
  basicFee: string;
 | 
			
		||||
  pooledBasicFeeByAmount: string;
 | 
			
		||||
  pooledBasicFeeByArea: string;
 | 
			
		||||
  /** 调整电费 */
 | 
			
		||||
  adjustFee: string;
 | 
			
		||||
  pooledAdjustFeeByAmount: string;
 | 
			
		||||
  pooledAdjustFeeByArea: string;
 | 
			
		||||
  consumption: string;
 | 
			
		||||
  loss: string;
 | 
			
		||||
  lossRate: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 填报电量计算返回结果
 | 
			
		||||
 */
 | 
			
		||||
export interface SummaryCaculateResult {
 | 
			
		||||
  /** 电度电费 */
 | 
			
		||||
  consumptionFee: null | string;
 | 
			
		||||
  /** 有功(尖峰)电价 */
 | 
			
		||||
  criticalPrice: null | string;
 | 
			
		||||
  /** 有功(平)电量 */
 | 
			
		||||
  flat: null | string;
 | 
			
		||||
  /** 有功(平)电费 */
 | 
			
		||||
  flatFee: null | string;
 | 
			
		||||
  /** 有功(平)电价 */
 | 
			
		||||
  flatPrice: null | string;
 | 
			
		||||
  /** 有功(总)电价,电费均价 */
 | 
			
		||||
  overallPrice: null | string;
 | 
			
		||||
  /** 有功(峰)电价 */
 | 
			
		||||
  peakPrice: null | string;
 | 
			
		||||
  /** 有功(谷)电价 */
 | 
			
		||||
  valleyPrice: null | string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 待摊薄费用信息
 | 
			
		||||
 */
 | 
			
		||||
export interface ReportMaintenance {
 | 
			
		||||
  /** 待摊薄记录ID */
 | 
			
		||||
  diluteId: string;
 | 
			
		||||
  /** 维护费数额,单位:元/月 */
 | 
			
		||||
  fee: string;
 | 
			
		||||
  /** 备注 */
 | 
			
		||||
  memo: null | string;
 | 
			
		||||
  /** 费用项目名称 */
 | 
			
		||||
  name: string;
 | 
			
		||||
  /** 所属报表ID */
 | 
			
		||||
  reportId: string;
 | 
			
		||||
  /** 来源预置ID,如果不为空,表示条目是导入得来 */
 | 
			
		||||
  sourceId: null | string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 抄表记录信息
 | 
			
		||||
 */
 | 
			
		||||
export interface MeterRecord {
 | 
			
		||||
  /** 户址 */
 | 
			
		||||
  address: null | string;
 | 
			
		||||
  /** 退补电量(尖峰) */
 | 
			
		||||
  adjustCritical: string;
 | 
			
		||||
  /** 退补电量(平) */
 | 
			
		||||
  adjustFlat: string;
 | 
			
		||||
  /** 退补电量 */
 | 
			
		||||
  adjustOverall: string;
 | 
			
		||||
  /** 退补电量(峰) */
 | 
			
		||||
  adjustPeak: string;
 | 
			
		||||
  /** 退补电量(谷) */
 | 
			
		||||
  adjustValley: string;
 | 
			
		||||
  /** 联系人名称 */
 | 
			
		||||
  contactName: null | string;
 | 
			
		||||
  /** 联系人电话 */
 | 
			
		||||
  contactPhone: null | string;
 | 
			
		||||
  /** 条目创建时间,时间格式为 yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  createdAt: string;
 | 
			
		||||
  /** 本期表底(尖峰) */
 | 
			
		||||
  currentPeriodCritical: null | string;
 | 
			
		||||
  /** 本期表底(平) */
 | 
			
		||||
  currentPeriodFlat: null | string;
 | 
			
		||||
  /** 本期表底(总) */
 | 
			
		||||
  currentPeriodOverall: string;
 | 
			
		||||
  /** 本期表底(峰) */
 | 
			
		||||
  currentPeriodPeak: null | string;
 | 
			
		||||
  /** 本期表底(谷) */
 | 
			
		||||
  currentPeriodValley: null | string;
 | 
			
		||||
  /** 用户名称 */
 | 
			
		||||
  customerName: null | string;
 | 
			
		||||
  /** 是否公用设备表计 */
 | 
			
		||||
  isPublicMeter: boolean;
 | 
			
		||||
  /** 条目最后修改时间,时间格式为 yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  lastModifiedAt: null | string;
 | 
			
		||||
  /** 上期表底(尖峰) */
 | 
			
		||||
  lastPeriodCritical: null | string;
 | 
			
		||||
  /** 上期表底(平) */
 | 
			
		||||
  lastPeriodFlat: null | string;
 | 
			
		||||
  /** 上期表底(总) */
 | 
			
		||||
  lastPeriodOverall: string;
 | 
			
		||||
  /** 上期表底(峰) */
 | 
			
		||||
  lastPeriodPeak: null | string;
 | 
			
		||||
  /** 上期表底(谷) */
 | 
			
		||||
  lastPeriodValley: null | string;
 | 
			
		||||
  /** 表计表号 */
 | 
			
		||||
  meterId: string;
 | 
			
		||||
  /** 表计倍率 */
 | 
			
		||||
  ratio: string;
 | 
			
		||||
  /** 抄表序号,使用抄表序号进行排序 */
 | 
			
		||||
  seq: number;
 | 
			
		||||
  /** 是否计入摊薄 */
 | 
			
		||||
  willDilute?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 已填写的报表电量电费信息
 | 
			
		||||
 */
 | 
			
		||||
export interface ReportFilled extends ReportMeterUnit {
 | 
			
		||||
  /** 调整电费 */
 | 
			
		||||
  adjustFee: string;
 | 
			
		||||
  /** 基本电费 */
 | 
			
		||||
  basicFee: string;
 | 
			
		||||
  /** 电度电费 */
 | 
			
		||||
  consumptionFee: null | string;
 | 
			
		||||
  /** 线损率 */
 | 
			
		||||
  authorizedLossRate: null | string;
 | 
			
		||||
  /** 光伏发电电量 */
 | 
			
		||||
  generateAmount?: number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 核算报表中表计基本数据单元
 | 
			
		||||
 */
 | 
			
		||||
export interface ReportMeterUnit {
 | 
			
		||||
  /** 有功(尖峰)电量 */
 | 
			
		||||
  critical: Consumption;
 | 
			
		||||
  /** 有功(平)电量,计算得到的数值,不需要填写 */
 | 
			
		||||
  flat: Consumption;
 | 
			
		||||
  /** 有功(总)电量,总电量 */
 | 
			
		||||
  overall: Consumption;
 | 
			
		||||
  /** 有功(峰)电量 */
 | 
			
		||||
  peak: Consumption;
 | 
			
		||||
  /** 有功(谷)电量 */
 | 
			
		||||
  valley: Consumption;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 电量消耗综合数据
 | 
			
		||||
 */
 | 
			
		||||
export interface Consumption {
 | 
			
		||||
  /** 电量 */
 | 
			
		||||
  amount: string;
 | 
			
		||||
  /** 电费 */
 | 
			
		||||
  fee: null | string;
 | 
			
		||||
  /** 电价 */
 | 
			
		||||
  price: null | string;
 | 
			
		||||
  /** 电费占比 */
 | 
			
		||||
  proportion: null | string;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										60
									
								
								src/shared/model-charge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/shared/model-charge.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 充值记录
 | 
			
		||||
 */
 | 
			
		||||
export interface ChargeInfo {
 | 
			
		||||
  /** 充值账号 */
 | 
			
		||||
  account: string;
 | 
			
		||||
  /** 充值金额 */
 | 
			
		||||
  amount: string;
 | 
			
		||||
  /** 充值记录ID */
 | 
			
		||||
  id: string;
 | 
			
		||||
  /** 表计编号 */
 | 
			
		||||
  meter: string;
 | 
			
		||||
  /** 表计地址 */
 | 
			
		||||
  meterAddress: string;
 | 
			
		||||
  /** 充值方式,0:现金,1:银行卡,2:支付宝,3:微信,4:云闪付 */
 | 
			
		||||
  paymentType: PaymentType;
 | 
			
		||||
  /** 同步状态,0:未同步,1:同步成功,2:同步失败 */
 | 
			
		||||
  syncStatus: SyncStatus;
 | 
			
		||||
  /** 商户ID */
 | 
			
		||||
  tenement: string;
 | 
			
		||||
  /** 商户名称 */
 | 
			
		||||
  tenementName: string;
 | 
			
		||||
  /** 充值时间,格式:yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  toppedUpAt: string;
 | 
			
		||||
  /** 取消时间,格式:yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  cancelledAt: string;
 | 
			
		||||
  /** 付款凭证号*/
 | 
			
		||||
  voucherNo: string;
 | 
			
		||||
  /** 操作时间 */
 | 
			
		||||
  paymentAt: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export enum ChargeType {
 | 
			
		||||
  "充值",
 | 
			
		||||
  "冲正",
 | 
			
		||||
  "退费"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 充值方式
 | 
			
		||||
 */
 | 
			
		||||
export const enum PaymentType {
 | 
			
		||||
  Cash,
 | 
			
		||||
  Card,
 | 
			
		||||
  Alipay,
 | 
			
		||||
  Wechat,
 | 
			
		||||
  UnionPay,
 | 
			
		||||
  Public_Transfer,
 | 
			
		||||
  C_Wechat
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 同步状态
 | 
			
		||||
 */
 | 
			
		||||
export const enum SyncStatus {
 | 
			
		||||
  UnSync,
 | 
			
		||||
  Success,
 | 
			
		||||
  Failure
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										178
									
								
								src/shared/model-components copy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								src/shared/model-components copy.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 用于描述从后端传来的使用code承载内容编号,name承载内容名称的基本数据结构。
 | 
			
		||||
 */
 | 
			
		||||
export interface BaseContent {
 | 
			
		||||
  /**
 | 
			
		||||
   * 内容编号。
 | 
			
		||||
   */
 | 
			
		||||
  code: string;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 内容名称。
 | 
			
		||||
   */
 | 
			
		||||
  name: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于解析来自服务端的响应体基本内容,其他响应可直接继承和扩展本接口
 | 
			
		||||
 */
 | 
			
		||||
export interface BaseResponse {
 | 
			
		||||
  /**
 | 
			
		||||
   * 用于记录服务端处理状态码
 | 
			
		||||
   */
 | 
			
		||||
  code: number;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 用于记录服务端处理状态信息
 | 
			
		||||
   */
 | 
			
		||||
  message: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 向服务端查询数量的响应体。
 | 
			
		||||
 */
 | 
			
		||||
export interface AmountResponse extends BaseResponse {
 | 
			
		||||
  /**
 | 
			
		||||
   * 所查询的内容数量。
 | 
			
		||||
   */
 | 
			
		||||
  amount: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于记录条目修改时间以及修改人的记录。
 | 
			
		||||
 */
 | 
			
		||||
export interface ModificationRecords {
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目创建时间。
 | 
			
		||||
   */
 | 
			
		||||
  createdAt: Date | string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目创建人名称或代号。
 | 
			
		||||
   */
 | 
			
		||||
  createdBy: string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目修改时间。
 | 
			
		||||
   */
 | 
			
		||||
  modifiedAt: Date | string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目修改人名称或代号。
 | 
			
		||||
   */
 | 
			
		||||
  modifiedBy: string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目删除时间,如果未删除则为null,可以用于实现软删除。
 | 
			
		||||
   */
 | 
			
		||||
  deletedAt: Date | string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目删除人名称或代号。
 | 
			
		||||
   */
 | 
			
		||||
  deletedBy: string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目撤销时间,注意名词与删除和取消的区别。
 | 
			
		||||
   */
 | 
			
		||||
  revokedAt: Date | string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目撤销人名称或代号。
 | 
			
		||||
   */
 | 
			
		||||
  revokedBy: string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目取消时间,注意名词与删除和撤销的区别。
 | 
			
		||||
   */
 | 
			
		||||
  canceledAt: Date | string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目取消人名称或代号。
 | 
			
		||||
   */
 | 
			
		||||
  canceledBy: string | number | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 定义解析分页内容所需要的响应参数。
 | 
			
		||||
 */
 | 
			
		||||
export interface Pageable {
 | 
			
		||||
  /**
 | 
			
		||||
   * 当前所返回的数据所在的页面。
 | 
			
		||||
   */
 | 
			
		||||
  current: number;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 当前所返回的数据每页条目数量。
 | 
			
		||||
   */
 | 
			
		||||
  pageSize: number;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 当前所有的页面总数。
 | 
			
		||||
   */
 | 
			
		||||
  total: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 定义可以支持模型数据进行排序的类型。
 | 
			
		||||
 */
 | 
			
		||||
export interface Sortable {
 | 
			
		||||
  /**
 | 
			
		||||
   * 排序字段。
 | 
			
		||||
   */
 | 
			
		||||
  sort: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 定义记录条目的字符串型状态信息。
 | 
			
		||||
 */
 | 
			
		||||
export interface Stateful {
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目的状态信息。
 | 
			
		||||
   */
 | 
			
		||||
  state: string | boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于描述事物的修订版本信息的类型。
 | 
			
		||||
 */
 | 
			
		||||
export interface Revision extends Partial<ModificationRecords> {
 | 
			
		||||
  /**
 | 
			
		||||
   * 修订版本号。
 | 
			
		||||
   */
 | 
			
		||||
  revision: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在事物中记录当前活跃修订版本号以及可用的修订版本列表的类型。
 | 
			
		||||
 */
 | 
			
		||||
export interface Revisionary {
 | 
			
		||||
  /**
 | 
			
		||||
   * 当前活跃的修订版本。
 | 
			
		||||
   */
 | 
			
		||||
  revision: number;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 可用的全部修订版本列表。(可选)
 | 
			
		||||
   */
 | 
			
		||||
  revisions: Revision[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于记录条目的所有者信息。
 | 
			
		||||
 */
 | 
			
		||||
export type HasOwner = {
 | 
			
		||||
  [Property in keyof BaseContent as `owner${Capitalize<string & Property>}`]:
 | 
			
		||||
    | BaseContent[Property]
 | 
			
		||||
    | null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于记录条目中的简易行政区划描述信息。
 | 
			
		||||
 * 这里所给出的行政区划信息是多级行政区划合成以后的。
 | 
			
		||||
 */
 | 
			
		||||
export type SimpleAreaDescription = {
 | 
			
		||||
  [Property in keyof BaseContent as `area${Capitalize<string & Property>}`]:
 | 
			
		||||
    | BaseContent[Property]
 | 
			
		||||
    | null;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										178
									
								
								src/shared/model-components.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								src/shared/model-components.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 用于描述从后端传来的使用code承载内容编号,name承载内容名称的基本数据结构。
 | 
			
		||||
 */
 | 
			
		||||
export interface BaseContent {
 | 
			
		||||
  /**
 | 
			
		||||
   * 内容编号。
 | 
			
		||||
   */
 | 
			
		||||
  code: string;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 内容名称。
 | 
			
		||||
   */
 | 
			
		||||
  name: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于解析来自服务端的响应体基本内容,其他响应可直接继承和扩展本接口
 | 
			
		||||
 */
 | 
			
		||||
export interface BaseResponse {
 | 
			
		||||
  /**
 | 
			
		||||
   * 用于记录服务端处理状态码
 | 
			
		||||
   */
 | 
			
		||||
  code: number;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 用于记录服务端处理状态信息
 | 
			
		||||
   */
 | 
			
		||||
  message: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 向服务端查询数量的响应体。
 | 
			
		||||
 */
 | 
			
		||||
export interface AmountResponse extends BaseResponse {
 | 
			
		||||
  /**
 | 
			
		||||
   * 所查询的内容数量。
 | 
			
		||||
   */
 | 
			
		||||
  amount: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于记录条目修改时间以及修改人的记录。
 | 
			
		||||
 */
 | 
			
		||||
export interface ModificationRecords {
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目创建时间。
 | 
			
		||||
   */
 | 
			
		||||
  createdAt: Date | string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目创建人名称或代号。
 | 
			
		||||
   */
 | 
			
		||||
  createdBy: string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目修改时间。
 | 
			
		||||
   */
 | 
			
		||||
  modifiedAt: Date | string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目修改人名称或代号。
 | 
			
		||||
   */
 | 
			
		||||
  modifiedBy: string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目删除时间,如果未删除则为null,可以用于实现软删除。
 | 
			
		||||
   */
 | 
			
		||||
  deletedAt: Date | string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目删除人名称或代号。
 | 
			
		||||
   */
 | 
			
		||||
  deletedBy: string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目撤销时间,注意名词与删除和取消的区别。
 | 
			
		||||
   */
 | 
			
		||||
  revokedAt: Date | string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目撤销人名称或代号。
 | 
			
		||||
   */
 | 
			
		||||
  revokedBy: string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目取消时间,注意名词与删除和撤销的区别。
 | 
			
		||||
   */
 | 
			
		||||
  canceledAt: Date | string | number | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目取消人名称或代号。
 | 
			
		||||
   */
 | 
			
		||||
  canceledBy: string | number | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 定义解析分页内容所需要的响应参数。
 | 
			
		||||
 */
 | 
			
		||||
export interface Pageable {
 | 
			
		||||
  /**
 | 
			
		||||
   * 当前所返回的数据所在的页面。
 | 
			
		||||
   */
 | 
			
		||||
  current: number;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 当前所返回的数据每页条目数量。
 | 
			
		||||
   */
 | 
			
		||||
  pageSize: number;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 当前所有的页面总数。
 | 
			
		||||
   */
 | 
			
		||||
  total: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 定义可以支持模型数据进行排序的类型。
 | 
			
		||||
 */
 | 
			
		||||
export interface Sortable {
 | 
			
		||||
  /**
 | 
			
		||||
   * 排序字段。
 | 
			
		||||
   */
 | 
			
		||||
  sort: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 定义记录条目的字符串型状态信息。
 | 
			
		||||
 */
 | 
			
		||||
export interface Stateful {
 | 
			
		||||
  /**
 | 
			
		||||
   * 记录条目的状态信息。
 | 
			
		||||
   */
 | 
			
		||||
  state: string | boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于描述事物的修订版本信息的类型。
 | 
			
		||||
 */
 | 
			
		||||
export interface Revision extends Partial<ModificationRecords> {
 | 
			
		||||
  /**
 | 
			
		||||
   * 修订版本号。
 | 
			
		||||
   */
 | 
			
		||||
  revision: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在事物中记录当前活跃修订版本号以及可用的修订版本列表的类型。
 | 
			
		||||
 */
 | 
			
		||||
export interface Revisionary {
 | 
			
		||||
  /**
 | 
			
		||||
   * 当前活跃的修订版本。
 | 
			
		||||
   */
 | 
			
		||||
  revision: number;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 可用的全部修订版本列表。(可选)
 | 
			
		||||
   */
 | 
			
		||||
  revisions: Revision[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于记录条目的所有者信息。
 | 
			
		||||
 */
 | 
			
		||||
export type HasOwner = {
 | 
			
		||||
  [Property in keyof BaseContent as `owner${Capitalize<string & Property>}`]:
 | 
			
		||||
    | BaseContent[Property]
 | 
			
		||||
    | null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于记录条目中的简易行政区划描述信息。
 | 
			
		||||
 * 这里所给出的行政区划信息是多级行政区划合成以后的。
 | 
			
		||||
 */
 | 
			
		||||
export type SimpleAreaDescription = {
 | 
			
		||||
  [Property in keyof BaseContent as `area${Capitalize<string & Property>}`]:
 | 
			
		||||
    | BaseContent[Property]
 | 
			
		||||
    | null;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										139
									
								
								src/shared/model-flow.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								src/shared/model-flow.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,139 @@
 | 
			
		||||
import { ParkInfo, TenementInfo } from "./model-park";
 | 
			
		||||
import { BaseUserInfo } from "./model-user";
 | 
			
		||||
 | 
			
		||||
/** 审批流程列表每一项 */
 | 
			
		||||
export interface FlowListItem {
 | 
			
		||||
  /** 设置人姓名 */
 | 
			
		||||
  setUserName: string;
 | 
			
		||||
  /** 设置时间 */
 | 
			
		||||
  setTime: string;
 | 
			
		||||
  /** 流程id */
 | 
			
		||||
  id: string;
 | 
			
		||||
  /** 流程名字 */
 | 
			
		||||
  name: string;
 | 
			
		||||
  /** 审核层级 */
 | 
			
		||||
  tier: number;
 | 
			
		||||
  /** 是否启用 */
 | 
			
		||||
  enable: boolean;
 | 
			
		||||
  /** 修改时间 */
 | 
			
		||||
  updateTime: string;
 | 
			
		||||
  /** 需要审批的用户们 */
 | 
			
		||||
  users: string[],
 | 
			
		||||
  /** 是否通知全体 */
 | 
			
		||||
  all: boolean,
 | 
			
		||||
  /** 类型 0-退费 */
 | 
			
		||||
  type: number,
 | 
			
		||||
  index?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 新建审批流程表单数据 */
 | 
			
		||||
export interface  FlowForm {
 | 
			
		||||
  /** 流程id 0-退费 */
 | 
			
		||||
  type: 0
 | 
			
		||||
  /** 审核层级 */
 | 
			
		||||
  level: number;
 | 
			
		||||
  /** 审核用户列表 */
 | 
			
		||||
  users: string[];
 | 
			
		||||
  /** 是否通知所有人 */
 | 
			
		||||
  all: boolean,
 | 
			
		||||
  /** 是否启用 */
 | 
			
		||||
  enable: boolean
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 获取当前提交审批列表 */
 | 
			
		||||
export interface ApproveListItem {
 | 
			
		||||
  /** 发起时间 */
 | 
			
		||||
  applyTime: string
 | 
			
		||||
  /** 发起人 */
 | 
			
		||||
  applyUserName: string
 | 
			
		||||
  /** 发起人id */
 | 
			
		||||
  applyUserID: string
 | 
			
		||||
  /** 类型   (0-退费申请) */
 | 
			
		||||
  type: number
 | 
			
		||||
  /** 操作状态 0-待处理,1-同意,2-拒绝 */
 | 
			
		||||
  operateStatus: number
 | 
			
		||||
  /** 流程状态   (1-处理中,2-已完成,3-已退回) */
 | 
			
		||||
  flowStatus: number
 | 
			
		||||
  /** 审批id */
 | 
			
		||||
  id: string,
 | 
			
		||||
  /** 商户 */
 | 
			
		||||
  tenement: TenementInfo,
 | 
			
		||||
  /** 园区 */
 | 
			
		||||
  park: ParkInfo,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 获取当前提交审批列表参数 */
 | 
			
		||||
export interface ApproveListQuery {
 | 
			
		||||
  /** 商户id */
 | 
			
		||||
  tenement?: string
 | 
			
		||||
  /** 操作类型(0-退费申请) */
 | 
			
		||||
  type?: number
 | 
			
		||||
  /** 流程状态(1-处理中,2-已完成,3-已退回) */
 | 
			
		||||
  status?: number
 | 
			
		||||
  /** 页码 */
 | 
			
		||||
  page?: number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface FlowDetailList {
 | 
			
		||||
  /** 时间 */
 | 
			
		||||
  time: string,
 | 
			
		||||
  /** 操作人 */
 | 
			
		||||
  user: BaseUserInfo,
 | 
			
		||||
  /** 类型 0-已发起,1-同意,2-拒绝*/
 | 
			
		||||
  type: 0 | 1, 2,
 | 
			
		||||
  /** 审批意见 */
 | 
			
		||||
  reason: string,
 | 
			
		||||
  /** 操作内容 */
 | 
			
		||||
  content: string,
 | 
			
		||||
  index?: number,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 获取当前审批的详情 */
 | 
			
		||||
export interface FlowDetail {
 | 
			
		||||
  /** 商户全称 */
 | 
			
		||||
  fullName?: string
 | 
			
		||||
  /** 电表编号 */
 | 
			
		||||
  code?: string
 | 
			
		||||
  /** 账务余额 */
 | 
			
		||||
  balance?: number
 | 
			
		||||
  /** 退费金额 */
 | 
			
		||||
  amount?: number
 | 
			
		||||
  /** 上传附件 */
 | 
			
		||||
  fileList?: string[],
 | 
			
		||||
  /** 申请原因 */
 | 
			
		||||
  reason?: string,
 | 
			
		||||
  /**列表 */
 | 
			
		||||
  list?:FlowDetailList[];
 | 
			
		||||
  /** 商户 */
 | 
			
		||||
  tenement?: TenementInfo,
 | 
			
		||||
  /** 园区 */
 | 
			
		||||
  park?: ParkInfo,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DisposeFlow {
 | 
			
		||||
  /** 审批意见 */
 | 
			
		||||
  content: string,
 | 
			
		||||
  /** 操作 0-不同意,1-同意 */
 | 
			
		||||
  status: 0 | 1,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FlowSelectItem {
 | 
			
		||||
  label: string,
 | 
			
		||||
  value: number,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const flowList: FlowSelectItem[] = [
 | 
			
		||||
  { label: "退费", value: 0 }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
export const flowStatusList: FlowSelectItem[] = [
 | 
			
		||||
  { label: "处理中", value: 1 },
 | 
			
		||||
  { label: "已完成", value: 2 },
 | 
			
		||||
  { label: "已退费", value: 3 },
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
export const operateStatusList: FlowSelectItem[] = [
 | 
			
		||||
  { label: "待处理", value: 0 },
 | 
			
		||||
  { label: "同意", value: 1 },
 | 
			
		||||
  { label: "拒绝", value: 2 },
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										165
									
								
								src/shared/model-invoice.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								src/shared/model-invoice.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,165 @@
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 票据信息
 | 
			
		||||
 */
 | 
			
		||||
export interface InvoiceInfo {
 | 
			
		||||
  id: string,
 | 
			
		||||
  /** 开票金额,即价税合计 */
 | 
			
		||||
  amount: string;
 | 
			
		||||
  /** 开票时间,记录时间,格式:yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  issuedAt: string;
 | 
			
		||||
  /** 发票号码 */
 | 
			
		||||
  no: string;
 | 
			
		||||
  /** 税率 */
 | 
			
		||||
  taxRate: string;
 | 
			
		||||
  /** 计税方式,0:核算电费含税,1:核算电费未税 */
 | 
			
		||||
  taxMethod: TaxMethod;
 | 
			
		||||
  /** 商户ID */
 | 
			
		||||
  tenement: string;
 | 
			
		||||
  /** 抬头 */
 | 
			
		||||
  title: InvoiceTitle;
 | 
			
		||||
  /** 发票类型 */
 | 
			
		||||
  type: string;
 | 
			
		||||
  /** 开始时间 */
 | 
			
		||||
  periodStart: string,
 | 
			
		||||
  /** 结束时间 */
 | 
			
		||||
  periodEnd: string,
 | 
			
		||||
  /** 用电量 */
 | 
			
		||||
  quantity: number,
 | 
			
		||||
  /** 核算周期 */
 | 
			
		||||
  periodTime: periodTime[],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface periodTime {
 | 
			
		||||
  time: string,
 | 
			
		||||
  codes: string[],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const enum TaxMethod {
 | 
			
		||||
  Including,
 | 
			
		||||
  Excluding
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const enum PacketType {
 | 
			
		||||
  watch,
 | 
			
		||||
  cycle,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 发票抬头信息
 | 
			
		||||
 */
 | 
			
		||||
export interface InvoiceTitle {
 | 
			
		||||
  /** 开户账号 */
 | 
			
		||||
  account: null | string;
 | 
			
		||||
  /** 注册地址 */
 | 
			
		||||
  address: null | string;
 | 
			
		||||
  /** 开户行名称 */
 | 
			
		||||
  bank: null | string;
 | 
			
		||||
  /** 开票人 */
 | 
			
		||||
  name: string;
 | 
			
		||||
  /** 注册电话 */
 | 
			
		||||
  phone: null | string;
 | 
			
		||||
  /** 开票人社会统一信用代码 */
 | 
			
		||||
  usci: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 发票详情
 | 
			
		||||
 */
 | 
			
		||||
export interface InvoiceDetail extends InvoiceInfo {
 | 
			
		||||
  /** 发票货物清单 */
 | 
			
		||||
  cargos: {
 | 
			
		||||
    /** 货物名称 */
 | 
			
		||||
    name: string;
 | 
			
		||||
    /** 单价 */
 | 
			
		||||
    price: string;
 | 
			
		||||
    /** 数量 */
 | 
			
		||||
    quantity: string;
 | 
			
		||||
    /** 税额 */
 | 
			
		||||
    tax: string;
 | 
			
		||||
    /** 税率 */
 | 
			
		||||
    taxRate: string;
 | 
			
		||||
    /** 价税合计 */
 | 
			
		||||
    total: string;
 | 
			
		||||
    /** 单位 */
 | 
			
		||||
    unit: string;
 | 
			
		||||
  }[];
 | 
			
		||||
  /** 概述信息 */
 | 
			
		||||
  covers: {
 | 
			
		||||
    /** 核算电费总额 */
 | 
			
		||||
    fee: string;
 | 
			
		||||
    /** 核算周期结束,格式:yyyy-MM-dd */
 | 
			
		||||
    periodEnd: string;
 | 
			
		||||
    /** 核算周期起始,格式:yyyy-MM-dd */
 | 
			
		||||
    periodStart: string;
 | 
			
		||||
    /** 报表ID */
 | 
			
		||||
    report: string;
 | 
			
		||||
    /** 表号 */
 | 
			
		||||
    code: string
 | 
			
		||||
  }[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 指定商户的未开票信息
 | 
			
		||||
 */
 | 
			
		||||
export interface UninvoicedRecord {
 | 
			
		||||
  /** 电费 */
 | 
			
		||||
  fee: string;
 | 
			
		||||
  /** 核算结束日期,格式:yyyy-MM-dd */
 | 
			
		||||
  periodEnd: string;
 | 
			
		||||
  /** 核算开始日期,格式:yyyy-MM-dd */
 | 
			
		||||
  periodStart: string;
 | 
			
		||||
  /** 电量 */
 | 
			
		||||
  quantity: string;
 | 
			
		||||
  /** 报表ID */
 | 
			
		||||
  report: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 未开票的信息
 | 
			
		||||
*/
 | 
			
		||||
export interface UninvoiceData {
 | 
			
		||||
  /** 商户简称 */
 | 
			
		||||
  shortName: string;
 | 
			
		||||
  /** 商户全称 */
 | 
			
		||||
  fullName: string;
 | 
			
		||||
  /** 表计编号 */
 | 
			
		||||
  code: string;
 | 
			
		||||
  /** 单价 */
 | 
			
		||||
  price: number;
 | 
			
		||||
  /** 合计电费 */
 | 
			
		||||
  fee: number;
 | 
			
		||||
  /** 用电量 */
 | 
			
		||||
  quantity: number;
 | 
			
		||||
  /** 核算结束日期 */
 | 
			
		||||
  periodEnd: string;
 | 
			
		||||
  /** 核算开始日期 */
 | 
			
		||||
  periodStart: string;
 | 
			
		||||
  /** 报表ID */
 | 
			
		||||
  report: string;
 | 
			
		||||
  /** 商户id */
 | 
			
		||||
  tenementID: string;
 | 
			
		||||
  /** index */
 | 
			
		||||
  index: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface cover {
 | 
			
		||||
  code: string,
 | 
			
		||||
  tenementID: string,
 | 
			
		||||
  report: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface CreateInvoicePrimaryData {
 | 
			
		||||
  /** 商户id */
 | 
			
		||||
  tenementID: string
 | 
			
		||||
  /** 商户全称 */
 | 
			
		||||
  fullName: string;
 | 
			
		||||
  /** 报表id */
 | 
			
		||||
  // reportIDs: string[],
 | 
			
		||||
  /** 园区id */
 | 
			
		||||
  parkId: string,
 | 
			
		||||
  /** 表号列表 */
 | 
			
		||||
  covers: cover[]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										71
									
								
								src/shared/model-log.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/shared/model-log.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
export type Log = {
 | 
			
		||||
  /** 操作时间 */
 | 
			
		||||
  time: string,
 | 
			
		||||
  /** 操作账号 */
 | 
			
		||||
  username: string,
 | 
			
		||||
  /** 操作人姓名 */
 | 
			
		||||
  nickName: string,
 | 
			
		||||
  /** 操作类型(0-园区新建,1-删除,2-修改、3-停用,4-商户的新建,5-修改、6-迁出、7-表计的新建、8-修改,9-换表、10-绑定、11-解绑、 12-抄表记录的新建、13-修改,14-电费核算、15-发布、16-导出,17-账务的新增、18-余额查询、19-售电充值的新增、20-充正新增、21-商户退费、22-发票开具、23-新开发票、24-已开发票、25-录入发票号,26-权限设置:修改权限,27-子账号的创建、28-删除、29-修改。 */
 | 
			
		||||
  type: string,
 | 
			
		||||
  /** 操作内容 */
 | 
			
		||||
  content: string,
 | 
			
		||||
  /** 操作id */
 | 
			
		||||
  id: string,
 | 
			
		||||
}
 | 
			
		||||
export enum LogType {
 | 
			
		||||
  '新建园区',
 | 
			
		||||
  '删除园区',
 | 
			
		||||
  '修改园区',
 | 
			
		||||
  '启/停用园区',
 | 
			
		||||
  '新建商户',
 | 
			
		||||
  '修改商户',
 | 
			
		||||
  '迁出商户',
 | 
			
		||||
  '新建表计',
 | 
			
		||||
  '修改表计',
 | 
			
		||||
  '换表表计',
 | 
			
		||||
  '绑定表计',
 | 
			
		||||
  '解绑表计',
 | 
			
		||||
  '新建抄表记录',
 | 
			
		||||
  '修改抄表记录',
 | 
			
		||||
  '电费核算',
 | 
			
		||||
  '发布核算',
 | 
			
		||||
  '导出核算',
 | 
			
		||||
  '新增账务',
 | 
			
		||||
  '余额查询',
 | 
			
		||||
  '新增充值',
 | 
			
		||||
  '新增冲正',
 | 
			
		||||
  '商户退费',
 | 
			
		||||
  '发票开具',
 | 
			
		||||
  '新开发票',
 | 
			
		||||
  '已开发票',
 | 
			
		||||
  '录入发票号',
 | 
			
		||||
  '权限设置',
 | 
			
		||||
  '创建子账号',
 | 
			
		||||
  '删除子账号',
 | 
			
		||||
  '修改子账号',
 | 
			
		||||
  '绑定公摊表',
 | 
			
		||||
  "修改充值",
 | 
			
		||||
  "查看售电记录",
 | 
			
		||||
  "新增退补电量",
 | 
			
		||||
  "退补电量列表",
 | 
			
		||||
  "撤回发布账单",
 | 
			
		||||
  "余额导入",
 | 
			
		||||
  "报表查询",
 | 
			
		||||
  "新增流程",
 | 
			
		||||
  "编辑流程",
 | 
			
		||||
  "删除流程",
 | 
			
		||||
  "新增审批",
 | 
			
		||||
  "审批",
 | 
			
		||||
  "余额模板导出",
 | 
			
		||||
  "报表导出",
 | 
			
		||||
  "文件上传",
 | 
			
		||||
  "文件删除",
 | 
			
		||||
  "监管账号用户查询",
 | 
			
		||||
  "监管运维账号-创建监管账号",
 | 
			
		||||
  "监管运维账号-查询用户详细信息",
 | 
			
		||||
  "监管运维账号-修改用户状态",
 | 
			
		||||
  "监管运维账号-创建企业用户",
 | 
			
		||||
  "监管运维账号-搜索企业用户",
 | 
			
		||||
  "监管运维账号-更新用户凭据",
 | 
			
		||||
  "监管运维账号-企业用户服务期限延期处理",
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										348
									
								
								src/shared/model-park.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										348
									
								
								src/shared/model-park.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,348 @@
 | 
			
		||||
import type { BaseUserInfo } from './model-user';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 园区信息
 | 
			
		||||
 */
 | 
			
		||||
export type ParkInfo = SimpleParkInfo & {
 | 
			
		||||
  /** 条目创建时间,时间格式为 yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  createdAt: string;
 | 
			
		||||
  /** 条目删除时间,时间格式为 yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  deletedAt: null | string;
 | 
			
		||||
  /** 条目是否启用 */
 | 
			
		||||
  enabled: boolean;
 | 
			
		||||
  /** 发票税率,0-1的小数 */
 | 
			
		||||
  taxRate?: string;
 | 
			
		||||
  /** 基准核定线损率,0-1的小数 */
 | 
			
		||||
  normAuthorizedLoss?: string;
 | 
			
		||||
  /** 条目最后修改时间,时间格式为 yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  lastModifiedAt: null | string;
 | 
			
		||||
  /** 电价计算政策,0:园区平均电度电价,1:园区平均电价 */
 | 
			
		||||
  pricePolicy: PricePolicyType;
 | 
			
		||||
  /** 公摊电费分摊策略,0:不分摊,1:按电量分摊,2:按面积分摊 */
 | 
			
		||||
  publicDiluted: DilutedType;
 | 
			
		||||
  /** 线损电费分摊策略,0:不分摊,1:按电量分摊,2:按面积分摊 */
 | 
			
		||||
  lossDiluted: DilutedType;
 | 
			
		||||
  /** 基本电费分摊策略,0:不分摊,1:按电量分摊,2:按面积分摊 */
 | 
			
		||||
  basisDiluted: DilutedType;
 | 
			
		||||
  /** 调整电费分摊策略,0:不分摊,1:按电量分摊,2:按面积分摊 */
 | 
			
		||||
  adjustDiluted: DilutedType;
 | 
			
		||||
  voltageTransmissionPrice?: string,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 基础园区信息
 | 
			
		||||
 */
 | 
			
		||||
export interface SimpleParkInfo {
 | 
			
		||||
  /** 园区ID */
 | 
			
		||||
  id: string;
 | 
			
		||||
  /** 园区所属用户ID */
 | 
			
		||||
  userId: string;
 | 
			
		||||
  /** 园区名称 */
 | 
			
		||||
  name: string;
 | 
			
		||||
  /** 园区住户数量 */
 | 
			
		||||
  tenement: null | string;
 | 
			
		||||
  /** 园区面积 */
 | 
			
		||||
  area: null | string;
 | 
			
		||||
  /** 供电容量 */
 | 
			
		||||
  capacity: null | string;
 | 
			
		||||
  /** 用电分类,0:两部制,1:单一峰谷,2:单一单一 */
 | 
			
		||||
  category: ElectrCategory;
 | 
			
		||||
  /** 户表计量类型,0:非峰谷,1:峰谷 */
 | 
			
		||||
  meter04kvType: Meter04KvType;
 | 
			
		||||
  /** 园区所在行政区划 */
 | 
			
		||||
  region: null | string;
 | 
			
		||||
  /** 园区地址 */
 | 
			
		||||
  address: null | string;
 | 
			
		||||
  /** 园区联系人 */
 | 
			
		||||
  contact: null | string;
 | 
			
		||||
  /** 园区联系人电话 */
 | 
			
		||||
  phone: null | string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用电类别
 | 
			
		||||
 */
 | 
			
		||||
export const enum ElectrCategory {
 | 
			
		||||
  /** 两部制 */
 | 
			
		||||
  DoubleCompose,
 | 
			
		||||
  /** 单一峰谷 */
 | 
			
		||||
  PeakToValley,
 | 
			
		||||
  /** 单一电价 */
 | 
			
		||||
  Single
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 户表计量类型
 | 
			
		||||
 */
 | 
			
		||||
export const enum Meter04KvType {
 | 
			
		||||
  /** 非峰谷 */
 | 
			
		||||
  DisableValley,
 | 
			
		||||
  /** 峰谷 */
 | 
			
		||||
  Valley
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用户电价政策
 | 
			
		||||
 */
 | 
			
		||||
export const enum PricePolicyType {
 | 
			
		||||
  /** 平均电度电价 */
 | 
			
		||||
  Unit,
 | 
			
		||||
  /** 平均电价 */
 | 
			
		||||
  Avg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 分摊策略
 | 
			
		||||
 */
 | 
			
		||||
export const enum DilutedType {
 | 
			
		||||
  /** 不分摊 */
 | 
			
		||||
  NotDiluted,
 | 
			
		||||
  /** 按电量分摊 */
 | 
			
		||||
  QuantityDiluted,
 | 
			
		||||
  /** 按商铺面积分摊 */
 | 
			
		||||
  AreaDiluted
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 表计类型
 | 
			
		||||
 */
 | 
			
		||||
export const enum MeterType {
 | 
			
		||||
  /** 商户电表 */
 | 
			
		||||
  Tenement,
 | 
			
		||||
  /** 园区电表 */
 | 
			
		||||
  Park,
 | 
			
		||||
  /** 公摊电表 */
 | 
			
		||||
  Public
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 0.4Kv表计信息
 | 
			
		||||
 */
 | 
			
		||||
export interface Meter04KvInfo {
 | 
			
		||||
  tableKey?: string;
 | 
			
		||||
  /** 户址 */
 | 
			
		||||
  address: null | string;
 | 
			
		||||
  /** 表计表号 */
 | 
			
		||||
  code: string;
 | 
			
		||||
  /** 条目创建时间,时间格式为 yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  createdAt: string;
 | 
			
		||||
  /** 是否可用 */
 | 
			
		||||
  enabled: boolean;
 | 
			
		||||
  /** 条目最后修改时间,时间格式为 yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  lastModifiedAt: null | string;
 | 
			
		||||
  /** 所属园区ID */
 | 
			
		||||
  parkId: string;
 | 
			
		||||
  /** 表计倍率 */
 | 
			
		||||
  ratio: string;
 | 
			
		||||
  /** 抄表序号 */
 | 
			
		||||
  seq: number;
 | 
			
		||||
  /** 表计类型 */
 | 
			
		||||
  type: MeterType;
 | 
			
		||||
  /** 所辖面积 */
 | 
			
		||||
  area: number;
 | 
			
		||||
  /** 所在建筑 */
 | 
			
		||||
  building: number;
 | 
			
		||||
  /** 建筑名称 */
 | 
			
		||||
  buildingName: string;
 | 
			
		||||
  /** 停用日期 */
 | 
			
		||||
  downTime?: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 上传Excel后出现错误的信息
 | 
			
		||||
 */
 | 
			
		||||
export interface UploadExcelError {
 | 
			
		||||
  /** 出错的列号 */
 | 
			
		||||
  col: number;
 | 
			
		||||
  /** 出错信息 */
 | 
			
		||||
  error: string;
 | 
			
		||||
  /** 出错的行号 */
 | 
			
		||||
  row: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 物业附加费信息
 | 
			
		||||
 */
 | 
			
		||||
export interface MaintenanceInfo {
 | 
			
		||||
  /** 条目创建时间,时间格式为 yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  createdAt: string;
 | 
			
		||||
  /** 条目删除时间,时间格式为 yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  deletedAt: null | string;
 | 
			
		||||
  /** 条目是否启用 */
 | 
			
		||||
  enabled: boolean;
 | 
			
		||||
  /** 物业附加费所属年份 */
 | 
			
		||||
  period: string;
 | 
			
		||||
  /** 附加费数额,单位:元/年 */
 | 
			
		||||
  fee: string;
 | 
			
		||||
  /** 物业附加费记录ID */
 | 
			
		||||
  id: string;
 | 
			
		||||
  /** 条目最后修改时间,时间格式为 yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  lastModifiedAt: null | string;
 | 
			
		||||
  /** 备注 */
 | 
			
		||||
  memo: null | string;
 | 
			
		||||
  /** 费用项目名称 */
 | 
			
		||||
  name: string;
 | 
			
		||||
  /** 所属园区ID */
 | 
			
		||||
  parkId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 物业附加费列表条目信息 */
 | 
			
		||||
export interface MaintenanceSummary {
 | 
			
		||||
  /** 管理单位信息 */
 | 
			
		||||
  user: BaseUserInfo;
 | 
			
		||||
  /** 管理单位园区信息 */
 | 
			
		||||
  park: ParkInfo;
 | 
			
		||||
  /** 物业附加费所属年份 */
 | 
			
		||||
  period: string;
 | 
			
		||||
  /** 合计附加费数额,单位:元/年 */
 | 
			
		||||
  fee: string;
 | 
			
		||||
  /** 附加费单价, 单位:元/平米/年 */
 | 
			
		||||
  price: string;
 | 
			
		||||
  /** 附加费单价,单位:元/平米/季 */
 | 
			
		||||
  quarterPrice: string;
 | 
			
		||||
  /** 附加费单价, 单位:元/平米/半年 */
 | 
			
		||||
  semiAnnualPrice: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 园区建筑
 | 
			
		||||
 */
 | 
			
		||||
export interface ParkBuilding {
 | 
			
		||||
  // 是否启用
 | 
			
		||||
  enabled: boolean;
 | 
			
		||||
  // 建筑楼层数量
 | 
			
		||||
  floors: string;
 | 
			
		||||
  // 建筑ID
 | 
			
		||||
  id: string;
 | 
			
		||||
  // 建筑名称
 | 
			
		||||
  name: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 更换表计的表单
 | 
			
		||||
 */
 | 
			
		||||
export interface ExchangeFormData {
 | 
			
		||||
  /** 原表计读数 */
 | 
			
		||||
  oldReading: MeterReading;
 | 
			
		||||
  /** 新表计资料 */
 | 
			
		||||
  newMeter: {
 | 
			
		||||
    /** 表计编号 */
 | 
			
		||||
    code: string;
 | 
			
		||||
    /** 倍率 */
 | 
			
		||||
    ratio: string;
 | 
			
		||||
    /** 表计读数 */
 | 
			
		||||
    reading: MeterReading;
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 表计读数
 | 
			
		||||
 */
 | 
			
		||||
export interface MeterReading {
 | 
			
		||||
  /** 有功(尖峰),非峰谷表读数设为0 */
 | 
			
		||||
  critical: string;
 | 
			
		||||
  /** 有功(平),非峰谷表读数设为有功(总)的数值 */
 | 
			
		||||
  flat: string;
 | 
			
		||||
  /** 有功(峰),非峰谷表读数设为0 */
 | 
			
		||||
  peak: string;
 | 
			
		||||
  /** 有功(谷),非峰谷表读数设为0 */
 | 
			
		||||
  valley: string;
 | 
			
		||||
  /** 有功(总) */
 | 
			
		||||
  overall: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 公摊表计数据
 | 
			
		||||
 */
 | 
			
		||||
export interface MeterPooled extends Meter04KvInfo {
 | 
			
		||||
  /** 关联的子级表计 */
 | 
			
		||||
  bindedMeters: Meter04KvInfo[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 选择表计数据
 | 
			
		||||
 */
 | 
			
		||||
export interface MeterChoiceData {
 | 
			
		||||
  /** 表计地址 */
 | 
			
		||||
  address: string;
 | 
			
		||||
  /** 表计编号 */
 | 
			
		||||
  code: string;
 | 
			
		||||
  /** 标记所属园区ID */
 | 
			
		||||
  park: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 商户信息
 | 
			
		||||
 */
 | 
			
		||||
export interface TenementInfo {
 | 
			
		||||
  /** 联系地址 */
 | 
			
		||||
  address: string;
 | 
			
		||||
  /** 所在建筑ID */
 | 
			
		||||
  building: null | string;
 | 
			
		||||
  /** 所在建筑名称 */
 | 
			
		||||
  buildingName: null | string;
 | 
			
		||||
  /** 联系人姓名 */
 | 
			
		||||
  contact: null | string;
 | 
			
		||||
  /** 条目创建时间 */
 | 
			
		||||
  createdAt: string;
 | 
			
		||||
  /** 条目删除时间 */
 | 
			
		||||
  deletedAt: null | string;
 | 
			
		||||
  /** 全名 */
 | 
			
		||||
  fullName: string;
 | 
			
		||||
  /** 商户ID */
 | 
			
		||||
  id: string;
 | 
			
		||||
  /** 条目最后修改时间 */
 | 
			
		||||
  lastModifiedAt: null | string;
 | 
			
		||||
  /** 入住日期 */
 | 
			
		||||
  movedInAt: string;
 | 
			
		||||
  /** 迁出日期 */
 | 
			
		||||
  movedOutAt: null | string;
 | 
			
		||||
  /** 所在建筑层数 */
 | 
			
		||||
  onFloor: null | string;
 | 
			
		||||
  /** 联系电话,将作为主要关联电话使用 */
 | 
			
		||||
  phone: null | string;
 | 
			
		||||
  /** 简称 */
 | 
			
		||||
  shortName: null | string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MeterByTenement {
 | 
			
		||||
  /** 园区ID */
 | 
			
		||||
  parkId: string,
 | 
			
		||||
  /** 商户id */
 | 
			
		||||
  tenementId: string,
 | 
			
		||||
  /** 电表号 */
 | 
			
		||||
  meterId: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export const enum FeeType {
 | 
			
		||||
  HCBN,
 | 
			
		||||
  WY,
 | 
			
		||||
  WYDS
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const FeeTypeList = [
 | 
			
		||||
  { label: "华昌宝能收费", value: 0 },
 | 
			
		||||
  { label: "物业", value: 1 },
 | 
			
		||||
  { label: "物业代收", value: 2 },
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
export interface MeterBox {
 | 
			
		||||
  id ?: string,
 | 
			
		||||
  park?: string,
 | 
			
		||||
  building?: string,
 | 
			
		||||
  boxNo?: string,
 | 
			
		||||
  address?: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MeterBoxListItem {
 | 
			
		||||
  id: string,
 | 
			
		||||
  boxNo: string,
 | 
			
		||||
  park: ParkInfo,
 | 
			
		||||
  building: ParkBuilding,
 | 
			
		||||
  enabled: boolean,
 | 
			
		||||
  address: string,
 | 
			
		||||
  createdAt: string,
 | 
			
		||||
  lastModifiedAt: string,
 | 
			
		||||
  deletedAt: string,
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										469
									
								
								src/shared/model-publicity.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										469
									
								
								src/shared/model-publicity.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,469 @@
 | 
			
		||||
import type { ParkInfo, SimpleParkInfo } from '@/shared/model-park';
 | 
			
		||||
import type { BaseUserInfo } from '@/shared/model-user';
 | 
			
		||||
import type { Consumption } from '@/shared/model-calculate';
 | 
			
		||||
import { Meter04KvInfo, TenementInfo } from '@/shared/model-park';
 | 
			
		||||
import { ReportMeterUnit } from '@/shared/model-calculate';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 电费核算信息
 | 
			
		||||
 */
 | 
			
		||||
export interface BasePublicityInfo {
 | 
			
		||||
  report: SimpleReportInfo & ReportStatus & { number: string };
 | 
			
		||||
  park: SimpleParkInfo;
 | 
			
		||||
  user: BaseUserInfo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 电费核算报表
 | 
			
		||||
 */
 | 
			
		||||
export interface SimpleReportInfo {
 | 
			
		||||
  /** 报表Id */
 | 
			
		||||
  id: string;
 | 
			
		||||
  /** 最后一次申请撤回的时间,格式为 yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  lastWithdrawAppliedAt: string;
 | 
			
		||||
  /** 最后一次申请审核的时间,格式为 yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  lastWithdrawAuditAt: string;
 | 
			
		||||
  /** 所属园区Id */
 | 
			
		||||
  parkId: string;
 | 
			
		||||
  /** 核算起始日期,格式为 yyyy-MM-dd */
 | 
			
		||||
  periodBegin: string;
 | 
			
		||||
  /** 核算结束日期,格式为 yyyy-MM-dd */
 | 
			
		||||
  periodEnd: string;
 | 
			
		||||
  /** 是否已发布 */
 | 
			
		||||
  published: boolean;
 | 
			
		||||
  /** 发布时间 */
 | 
			
		||||
  publishedAt: string;
 | 
			
		||||
  /** 报表撤回状态 */
 | 
			
		||||
  withdraw: WithdrawState;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 电费核算报表状态
 | 
			
		||||
 */
 | 
			
		||||
export interface ReportStatus {
 | 
			
		||||
  status: ReportStatusType;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 电费核算状态
 | 
			
		||||
 */
 | 
			
		||||
export const enum ReportStatusType {
 | 
			
		||||
  /** 数据丢失 */
 | 
			
		||||
  Miss_Data,
 | 
			
		||||
  /** 数据缺陷 */
 | 
			
		||||
  Defects_Data,
 | 
			
		||||
  /** 计算错误 */
 | 
			
		||||
  Calculation_Data,
 | 
			
		||||
  /** 储存错误 */
 | 
			
		||||
  Storage_Data,
 | 
			
		||||
  /** 除数为0 */
 | 
			
		||||
  Divisor_Zero,
 | 
			
		||||
  /** 程序错误 */
 | 
			
		||||
  Program_Exception,
 | 
			
		||||
  /** 成功 */
 | 
			
		||||
  Success = 9,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export interface CalculateErrorMessage {
 | 
			
		||||
  /** 所属报表ID */
 | 
			
		||||
  reportId: string;
 | 
			
		||||
  /** 出现错误的电表ID */
 | 
			
		||||
  meterId: string;
 | 
			
		||||
  /** 商户id */
 | 
			
		||||
  ID: string;
 | 
			
		||||
  /** 商户全称 */
 | 
			
		||||
  fullName: string;
 | 
			
		||||
  /** 抄表时间 */
 | 
			
		||||
  readAt: string;
 | 
			
		||||
  /** 电表是否开启 */
 | 
			
		||||
  enabled: boolean;
 | 
			
		||||
  /** 备注 */
 | 
			
		||||
  remark: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 报表的撤回状态
 | 
			
		||||
 */
 | 
			
		||||
export const enum WithdrawState {
 | 
			
		||||
  /** 未撤回 */
 | 
			
		||||
  Default,
 | 
			
		||||
  /** 申请撤回中 */
 | 
			
		||||
  Withdrawing,
 | 
			
		||||
  /** 申请拒绝 */
 | 
			
		||||
  Refused,
 | 
			
		||||
  /** 申请批准 */
 | 
			
		||||
  Passed
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 园区核算概况
 | 
			
		||||
 */
 | 
			
		||||
export interface ParkSummary {
 | 
			
		||||
  /** 调整电费 */
 | 
			
		||||
  adjustFee: string;
 | 
			
		||||
  /** 总建筑面积 */
 | 
			
		||||
  area: string;
 | 
			
		||||
  /** 基本电费 */
 | 
			
		||||
  basicFee: string;
 | 
			
		||||
  /** 户表总电量,商户表计+物业表计,不含园区表计和公摊表计 */
 | 
			
		||||
  consumption: string;
 | 
			
		||||
  /** 线损电量 */
 | 
			
		||||
  loss: string;
 | 
			
		||||
  /** 线损率,取值为百分数 */
 | 
			
		||||
  lossRate: string;
 | 
			
		||||
  /** 总消耗电度 */
 | 
			
		||||
  overall: Consumption;
 | 
			
		||||
  /** 电度摊薄调整电费电价 */
 | 
			
		||||
  pooledAdjustFeeByAmount: string;
 | 
			
		||||
  /** 面积摊薄调整电费电价 */
 | 
			
		||||
  pooledAdjustFeeByArea: string;
 | 
			
		||||
  /** 电度摊薄基本电费电价 */
 | 
			
		||||
  pooledBasicFeeByAmount: string;
 | 
			
		||||
  /** 面积摊薄基本电费电价 */
 | 
			
		||||
  pooledBasicFeeByArea: string;
 | 
			
		||||
  /** 核算报表ID */
 | 
			
		||||
  reportId: string;
 | 
			
		||||
  /** 光伏发电电量 */
 | 
			
		||||
  generateAmount?: number,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 公摊表计电费情况
 | 
			
		||||
 */
 | 
			
		||||
export interface PublicPooled extends Meter04KvInfo {
 | 
			
		||||
  /** 接入系统时间,挂表 */
 | 
			
		||||
  attachedAt: string;
 | 
			
		||||
  /** 从系统移除时间,拆表 */
 | 
			
		||||
  detachedAt: null | string;
 | 
			
		||||
  /** 所在楼层 */
 | 
			
		||||
  onFloor: null | string;
 | 
			
		||||
  /** 总电量部分 */
 | 
			
		||||
  overall: Consumption;
 | 
			
		||||
  /** 摊薄方式,0:按电度摊薄,1:按面积摊薄 */
 | 
			
		||||
  poolMethod: PoolMethod;
 | 
			
		||||
  /** 表格rowkey标识 */
 | 
			
		||||
  tableRowKey: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 摊薄方式: 0:不分摊,1:按电度摊薄,2:按面积摊薄
 | 
			
		||||
 */
 | 
			
		||||
export const enum PoolMethod {
 | 
			
		||||
  No,
 | 
			
		||||
  Consumption,
 | 
			
		||||
  Area
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 商户电量电费信息
 | 
			
		||||
 */
 | 
			
		||||
export interface ReportTenement extends TenementInfo {
 | 
			
		||||
  consumption: string;
 | 
			
		||||
  fee: string;
 | 
			
		||||
  pooled: string;
 | 
			
		||||
  final: string;
 | 
			
		||||
  /** 类型,0-查看明细,1-电费账单 */
 | 
			
		||||
  type: 0 | 1;
 | 
			
		||||
  /** tabs的key */
 | 
			
		||||
  key: string;
 | 
			
		||||
  consumptionAmount: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 商户详情
 | 
			
		||||
 */
 | 
			
		||||
export interface ReportTenementDetail {
 | 
			
		||||
  park: SimpleParkInfo;
 | 
			
		||||
  tenement: TenementInfo;
 | 
			
		||||
  comprehensive: TenementComprehensiveDetail;
 | 
			
		||||
  meters: (Meter04KvInfo &
 | 
			
		||||
    PooledSumDetail &
 | 
			
		||||
    ReportMeterUnit & { /** 合计电费 */ finalTotal: string; loss: Consumption } & {
 | 
			
		||||
      /** 首次抄表时间 */
 | 
			
		||||
      currentTermReadings: string,
 | 
			
		||||
      /** 最近抄表时间 */
 | 
			
		||||
      lastTermReadings: string,
 | 
			
		||||
     }
 | 
			
		||||
    & {
 | 
			
		||||
    startNumber: number,
 | 
			
		||||
    endNumber: number,
 | 
			
		||||
    displayRatio: number,
 | 
			
		||||
    publicAmount: string,
 | 
			
		||||
    refundAmount: string,
 | 
			
		||||
  }
 | 
			
		||||
     )[];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  pooled: (Meter04KvInfo & ReportMeterUnit)[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 商户综合明细
 | 
			
		||||
 */
 | 
			
		||||
export type TenementComprehensiveDetail = PooledSumDetail & {
 | 
			
		||||
  /** 合计电度电量 */
 | 
			
		||||
  consumption: string;
 | 
			
		||||
  /** 合计电度电费 */
 | 
			
		||||
  fee: string;
 | 
			
		||||
  /** 电费均价 */
 | 
			
		||||
  price: string;
 | 
			
		||||
  /** 合计电费 */
 | 
			
		||||
  total: string;
 | 
			
		||||
  /** 核定线损部分 */
 | 
			
		||||
  loss: Consumption;
 | 
			
		||||
  /** 摊薄线损电费 */
 | 
			
		||||
  basicPooled: string;
 | 
			
		||||
  /** 公摊电费 */
 | 
			
		||||
  publicPooled: string;
 | 
			
		||||
  /** 摊薄调整电费 */
 | 
			
		||||
  adjustPooled: string;
 | 
			
		||||
  /** 摊薄线损电量 */
 | 
			
		||||
  lossAmount: string;
 | 
			
		||||
  /** 开始时间 */
 | 
			
		||||
  startDate: string;
 | 
			
		||||
  /** 结束时间 */
 | 
			
		||||
  endDate: string;
 | 
			
		||||
  /** 本期公摊电量 */
 | 
			
		||||
  publicAmount: number
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 摊薄合计项目
 | 
			
		||||
 */
 | 
			
		||||
export interface PooledSumDetail {
 | 
			
		||||
  /** 摊薄调整电费 */
 | 
			
		||||
  adjustPooled: string;
 | 
			
		||||
  /** 摊薄基本电费 */
 | 
			
		||||
  basicPooled: string;
 | 
			
		||||
  /** 摊薄线损电费 */
 | 
			
		||||
  lossPooled: string;
 | 
			
		||||
  /** 公摊电费 */
 | 
			
		||||
  publicPooled: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 公示报表详情
 | 
			
		||||
 */
 | 
			
		||||
export interface PublicityDetail {
 | 
			
		||||
  /** 报表所属用户的简易信息 */
 | 
			
		||||
  enterprise: BaseUserInfo;
 | 
			
		||||
  /** 报表关联园区信息 */
 | 
			
		||||
  park: ParkInfo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 终端用户部分全字段
 | 
			
		||||
 */
 | 
			
		||||
export interface PublicityEndUser {
 | 
			
		||||
  /** 地址 */
 | 
			
		||||
  address: null | string;
 | 
			
		||||
  /** 是否公用也被表计 */
 | 
			
		||||
  isPublicMeter: boolean;
 | 
			
		||||
  /** 电量(尖峰) */
 | 
			
		||||
  critical: string;
 | 
			
		||||
  /** 电费(尖峰) */
 | 
			
		||||
  criticalFee: string;
 | 
			
		||||
  /** 用户名称 */
 | 
			
		||||
  customerName: null | string;
 | 
			
		||||
  /** 配电物业费 */
 | 
			
		||||
  maintenance: string;
 | 
			
		||||
  /** 表号 */
 | 
			
		||||
  meterId: string;
 | 
			
		||||
  /** 电量(总) */
 | 
			
		||||
  overall: string;
 | 
			
		||||
  /** 电费均价 */
 | 
			
		||||
  overallPrice: string;
 | 
			
		||||
  /** 电费(总) */
 | 
			
		||||
  overallFee: string;
 | 
			
		||||
  /** 电量(峰) */
 | 
			
		||||
  peak: string;
 | 
			
		||||
  /** 电费(峰) */
 | 
			
		||||
  peakFee: string;
 | 
			
		||||
  /** 电量(谷) */
 | 
			
		||||
  valley: string;
 | 
			
		||||
  /** 电费(谷) */
 | 
			
		||||
  valleyFee: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 终端用户总计部分
 | 
			
		||||
 *
 | 
			
		||||
 * 终端用户部分
 | 
			
		||||
 */
 | 
			
		||||
export interface PublicityEndUserSum {
 | 
			
		||||
  /** 总电度电费 */
 | 
			
		||||
  consumptionFee: string;
 | 
			
		||||
  /** 尖峰电量 */
 | 
			
		||||
  critical: string;
 | 
			
		||||
  /** 尖峰电费 */
 | 
			
		||||
  criticalFee: string;
 | 
			
		||||
  /** 尖峰电价 */
 | 
			
		||||
  criticalPrice: string;
 | 
			
		||||
  /** 平电量 */
 | 
			
		||||
  flat: string;
 | 
			
		||||
  /** 平电费 */
 | 
			
		||||
  flatFee: string;
 | 
			
		||||
  /** 平电价 */
 | 
			
		||||
  flatPrice: string;
 | 
			
		||||
  /** 总电量 */
 | 
			
		||||
  overall: string;
 | 
			
		||||
  /** 电量均价 */
 | 
			
		||||
  overallPrice: string;
 | 
			
		||||
  /** 峰电量 */
 | 
			
		||||
  peak: string;
 | 
			
		||||
  /** 峰电费 */
 | 
			
		||||
  peakFee: string;
 | 
			
		||||
  /** 峰电价 */
 | 
			
		||||
  peakPrice: string;
 | 
			
		||||
  /** 谷电量 */
 | 
			
		||||
  valley: string;
 | 
			
		||||
  /** 谷电费 */
 | 
			
		||||
  valleyFee: string;
 | 
			
		||||
  /** 谷电价 */
 | 
			
		||||
  valleyPrice: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 损失总计
 | 
			
		||||
 *
 | 
			
		||||
 * 损失部分
 | 
			
		||||
 */
 | 
			
		||||
export interface PublicityLoss {
 | 
			
		||||
  /** 电度电费 */
 | 
			
		||||
  consumptionFee: string;
 | 
			
		||||
  /** 电价 */
 | 
			
		||||
  price: string;
 | 
			
		||||
  /** 占比 */
 | 
			
		||||
  proportion: string;
 | 
			
		||||
  /** 电量 */
 | 
			
		||||
  quantity: string;
 | 
			
		||||
  /** 核定电量 */
 | 
			
		||||
  authorizeQuantity: string;
 | 
			
		||||
  /** 核定电费 */
 | 
			
		||||
  authorizeConsumptionFee: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 调整电费部分
 | 
			
		||||
 */
 | 
			
		||||
export interface PublicityMaintenance {
 | 
			
		||||
  /** 基础电费 */
 | 
			
		||||
  basicFees: string;
 | 
			
		||||
  /** 调整电费 */
 | 
			
		||||
  adjustFee: string;
 | 
			
		||||
  /** 损失电费 */
 | 
			
		||||
  lossFee: string;
 | 
			
		||||
  /** 损失率 */
 | 
			
		||||
  lossProportion: string;
 | 
			
		||||
  /** 调整电费占比 */
 | 
			
		||||
  adjustProportion: string;
 | 
			
		||||
  /** 调整电费单价 */
 | 
			
		||||
  adjustPrice: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 其他应收合计
 | 
			
		||||
 *
 | 
			
		||||
 * 其他应收部分
 | 
			
		||||
 */
 | 
			
		||||
export interface PublicityOthers {
 | 
			
		||||
  /** 基础电费 */
 | 
			
		||||
  basicFees: string;
 | 
			
		||||
  /** 配电运行维护费 */
 | 
			
		||||
  maintenanceFee: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 公共总计
 | 
			
		||||
 *
 | 
			
		||||
 * 公共设施部分
 | 
			
		||||
 */
 | 
			
		||||
export interface PublicityCategoryOverall {
 | 
			
		||||
  /** 总电度电费 */
 | 
			
		||||
  consumptionFee: string;
 | 
			
		||||
  /** 尖峰电量 */
 | 
			
		||||
  critical: string;
 | 
			
		||||
  /** 尖峰电费 */
 | 
			
		||||
  criticalFee: string;
 | 
			
		||||
  /** 尖峰电价 */
 | 
			
		||||
  criticalPrice: string;
 | 
			
		||||
  /** 平电量 */
 | 
			
		||||
  flat: string;
 | 
			
		||||
  /** 平电费 */
 | 
			
		||||
  flatFee: string;
 | 
			
		||||
  /** 平电价 */
 | 
			
		||||
  flatPrice: string;
 | 
			
		||||
  /** 总电量 */
 | 
			
		||||
  overall: string;
 | 
			
		||||
  /** 总电费 */
 | 
			
		||||
  overallFee: string;
 | 
			
		||||
  /** 电量均价 */
 | 
			
		||||
  overallPrice: string;
 | 
			
		||||
  /** 峰电量 */
 | 
			
		||||
  peak: string;
 | 
			
		||||
  /** 峰电费 */
 | 
			
		||||
  peakFee: string;
 | 
			
		||||
  /** 峰电价 */
 | 
			
		||||
  peakPrice: string;
 | 
			
		||||
  /** 占比 */
 | 
			
		||||
  proportion: string;
 | 
			
		||||
  /** 谷电量 */
 | 
			
		||||
  valley: string;
 | 
			
		||||
  /** 谷电费 */
 | 
			
		||||
  valleyFee: string;
 | 
			
		||||
  /** 谷电价 */
 | 
			
		||||
  valleyPrice: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 终端用户指定时间区间内的调整费用统计 */
 | 
			
		||||
export interface PublicityEndUserPeriodStatistics {
 | 
			
		||||
  /** 用户名称 */
 | 
			
		||||
  customerName?: string;
 | 
			
		||||
  /** 户址 */
 | 
			
		||||
  address?: string;
 | 
			
		||||
  /** 表计编号 */
 | 
			
		||||
  meterId: string;
 | 
			
		||||
  /** 表计是否峰谷表计 */
 | 
			
		||||
  pvKind?: number;
 | 
			
		||||
  /** 表计是否公共设备表计 */
 | 
			
		||||
  isPublicMeter?: boolean;
 | 
			
		||||
  /** 总电量 */
 | 
			
		||||
  overall: string | null;
 | 
			
		||||
  /** 尖峰电量 */
 | 
			
		||||
  critical: string | null;
 | 
			
		||||
  /** 峰电量 */
 | 
			
		||||
  peak: string | null;
 | 
			
		||||
  /** 谷电量 */
 | 
			
		||||
  valley: string | null;
 | 
			
		||||
  /** 总电费 */
 | 
			
		||||
  overallFee: string | null;
 | 
			
		||||
  /** 尖峰电费 */
 | 
			
		||||
  criticalFee: string | null;
 | 
			
		||||
  /** 峰电费 */
 | 
			
		||||
  peakFee: string | null;
 | 
			
		||||
  /** 谷电费 */
 | 
			
		||||
  valleyFee: string | null;
 | 
			
		||||
  /** 调整费用 */
 | 
			
		||||
  adjustFee: string | null;
 | 
			
		||||
  /** 调整费用占比 */
 | 
			
		||||
  adjustProportion: string | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**获取报表核算的错误列表(如果没有返回的是空列表) */
 | 
			
		||||
export interface errorMessageItem {
 | 
			
		||||
  /** 错误信息备注 */
 | 
			
		||||
  remark: string;
 | 
			
		||||
  /** 商户id */
 | 
			
		||||
  id: string;
 | 
			
		||||
  /** 商户全称 */
 | 
			
		||||
  fullName: string;
 | 
			
		||||
  /** 抄表时间 */
 | 
			
		||||
  readAt: string;
 | 
			
		||||
  /** 表号 */
 | 
			
		||||
  code: string;
 | 
			
		||||
  /** 表是否启用 */
 | 
			
		||||
  enabled: string;
 | 
			
		||||
  /** 报表id */
 | 
			
		||||
  rid: string;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										75
									
								
								src/shared/model-reading.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/shared/model-reading.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
import {Meter04KvInfo, MeterReading, TenementInfo} from '@/shared/model-park';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 抄表记录
 | 
			
		||||
 */
 | 
			
		||||
export interface ReadingInfo extends Meter04KvInfo, MeterReading {
 | 
			
		||||
  /**
 | 
			
		||||
   * 抄表时间,时间格式为 yyyy-MM-dd HH:mm:ss
 | 
			
		||||
   */
 | 
			
		||||
  readAt: string;
 | 
			
		||||
  /**
 | 
			
		||||
   * 抄表时间戳,与readAt对应的时间戳,索引记录用
 | 
			
		||||
   */
 | 
			
		||||
  readAtTimestamp: string;
 | 
			
		||||
  /** 商户全名 */
 | 
			
		||||
  fullName: string;
 | 
			
		||||
  /** 商户联系人 */
 | 
			
		||||
  contact?: string;
 | 
			
		||||
  /** 商户电话 */
 | 
			
		||||
  phone?: string;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 退补电费列表
 | 
			
		||||
 */
 | 
			
		||||
export interface Refund {
 | 
			
		||||
  /**
 | 
			
		||||
   * 退补记录号
 | 
			
		||||
   */
 | 
			
		||||
  number: string;
 | 
			
		||||
  /**
 | 
			
		||||
   * 操作时间
 | 
			
		||||
   */
 | 
			
		||||
  operateTime: string;
 | 
			
		||||
  /** 商户 */
 | 
			
		||||
  tenement: TenementInfo,
 | 
			
		||||
  /** 表计 */
 | 
			
		||||
  meter?: Meter04KvInfo;
 | 
			
		||||
  /** 退补周期 */
 | 
			
		||||
  period?: string;
 | 
			
		||||
  /** 退补电量 */
 | 
			
		||||
  amount?: string;
 | 
			
		||||
  /** 备注 */
 | 
			
		||||
  remark?: string;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 退补电费新增参数
 | 
			
		||||
 */
 | 
			
		||||
export interface RefundForm {
 | 
			
		||||
  /** 商户id */
 | 
			
		||||
  tenementId: string,
 | 
			
		||||
  /** 表号 */
 | 
			
		||||
  meterId: string,
 | 
			
		||||
  /** 周期 */
 | 
			
		||||
  period: any,
 | 
			
		||||
  /** 退补电量 */
 | 
			
		||||
  overall: number,
 | 
			
		||||
  /** 备注 */
 | 
			
		||||
  remark?: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 退补电费修改参数
 | 
			
		||||
 */
 | 
			
		||||
export interface RefundUpdateForm {
 | 
			
		||||
  /** 记录id */
 | 
			
		||||
  id: string,
 | 
			
		||||
  /**  */
 | 
			
		||||
  meterId: string,
 | 
			
		||||
  /** 周期 */
 | 
			
		||||
  period: string,
 | 
			
		||||
  /** 退补电量 */
 | 
			
		||||
  overall: number,
 | 
			
		||||
  /** 备注 */
 | 
			
		||||
  remark?: string,
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								src/shared/model-sonaccount.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/shared/model-sonaccount.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
 | 
			
		||||
export interface privilege { identity: string, description: string };
 | 
			
		||||
 | 
			
		||||
export interface SonAccountItem {
 | 
			
		||||
    /**
 | 
			
		||||
     * 账号ID
 | 
			
		||||
    */
 | 
			
		||||
    sid: string,
 | 
			
		||||
    /**
 | 
			
		||||
     * 账号名
 | 
			
		||||
    */
 | 
			
		||||
    name: string,
 | 
			
		||||
    /**
 | 
			
		||||
     * 账号登录名
 | 
			
		||||
    */
 | 
			
		||||
    username: string,
 | 
			
		||||
    /**
 | 
			
		||||
     * 联系人姓名
 | 
			
		||||
    */
 | 
			
		||||
    contactName :string,
 | 
			
		||||
    /**
 | 
			
		||||
     * 联系人电话
 | 
			
		||||
    */
 | 
			
		||||
    contactPhone :string,
 | 
			
		||||
    /**
 | 
			
		||||
     * 拥有权限
 | 
			
		||||
     */
 | 
			
		||||
    privileges: privilege [],
 | 
			
		||||
    /**
 | 
			
		||||
     * 可用性
 | 
			
		||||
    */
 | 
			
		||||
    enabled: boolean,
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建时间
 | 
			
		||||
    */
 | 
			
		||||
    createdAt :string,
 | 
			
		||||
    /**
 | 
			
		||||
     * 修改时间
 | 
			
		||||
    */
 | 
			
		||||
    lastModifiedAt :string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export interface SubmitSonAccount {
 | 
			
		||||
   /**
 | 
			
		||||
     * 账号ID
 | 
			
		||||
    */
 | 
			
		||||
   sid: string,
 | 
			
		||||
   /**
 | 
			
		||||
    * 账号名
 | 
			
		||||
   */
 | 
			
		||||
   name: string,
 | 
			
		||||
   /**
 | 
			
		||||
    * 账号登录名
 | 
			
		||||
   */
 | 
			
		||||
   username: string,
 | 
			
		||||
   /**
 | 
			
		||||
    * 联系人姓名
 | 
			
		||||
   */
 | 
			
		||||
   contactName :string,
 | 
			
		||||
   /**
 | 
			
		||||
    * 联系人电话
 | 
			
		||||
   */
 | 
			
		||||
   contactPhone :string,
 | 
			
		||||
   /**
 | 
			
		||||
    * 拥有权限
 | 
			
		||||
    */
 | 
			
		||||
   privileges: string [],
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										155
									
								
								src/shared/model-statement.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								src/shared/model-statement.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
			
		||||
import {Meter04KvInfo, ParkInfo, TenementInfo} from "@/shared/model-park";
 | 
			
		||||
import {AccountingType, HappenWay} from "@/shared/model-accounting";
 | 
			
		||||
import {BaseUserInfo} from "@/shared/model-user";
 | 
			
		||||
/** 充值情况 **/
 | 
			
		||||
export interface RechargeStatement {
 | 
			
		||||
  /** 序号 **/
 | 
			
		||||
  index?: number,
 | 
			
		||||
  /** 园区 **/
 | 
			
		||||
  park: ParkInfo,
 | 
			
		||||
  /** 操作时间 **/
 | 
			
		||||
  operateTime?: number,
 | 
			
		||||
  /** 商户 **/
 | 
			
		||||
  tenement?: TenementInfo,
 | 
			
		||||
  /** 表计 **/
 | 
			
		||||
  meter?: Meter04KvInfo,
 | 
			
		||||
  /** 支付金额 **/
 | 
			
		||||
  money?: number,
 | 
			
		||||
  /** 付款方式 **/
 | 
			
		||||
  way?: AccountingType,
 | 
			
		||||
  /** 售电类型,0-充值,1-冲正,2-退费 **/
 | 
			
		||||
  type?: 0 | 1 | 2,
 | 
			
		||||
  /** 操作员 **/
 | 
			
		||||
  operateUser: BaseUserInfo
 | 
			
		||||
}
 | 
			
		||||
/** 用电情况 **/
 | 
			
		||||
export interface ElectricStatement {
 | 
			
		||||
  /** 序号 **/
 | 
			
		||||
  index?: number,
 | 
			
		||||
  /** 商户 **/
 | 
			
		||||
  tenement?: TenementInfo,
 | 
			
		||||
  /** 开始时间 **/
 | 
			
		||||
  startDate?: string,
 | 
			
		||||
  /** 结束时间 **/
 | 
			
		||||
  endDate?: string,
 | 
			
		||||
  /** 总电量 **/
 | 
			
		||||
  amount: number,
 | 
			
		||||
  /** 合计摊薄费用 **/
 | 
			
		||||
  pooledFee?: number,
 | 
			
		||||
  /** 合计公摊费用 **/
 | 
			
		||||
  publicFee?: number,
 | 
			
		||||
  /** 合计电费 **/
 | 
			
		||||
  amountFee?: number,
 | 
			
		||||
  /** 备注 **/
 | 
			
		||||
  remark: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 用电详细查询 **/
 | 
			
		||||
export interface ElectricDetailStatement {
 | 
			
		||||
  /** 序号 **/
 | 
			
		||||
  index?: number,
 | 
			
		||||
  /** 商户 **/
 | 
			
		||||
  tenement?: TenementInfo,
 | 
			
		||||
  /** 表计 **/
 | 
			
		||||
  meter?: Meter04KvInfo,
 | 
			
		||||
  /** 开始时间 **/
 | 
			
		||||
  startDate?: string,
 | 
			
		||||
  /** 结束时间 **/
 | 
			
		||||
  endDate?: string,
 | 
			
		||||
  /** 总电量 **/
 | 
			
		||||
  overallAmount: number,
 | 
			
		||||
  /** 电度电费 **/
 | 
			
		||||
  chargeFee?: number,
 | 
			
		||||
  /** 摊薄线损电量 **/
 | 
			
		||||
  lossAmount?: number,
 | 
			
		||||
  /** 摊薄调整电费 **/
 | 
			
		||||
  adjustPooled?: number,
 | 
			
		||||
  /** 公摊电费 **/
 | 
			
		||||
  publicPooled: number,
 | 
			
		||||
  /** 合计电费 **/
 | 
			
		||||
  finalAll: number,
 | 
			
		||||
  /** 备注 **/
 | 
			
		||||
  remark: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 账务记录查询 **/
 | 
			
		||||
export interface AccountingStatement {
 | 
			
		||||
  /** 序号 **/
 | 
			
		||||
  index?: number,
 | 
			
		||||
  /** 商户 **/
 | 
			
		||||
  tenement?: TenementInfo,
 | 
			
		||||
  /** 表计 **/
 | 
			
		||||
  meter?: Meter04KvInfo,
 | 
			
		||||
  /** 操作时间 **/
 | 
			
		||||
  operateDate?: string,
 | 
			
		||||
  /** 结束时间 **/
 | 
			
		||||
  type?: HappenWay,
 | 
			
		||||
  /** 上次余额 **/
 | 
			
		||||
  lastBalance: number,
 | 
			
		||||
  /** 金额 **/
 | 
			
		||||
  money?: number,
 | 
			
		||||
  /** 余额 **/
 | 
			
		||||
  balance?: number,
 | 
			
		||||
  /** 操作员 **/
 | 
			
		||||
  operateUser: BaseUserInfo
 | 
			
		||||
}
 | 
			
		||||
/** 发票记录 **/
 | 
			
		||||
export interface InvoiceStatement {
 | 
			
		||||
  /** 序号 **/
 | 
			
		||||
  index?: number,
 | 
			
		||||
  /** 商户 **/
 | 
			
		||||
  tenement?: TenementInfo,
 | 
			
		||||
  /** 表计 **/
 | 
			
		||||
  meter?: Meter04KvInfo,
 | 
			
		||||
  /** 初始金额 **/
 | 
			
		||||
  initMoney?: number,
 | 
			
		||||
  /** 累计充值金额 **/
 | 
			
		||||
  chargeMoney?: number,
 | 
			
		||||
  /** 已消耗金额 **/
 | 
			
		||||
  usedMoney: number,
 | 
			
		||||
  /** 已开票金额 **/
 | 
			
		||||
  invoiceMoney?: number,
 | 
			
		||||
  /** 开票后余额 **/
 | 
			
		||||
  invoiceBalance?: number,
 | 
			
		||||
  /** 备注 **/
 | 
			
		||||
  remark: string
 | 
			
		||||
}
 | 
			
		||||
/** 商户情况 **/
 | 
			
		||||
export interface TenementStatement extends TenementInfo{
 | 
			
		||||
  /** 序号 **/
 | 
			
		||||
  index?: number,
 | 
			
		||||
  /** 开票地址 **/
 | 
			
		||||
  invoiceAddress?: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DefaultQuery {
 | 
			
		||||
  /** 开始时间 **/
 | 
			
		||||
  startDate?: string,
 | 
			
		||||
  /** 结束时间 **/
 | 
			
		||||
  endDate?: string,
 | 
			
		||||
  /** 页数 **/
 | 
			
		||||
  page?: number,
 | 
			
		||||
  /** 园区 **/
 | 
			
		||||
  park?: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 报表类型
 | 
			
		||||
 */
 | 
			
		||||
// export const enum MeterType {
 | 
			
		||||
//   /** 充值查询 */
 | 
			
		||||
//   RechargeStatement,
 | 
			
		||||
//   /** 用电情况查询 */
 | 
			
		||||
//   ElectricStatement,
 | 
			
		||||
//   /** 用电详细查询 */
 | 
			
		||||
//   ElectricDetailStatement
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
export enum StatementType {
 | 
			
		||||
  "充值查询",
 | 
			
		||||
  "用电情况查询",
 | 
			
		||||
  "用电详细查询",
 | 
			
		||||
  "账务记录",
 | 
			
		||||
  "发票记录",
 | 
			
		||||
  "商户情况"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										85
									
								
								src/shared/model-sync.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/shared/model-sync.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
import { ParkInfo } from './model-park';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 同步任务
 | 
			
		||||
 */
 | 
			
		||||
export interface SyncTask {
 | 
			
		||||
  /** 同步任务ID */
 | 
			
		||||
  id: string;
 | 
			
		||||
  /** 归属企业ID */
 | 
			
		||||
  userId: string;
 | 
			
		||||
  /** parkID */
 | 
			
		||||
  parkId: string;
 | 
			
		||||
  /** 企业用户ID */
 | 
			
		||||
  entId: string;
 | 
			
		||||
  /** 企业名称 */
 | 
			
		||||
  entName: string;
 | 
			
		||||
  /** 上次运行时间,格式:yyyy-MM-dd HH:mm:ss。最后同步时间,这个时间不保证同步任务一定成功 */
 | 
			
		||||
  lastDispatchedAt?: string;
 | 
			
		||||
  /** 上次运行结果,0:同步中,1:同步成功,2:同步失败,3:等待中,4:已暂停 */
 | 
			
		||||
  lastDispatchStatus?: SyncTaskStatus;
 | 
			
		||||
  /** 下次运行时间,格式:yyyy-MM-dd HH:mm:ss */
 | 
			
		||||
  nextDispatchAt?: string;
 | 
			
		||||
  /** 园区名称 */
 | 
			
		||||
  parkName: string;
 | 
			
		||||
  /** 任务ID */
 | 
			
		||||
  taskId?: string;
 | 
			
		||||
  /** 任务名称 */
 | 
			
		||||
  taskName?: string;
 | 
			
		||||
  /** 状态 (0:队列中,1:执行中,2:成功,3:失败,4:取消) */
 | 
			
		||||
  status: number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 同步任务状态
 | 
			
		||||
 * 0:同步中,1:同步成功,2:同步失败,3:等待中,4:已暂停
 | 
			
		||||
 */
 | 
			
		||||
export const enum SyncTaskStatus {
 | 
			
		||||
  Synching,
 | 
			
		||||
  Success,
 | 
			
		||||
  Failure,
 | 
			
		||||
  Waiting,
 | 
			
		||||
  Pause
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 采集方式  0:自动+人工,1:自动,2:人工
 | 
			
		||||
 */
 | 
			
		||||
export const enum ReadingType {
 | 
			
		||||
  AutoManual,
 | 
			
		||||
  Auto,
 | 
			
		||||
  Manual
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 采集周期  0:每小时,1:每日,2:每周,3:每月
 | 
			
		||||
 */
 | 
			
		||||
export const enum ReadingInterval {
 | 
			
		||||
  Hour,
 | 
			
		||||
  Day,
 | 
			
		||||
  Week,
 | 
			
		||||
  Month
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 重试间隔方法  0:指数退避,1:2倍线性间隔,2:3倍线性间隔,3:固定间隔
 | 
			
		||||
 */
 | 
			
		||||
export const enum ReadingRetryAlgorithm {
 | 
			
		||||
  ExponentialBackOff,
 | 
			
		||||
  DoubleInterval,
 | 
			
		||||
  TripleInterval,
 | 
			
		||||
  FixedInterval
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 查看园区同步记录是否一致弹框列表
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export interface ParkSync {
 | 
			
		||||
  time: string,
 | 
			
		||||
  park: ParkInfo,
 | 
			
		||||
  ownNumber: number,
 | 
			
		||||
  targetNumber: number,
 | 
			
		||||
  isSame: number,
 | 
			
		||||
  id: string
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										73
									
								
								src/shared/model-user.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/shared/model-user.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 用户发起登录请求时,服务端返回的会话信息。
 | 
			
		||||
 */
 | 
			
		||||
export interface UserSession {
 | 
			
		||||
  /** 当前会话所属的用户ID。 */
 | 
			
		||||
  uid: string;
 | 
			
		||||
  /** 当前会话的用户名称或姓名。 */
 | 
			
		||||
  name: string;
 | 
			
		||||
  /** 用户类型,0:企业,1:监管,2:运维 */
 | 
			
		||||
  type: UserType;
 | 
			
		||||
  /** 代表当前会话的令牌。 */
 | 
			
		||||
  token: string;
 | 
			
		||||
  /** 当前会话的过期时间。 */
 | 
			
		||||
  expiresAt: string;
 | 
			
		||||
  /** 菜单权限 */
 | 
			
		||||
  menu: string[]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用户类型
 | 
			
		||||
 */
 | 
			
		||||
export const enum UserType {
 | 
			
		||||
  /** 企业 */
 | 
			
		||||
  Enterprise,
 | 
			
		||||
  /** 监管 */
 | 
			
		||||
  Regulatory,
 | 
			
		||||
  /** 运维 */
 | 
			
		||||
  Maintainer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 基本用户信息
 | 
			
		||||
 */
 | 
			
		||||
export interface BaseUserInfo {
 | 
			
		||||
  /** 用户联系人 */
 | 
			
		||||
  contact: null | string;
 | 
			
		||||
  /** 条目创建时间 */
 | 
			
		||||
  createdAt: string;
 | 
			
		||||
  /** 条目创建人,保存用户ID */
 | 
			
		||||
  createdBy: null | string;
 | 
			
		||||
  /** 条目是否启用 */
 | 
			
		||||
  enabled: boolean;
 | 
			
		||||
  /** 用户ID */
 | 
			
		||||
  id: string;
 | 
			
		||||
  /** 条目最后修改人,保存用户ID */
 | 
			
		||||
  lastModiedBy: null | string;
 | 
			
		||||
  /** 条目最后修改时间 */
 | 
			
		||||
  lastModifiedAt: null | string;
 | 
			
		||||
  /** 用户名称 */
 | 
			
		||||
  name: string;
 | 
			
		||||
  /** 用户联系人电话 */
 | 
			
		||||
  phone: null | string;
 | 
			
		||||
  /** 用户类型 */
 | 
			
		||||
  type: UserType;
 | 
			
		||||
  /** 用户账号 */
 | 
			
		||||
  username: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 完整用户信息
 | 
			
		||||
 */
 | 
			
		||||
export interface UserInfo extends BaseUserInfo {
 | 
			
		||||
  /** 月服务费 */
 | 
			
		||||
  unitServiceFee: number | null;
 | 
			
		||||
  /** 服务过期时间,格式为 YYYY-MM-dd */
 | 
			
		||||
  serviceExpiration: string;
 | 
			
		||||
  /** 用户所在行政区划 */
 | 
			
		||||
  region: null | string;
 | 
			
		||||
  /** 用户地址 */
 | 
			
		||||
  address: null | string;
 | 
			
		||||
  /** 用户名称的拼音缩写 */
 | 
			
		||||
  abbr: null | string;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								src/shared/props copy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/shared/props copy.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
import { Callback } from './foundation';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于向组件提供是否处于激活状态的配置。
 | 
			
		||||
 */
 | 
			
		||||
export interface ActivedProps {
 | 
			
		||||
  /**
 | 
			
		||||
   * 当前组件是否处于激活状态。
 | 
			
		||||
   */
 | 
			
		||||
  actived?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于抽屉以及对话框组件配置打开与关闭时的回调。
 | 
			
		||||
 * ! 如果回调函数需要接受参数,必须重载覆盖本接口中的方法。
 | 
			
		||||
 */
 | 
			
		||||
export interface CommonModalProps {
 | 
			
		||||
  /**
 | 
			
		||||
   * 执行打开时运行的回调。
 | 
			
		||||
   */
 | 
			
		||||
  onOpen?: Callback;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 执行关闭时运行的回调。
 | 
			
		||||
   */
 | 
			
		||||
  onClose?: Callback;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 执行打开前运行的回调。
 | 
			
		||||
   */
 | 
			
		||||
  onBeforeOpen?: Callback;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 执行打开后运行的回调。
 | 
			
		||||
   */
 | 
			
		||||
  onAfterOpen?: Callback;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 执行关闭前运行的回调。
 | 
			
		||||
   */
 | 
			
		||||
  onBeforeClose?: Callback;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 执行关闭后运行的回调。
 | 
			
		||||
   */
 | 
			
		||||
  onAfterClose?: Callback;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								src/shared/props.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/shared/props.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
import { Callback } from './foundation';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于向组件提供是否处于激活状态的配置。
 | 
			
		||||
 */
 | 
			
		||||
export interface ActivedProps {
 | 
			
		||||
  /**
 | 
			
		||||
   * 当前组件是否处于激活状态。
 | 
			
		||||
   */
 | 
			
		||||
  actived?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于抽屉以及对话框组件配置打开与关闭时的回调。
 | 
			
		||||
 * ! 如果回调函数需要接受参数,必须重载覆盖本接口中的方法。
 | 
			
		||||
 */
 | 
			
		||||
export interface CommonModalProps {
 | 
			
		||||
  /**
 | 
			
		||||
   * 执行打开时运行的回调。
 | 
			
		||||
   */
 | 
			
		||||
  onOpen?: Callback;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 执行关闭时运行的回调。
 | 
			
		||||
   */
 | 
			
		||||
  onClose?: Callback;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 执行打开前运行的回调。
 | 
			
		||||
   */
 | 
			
		||||
  onBeforeOpen?: Callback;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 执行打开后运行的回调。
 | 
			
		||||
   */
 | 
			
		||||
  onAfterOpen?: Callback;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 执行关闭前运行的回调。
 | 
			
		||||
   */
 | 
			
		||||
  onBeforeClose?: Callback;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 执行关闭后运行的回调。
 | 
			
		||||
   */
 | 
			
		||||
  onAfterClose?: Callback;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								src/shared/system copy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/shared/system copy.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
import { ItemType } from "antd/es/menu/hooks/useItems";
 | 
			
		||||
 | 
			
		||||
export type PrivilegedItemType = {
 | 
			
		||||
    any?: number[];
 | 
			
		||||
    all?: number[];
 | 
			
		||||
    link?: string;
 | 
			
		||||
    title?: string;
 | 
			
		||||
    specific?: string;
 | 
			
		||||
    children?: PrivilegedItemType[];
 | 
			
		||||
    label?: string,
 | 
			
		||||
    key?: string,
 | 
			
		||||
  } & ItemType;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export interface FileListItem {
 | 
			
		||||
  uid?: string,
 | 
			
		||||
  name?: string,
 | 
			
		||||
  status?: 'done' | 'uploading' | 'error' | 'removed',
 | 
			
		||||
  response?: string,
 | 
			
		||||
  linkProps?: string,
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								src/shared/system.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/shared/system.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
import { ItemType } from "antd/es/menu/hooks/useItems";
 | 
			
		||||
 | 
			
		||||
export type PrivilegedItemType = {
 | 
			
		||||
    any?: number[];
 | 
			
		||||
    all?: number[];
 | 
			
		||||
    link?: string;
 | 
			
		||||
    title?: string;
 | 
			
		||||
    specific?: string;
 | 
			
		||||
    children?: PrivilegedItemType[];
 | 
			
		||||
    label?: string,
 | 
			
		||||
    key?: string,
 | 
			
		||||
  } & ItemType;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export interface FileListItem {
 | 
			
		||||
  uid?: string,
 | 
			
		||||
  name?: string,
 | 
			
		||||
  status?: 'done' | 'uploading' | 'error' | 'removed',
 | 
			
		||||
  response?: string,
 | 
			
		||||
  linkProps?: string,
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								src/utils/asyncs.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/utils/asyncs.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
import { AxiosResponse } from 'axios';
 | 
			
		||||
import { lt, not } from 'ramda';
 | 
			
		||||
import { BaseResponse } from '@/shared/model-components';
 | 
			
		||||
import { alertError } from '.';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 对访问服务端产生的响应体进行解包处理,对于失败的访问抛出相应错误。
 | 
			
		||||
 * @param response Axios访问服务端产生的访问响应。
 | 
			
		||||
 * @returns 解包以后所需要的服务端返回的数据。
 | 
			
		||||
 */
 | 
			
		||||
export function unwrap<T extends BaseResponse>(response: AxiosResponse<T>): T {
 | 
			
		||||
  if (!response) {
 | 
			
		||||
    alertError('服务异常,请稍后重试')
 | 
			
		||||
    return null
 | 
			
		||||
  }
 | 
			
		||||
  if (not(lt(response.status, 300))) {
 | 
			
		||||
    // throw new NetworkError(response.status, response.data?.message || response.statusText);
 | 
			
		||||
  }
 | 
			
		||||
  return response.data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 服务端响应是否正常
 | 
			
		||||
 * @param result 响应结构
 | 
			
		||||
 */
 | 
			
		||||
export function isCorrectResult(result: BaseResponse) {
 | 
			
		||||
  return lt(result.code, 300);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4
									
								
								src/utils/defaultValues.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/utils/defaultValues.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 默认的表计读数
 | 
			
		||||
 */
 | 
			
		||||
export const defaultMeterReading = { critical: '0', peak: '0', flat: '0', valley: '0' };
 | 
			
		||||
							
								
								
									
										20
									
								
								src/utils/file.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/utils/file.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
export function isImage(ext: string): boolean {
 | 
			
		||||
    return ['.jpeg', '.jpg', '.png'].includes(ext)
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
export function isExcel(ext: string): boolean {
 | 
			
		||||
    return [".xls", ".xlsx"].includes(ext)
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
export function isPdf(ext: string) : boolean {
 | 
			
		||||
    return ".pdf" === ext
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
export function isWord(ext: string): boolean {
 | 
			
		||||
    return [".doc", ".docx"].includes(ext)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getExt(filename: string): string {
 | 
			
		||||
    const lastIndex = filename.lastIndexOf(".")
 | 
			
		||||
    return filename.slice(lastIndex)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										566
									
								
								src/utils/funcs.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										566
									
								
								src/utils/funcs.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,566 @@
 | 
			
		||||
//@ts-nocheck
 | 
			
		||||
import { Dirtyable, DirtyableValue } from '@/shared/foundation';
 | 
			
		||||
import { BaseResponse, Sortable } from '@/shared/model-components';
 | 
			
		||||
import BigNumber from 'bignumber.js';
 | 
			
		||||
import dayjs from 'dayjs';
 | 
			
		||||
import {
 | 
			
		||||
  addIndex,
 | 
			
		||||
  append,
 | 
			
		||||
  assoc,
 | 
			
		||||
  assocPath,
 | 
			
		||||
  clone,
 | 
			
		||||
  compose,
 | 
			
		||||
  curry,
 | 
			
		||||
  defaultTo,
 | 
			
		||||
  equals,
 | 
			
		||||
  includes,
 | 
			
		||||
  isEmpty,
 | 
			
		||||
  isNil,
 | 
			
		||||
  keys,
 | 
			
		||||
  lens,
 | 
			
		||||
  map,
 | 
			
		||||
  mergeLeft,
 | 
			
		||||
  mergeRight,
 | 
			
		||||
  not,
 | 
			
		||||
  or,
 | 
			
		||||
  path,
 | 
			
		||||
  pathEq,
 | 
			
		||||
  pathOr,
 | 
			
		||||
  prepend,
 | 
			
		||||
  prop,
 | 
			
		||||
  propEq,
 | 
			
		||||
  reduce,
 | 
			
		||||
  Reduced,
 | 
			
		||||
  set,
 | 
			
		||||
  split,
 | 
			
		||||
  subtract,
 | 
			
		||||
  view,
 | 
			
		||||
  __
 | 
			
		||||
} from 'ramda';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 一个空函数,可以执行,但是不会处理任何事情,主要用于占位
 | 
			
		||||
 */
 | 
			
		||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
 | 
			
		||||
export function noOp() {}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 判断给定的参数是否不是undefined和null。
 | 
			
		||||
 */
 | 
			
		||||
export const notNil = compose(not, isNil);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 判断给定的字段是否为空。
 | 
			
		||||
 */
 | 
			
		||||
export const propIsNil = curry(<T>(property, obj: T) => compose(isNil, prop(property))(obj));
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 判断给定的字段是否不为空。
 | 
			
		||||
 */
 | 
			
		||||
export const propNotNil = curry(<T>(property, obj: T) => compose(notNil, prop(property))(obj));
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 判断给定的参数是否不是含义上的空,例如空字符串、空列表等。
 | 
			
		||||
 */
 | 
			
		||||
export const notEmpty = compose(not, isEmpty);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 判断给定的两个参数是否不等。
 | 
			
		||||
 */
 | 
			
		||||
export const notEquals = curry(compose(not, equals));
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 判断对象中给定的属性是给定值之间是否不相等。
 | 
			
		||||
 */
 | 
			
		||||
export const notPropEq = curry(compose(not, propEq));
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 判断给定的值是否为null、未定义或者空白。
 | 
			
		||||
 * @param value 要判断是否可能为空或者空白的值
 | 
			
		||||
 * @returns 值的空白判断结果。
 | 
			
		||||
 */
 | 
			
		||||
export const isNilOrEmpty = <T>(value: T | null | undefined): boolean => or(isNil(value), isEmpty(value));
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 判断给定的值是否既不是null、未定义,也不是空白。
 | 
			
		||||
 */
 | 
			
		||||
export const norNilOrEmpty = compose(not, isNilOrEmpty);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于搭配map方法更改数组中对象的键名,或者可以直接使用`renameKeys({ oldKey: newKey })(obj)`的形式修改某一对象中的属性名。
 | 
			
		||||
 */
 | 
			
		||||
export const renameKeys = curry((keysMap: object, obj) =>
 | 
			
		||||
  reduce((acc, key) => assoc(keysMap[key] || key, prop(key, obj), acc), {}, keys(obj))
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于将对象中指定的键的内容中指定键的内容转换为普通数字表示。如果指定的键不是精确数据类型,那么将自动跳过。
 | 
			
		||||
 * @param includeKeys 指定需要转换的键。
 | 
			
		||||
 * @param obj 需要转换的对象。
 | 
			
		||||
 */
 | 
			
		||||
export const convertToNumber = curry(<T>(includeKeys: string[], obj: T) =>
 | 
			
		||||
  reduce(
 | 
			
		||||
    (acc: any, key: string | number | symbol) => {
 | 
			
		||||
      const value = prop(key, obj);
 | 
			
		||||
      return assoc(key, includes(key, includeKeys) ? new BigNumber(value).toNumber() : value, acc);
 | 
			
		||||
    },
 | 
			
		||||
    {},
 | 
			
		||||
    keys(obj)
 | 
			
		||||
  )
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于将对象中指定的键的内容转换为使用BigNumber的精确数字表示。如果指定时的键不是数字类型,那么将自动跳过。
 | 
			
		||||
 * @param includeKeys 指定需要转换的键。
 | 
			
		||||
 * @param obj 需要转换的对象。
 | 
			
		||||
 */
 | 
			
		||||
export const convertToPreciseness = curry(<T>(includeKeys: (string | number | symbol)[], obj: T) =>
 | 
			
		||||
  reduce(
 | 
			
		||||
    (acc: any, key: string | number | symbol) => {
 | 
			
		||||
      const value = prop(key, obj);
 | 
			
		||||
      return assoc(
 | 
			
		||||
        key,
 | 
			
		||||
        includes(key, includeKeys) && not(new BigNumber(value).isNaN()) ? new BigNumber(value) : value,
 | 
			
		||||
        acc
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
    {},
 | 
			
		||||
    keys(obj)
 | 
			
		||||
  )
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于定义用在`JSON.parse()`值进行转换的柯里化函数。
 | 
			
		||||
 * @param key 对象中的键
 | 
			
		||||
 * @param value 对象中的键对应的值
 | 
			
		||||
 * @param transformKeys 定义需要转换的键
 | 
			
		||||
 * @returns 执行转换的柯里化函数。
 | 
			
		||||
 */
 | 
			
		||||
const parseBigNumber = curry((key: string | number | symbol, value: any, transformKeys: (string | number | symbol)[]) =>
 | 
			
		||||
  includes(key, transformKeys) && not(new BigNumber(value).isNaN()) ? new BigNumber(value) : value
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在`JSON.parse()`方法中将指定的键值转换为使用BigNumber表示的精确数字的方法。
 | 
			
		||||
 * @param transformKeys 定义需要转换的键
 | 
			
		||||
 * @returns 用于进行BigNumber类型转换的函数。
 | 
			
		||||
 */
 | 
			
		||||
export const parseWithPreciseness = (transformKeys: (string | number | symbol)[]) =>
 | 
			
		||||
  parseBigNumber(__, __, transformKeys);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于定义用在`JSON.stringify()`值进行转换的柯里化函数。
 | 
			
		||||
 * @param key 对象中的键
 | 
			
		||||
 * @param value 对象中的键对应的值
 | 
			
		||||
 * @param  transformKeys 定义需要转换的键
 | 
			
		||||
 * @returns 执行转换的柯里化函数。
 | 
			
		||||
 */
 | 
			
		||||
const stringifyBigNumber = curry(
 | 
			
		||||
  (key: string | number | symbol, value: any, transformKeys: (string | number | symbol)[]) =>
 | 
			
		||||
    includes(key, transformKeys) ? new BigNumber(value).toNumber() : value
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在`JSON.stringify()`方法中将指定的键值转换为普通数字表示的方法。
 | 
			
		||||
 * @param transformKeys 定义需要转换的键
 | 
			
		||||
 * @returns 用于进行BigNumber类型转换的函数
 | 
			
		||||
 */
 | 
			
		||||
export const stringifyWithPreciseness = (transformKeys: (string | number | symbol)[]) =>
 | 
			
		||||
  stringifyBigNumber(__, __, transformKeys);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在组件中渲染输出带有计价单位的数字。
 | 
			
		||||
 * ! 之前用于适配Acro Design,待适配Ant Design。
 | 
			
		||||
 * @param col 表格组件所取得的列值
 | 
			
		||||
 * @param record 表格组件当前行所使用的数据原值
 | 
			
		||||
 * @returns 由数字与计价单位拼合起来的展示文字
 | 
			
		||||
 */
 | 
			
		||||
export const renderNumberWithUnit = (unit?: string) => (col: number | null | undefined, record: any) =>
 | 
			
		||||
  isNil(col) ? '-' : `${col} ${pathOr('', split('.', unit ?? 'chargeUnit'), record)}`;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 输出一个可空数字值,如果值为空,则返回-。
 | 
			
		||||
 * @param precision 输出数字的精度,默认精度为2。
 | 
			
		||||
 * @returns 可空数字的输出字符串
 | 
			
		||||
 */
 | 
			
		||||
export const renderNullableNumber =
 | 
			
		||||
  (precision = 2) =>
 | 
			
		||||
  (col: number | null, record: any) =>
 | 
			
		||||
    isNil(col) ? '-' : new BigNumber(col).toFixed(precision);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在组件中渲染输出带有货币单位的数字。
 | 
			
		||||
 * ! 之前用于适配Acro Design,待适配Ant Design。
 | 
			
		||||
 * @param currency 要使用的货币符号
 | 
			
		||||
 * @param precision 展示使用的数字精度
 | 
			
		||||
 * @returns 由货币符号和货币金额组合起来的展示文字生成函数
 | 
			
		||||
 */
 | 
			
		||||
export const renderCurrency =
 | 
			
		||||
  (currency: string, precision = 2) =>
 | 
			
		||||
  (col: number, record?: any) =>
 | 
			
		||||
    isNil(col) ? '-' : `${currency}${new BigNumber(col).toFixed(precision)}`;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 输出带有货币单位的数字。
 | 
			
		||||
 * @param amount 货币金额
 | 
			
		||||
 * @param currency 货币符号
 | 
			
		||||
 * @param precision 货币精度,小数点位数
 | 
			
		||||
 * @param groupped 是否按千位分组
 | 
			
		||||
 * @returns 由货币符号和货币金额组合起来的展示文字
 | 
			
		||||
 */
 | 
			
		||||
export const renderGroupedCurrency = (
 | 
			
		||||
  amount: number | null,
 | 
			
		||||
  currency: string,
 | 
			
		||||
  precision = 2,
 | 
			
		||||
  groupped = true
 | 
			
		||||
): string => {
 | 
			
		||||
  const precisedAmount = new BigNumber(amount ?? 0);
 | 
			
		||||
  const fmt = {
 | 
			
		||||
    prefix: `${currency} `,
 | 
			
		||||
    decimalSeparator: '.'
 | 
			
		||||
  };
 | 
			
		||||
  const grouppedFmt = mergeRight(fmt, { groupSeparator: ',', groupSize: 3 });
 | 
			
		||||
  return isNil(amount)
 | 
			
		||||
    ? '-'
 | 
			
		||||
    : groupped
 | 
			
		||||
    ? precisedAmount.toFormat(precision, grouppedFmt)
 | 
			
		||||
    : precisedAmount.toFormat(precision, fmt);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于在组件中渲染输出指定精确度百分比的数字。
 | 
			
		||||
 * ! 之前用于适配Acro Design,待适配Ant Design。
 | 
			
		||||
 * @returns 由指定精确度百分比和百分号组合起来的展示文字
 | 
			
		||||
 */
 | 
			
		||||
export const renderPercent =
 | 
			
		||||
  (presicision = 2) =>
 | 
			
		||||
  (col: number, _?: unknown) =>
 | 
			
		||||
    isNil(col) ? '-' : `${new BigNumber(col).times(100).toFixed(presicision)} %`;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 对从服务端获取到的响应数据进行错误提示输出。
 | 
			
		||||
 * @param tag 错误输出的标签信息
 | 
			
		||||
 * @param response 从服务端获取到的响应数据
 | 
			
		||||
 * @param error 可能伴随存在的错误。
 | 
			
		||||
 */
 | 
			
		||||
export const logError = (tag: string, response: BaseResponse, error?: Error) => {
 | 
			
		||||
  console.error(`交互时异常[${tag}]:`, response.code, response.message);
 | 
			
		||||
  if (notNil(error)) {
 | 
			
		||||
    console.error(error);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 对系统在运行过程中出现的异常进行错误提示输出。
 | 
			
		||||
 * @param tag 错误输出的标签信息。
 | 
			
		||||
 * @param error 可能伴随存在的错误。
 | 
			
		||||
 */
 | 
			
		||||
export const logException = (tag: string, error?: any) => {
 | 
			
		||||
  console.error(`运行时异常[${tag}]: `, notNil(error) ? errorMessage(error) : '未知错误');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于从携带有错误信息的错误对象实例中获取错误文字描述信息。
 | 
			
		||||
 * @param error 错误对象实例
 | 
			
		||||
 * @returns 错误文字描述信息
 | 
			
		||||
 */
 | 
			
		||||
export const errorMessage = prop<'message', string>('message');
 | 
			
		||||
 | 
			
		||||
type ResponseTransformer<T extends BaseResponse> = (response: string) => T;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于对从服务端返回的响应数据结构进行变形处理,主要用于生成一个用于变形处理的函数。
 | 
			
		||||
 *
 | 
			
		||||
 * * 用于存储变形数据的键是不可以改名的。
 | 
			
		||||
 *
 | 
			
		||||
 * @param nameMap 用于在改变数据结构时,键名称的替换。
 | 
			
		||||
 * @param extractKeys 用于提取存储变形数据的键。
 | 
			
		||||
 * @param collection 需要变形的数据是否是一个集合。
 | 
			
		||||
 * @returns 返回一个用于变形处理的函数。
 | 
			
		||||
 */
 | 
			
		||||
export const responseTransformer: <T extends BaseResponse>(
 | 
			
		||||
  nameMap: Record<string, string>,
 | 
			
		||||
  extractKeys: string[],
 | 
			
		||||
  collection: boolean
 | 
			
		||||
) => ResponseTransformer<T> = (
 | 
			
		||||
  nameMap: Record<string, string>,
 | 
			
		||||
  extractKeys: string[],
 | 
			
		||||
  collection: boolean
 | 
			
		||||
): ResponseTransformer<T> => {
 | 
			
		||||
  return (response: string) => {
 | 
			
		||||
    const data = JSON.parse(response);
 | 
			
		||||
    const baseResponse = {
 | 
			
		||||
      code: prop('code', data),
 | 
			
		||||
      message: prop('message', data)
 | 
			
		||||
    };
 | 
			
		||||
    const transformedResult = reduce(
 | 
			
		||||
      (acc, elem) => {
 | 
			
		||||
        const result = collection
 | 
			
		||||
          ? map(renameKeys(nameMap, __), prop(elem, data) ?? [])
 | 
			
		||||
          : renameKeys(nameMap, prop(elem, data) ?? {});
 | 
			
		||||
        return { ...acc, [elem]: result };
 | 
			
		||||
      },
 | 
			
		||||
      {},
 | 
			
		||||
      extractKeys
 | 
			
		||||
    );
 | 
			
		||||
    return mergeRight(baseResponse, transformedResult);
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于将一个对象转换成其中的每个字段都使用可脏数据类型包装的对象,所有字段默认都是不脏的。
 | 
			
		||||
 * @param original 原始对象
 | 
			
		||||
 * @returns 转换后的可脏对象
 | 
			
		||||
 */
 | 
			
		||||
export const convertToDirtyable = <T extends object>(original: T): Dirtyable<T> => {
 | 
			
		||||
  return reduce(
 | 
			
		||||
    (acc, elem) =>
 | 
			
		||||
      mergeRight({ [elem]: { value: prop(elem, original), lastValue: prop(elem, original), dirty: false } }, acc),
 | 
			
		||||
    {},
 | 
			
		||||
    keys(original)
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于对两个日期对象进行比较,返回可以被比较函数使用的数字值。
 | 
			
		||||
 * @param date1 第一个日期对象
 | 
			
		||||
 * @param date2 第二个日期对象
 | 
			
		||||
 * @returns 两个日期的比较结果
 | 
			
		||||
 */
 | 
			
		||||
export const compareDate = (date1: Date, date2: Date) => {
 | 
			
		||||
  const date1Time = dayjs(date1);
 | 
			
		||||
  const date2Time = dayjs(date2);
 | 
			
		||||
  return date1Time.isBefore(date2Time) ? -1 : date1Time.isAfter(date2Time) ? 1 : 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 翻译税模式的值到税模式的文字描述。
 | 
			
		||||
 * @param mode 税模式的值
 | 
			
		||||
 * @returns 税模式的文字描述
 | 
			
		||||
 */
 | 
			
		||||
export const translateTaxMode = (mode: string): string => {
 | 
			
		||||
  return defaultTo('未知', { '0': '未税', '1': '含税' }[mode]);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 生成聚焦可脏对象中某个可脏属性的聚焦函数。
 | 
			
		||||
 * @param property 要聚焦的可脏对象中的属性名。
 | 
			
		||||
 * @returns 分别用于聚焦可脏对象中的三个属性的聚焦函数
 | 
			
		||||
 */
 | 
			
		||||
export const lensDirtyable = (property: string) => {
 | 
			
		||||
  return [
 | 
			
		||||
    lens(path([property, 'value']), assocPath([property, 'value'])),
 | 
			
		||||
    lens(path([property, 'dirty']), assocPath([property, 'dirty'])),
 | 
			
		||||
    lens(path([property, 'lastValue']), assocPath([property, 'lastValue']))
 | 
			
		||||
  ];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于直接更改一个可脏类型(通常是基础类型)的值,原有值将自动被赋予新可脏实例的lastValue属性,同时整个可脏对象变为脏对象。
 | 
			
		||||
 * * 将会直接返回一个可脏对象的新实例。
 | 
			
		||||
 * @param value 可脏类型的的新值。
 | 
			
		||||
 * @param origin 可脏类型对象的原始实例。
 | 
			
		||||
 * @returns 所携带的值已经被更新的可脏对象的新实例。
 | 
			
		||||
 */
 | 
			
		||||
export const setDirtyableValue = <T>(value: T, origin: DirtyableValue<T>): DirtyableValue<T> => {
 | 
			
		||||
  return {
 | 
			
		||||
    dirty: true,
 | 
			
		||||
    lastValue: origin.value,
 | 
			
		||||
    value
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 直接更新一个可脏对象中的某个属性的值,将自动将属性的原有值赋予lastValue记录,同时整个对象变为脏对象。
 | 
			
		||||
 * * 将会直接返回一个可脏对象的新实例。
 | 
			
		||||
 * @param property 要修改的属性名称。
 | 
			
		||||
 * @param value 指定属性的新值。
 | 
			
		||||
 * @param origin 可脏对象的原始实例。
 | 
			
		||||
 * @returns 可脏对象被修改以后的新的已脏实例。
 | 
			
		||||
 */
 | 
			
		||||
export const setDirtyableProperty = <T>(property: string, value: unknown, origin: Dirtyable<T>): Dirtyable<T> => {
 | 
			
		||||
  const [lensValue, lensDirty, lensLastValue] = lensDirtyable(property);
 | 
			
		||||
  let newObj = set(lensDirty, true, origin);
 | 
			
		||||
  newObj = set(lensLastValue, view(lensValue, origin), newObj);
 | 
			
		||||
  newObj = set(lensValue, value, newObj);
 | 
			
		||||
  return newObj;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 检测指定的可脏对象是否包含脏属性。
 | 
			
		||||
 * @param dirtyable 要检测的可脏对象。
 | 
			
		||||
 * @param properties 可选,如果设置了该参数,则只检查该参数指定的属性是否脏。
 | 
			
		||||
 * @returns 给定的可脏对象是否包含脏属性。
 | 
			
		||||
 */
 | 
			
		||||
export const isDirtied = <T>(dirtyable: Dirtyable<T>, properties?: string[]): boolean => {
 | 
			
		||||
  return reduce(
 | 
			
		||||
    (acc, e) => acc || pathEq([e, 'dirty'], true, dirtyable),
 | 
			
		||||
    false,
 | 
			
		||||
    isNil(properties) ? keys(dirtyable) : properties
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 进行一个预判断的右向合并操作,如果给定的条件不成立,那么将不执行合并,直接返回a对象的克隆;
 | 
			
		||||
 * 如果给定的条件成立,那么将会将b对象合并进入a对象中。
 | 
			
		||||
 * @param predicate 是否执行合并的判断条件。其中可以接受的第一个参数是合并的对象,第二个参数是基底对象。
 | 
			
		||||
 * @param a 用于合并的基底对象。
 | 
			
		||||
 * @param b 用于合并的新对象,将会覆盖基底对象中相同的键。
 | 
			
		||||
 * @returns 完成合并的新对象,或者原始的基底对象的克隆。
 | 
			
		||||
 */
 | 
			
		||||
export const mergeRightBy = <T>(
 | 
			
		||||
  predicate: (origin?: Partial<T>, target?: Partial<T>) => boolean,
 | 
			
		||||
  a: Partial<T>,
 | 
			
		||||
  b: Partial<T>
 | 
			
		||||
): Partial<T> => {
 | 
			
		||||
  if (predicate(b, a)) {
 | 
			
		||||
    return mergeRight(a, b);
 | 
			
		||||
  } else {
 | 
			
		||||
    return clone(a);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 进行一个预判断的左向合并操作,如果给定的条件不成立,那么将不执行合并,直接返回b对象的克隆;
 | 
			
		||||
 * 如果给定的条件成立,那么将会将a对象合并进入b对象中。
 | 
			
		||||
 * @param predicate 是否执行合并的判断条件。其中可以接受的第一个参数是合并的对象,第二个参数是基底对象。
 | 
			
		||||
 * @param a 用于合并的对象,将会覆盖基底对象中相同的键。
 | 
			
		||||
 * @param b 用于合并的基底对象。
 | 
			
		||||
 * @returns 完成合并的新对象,或者是原始的基底对象的克隆。
 | 
			
		||||
 */
 | 
			
		||||
export const mergeLeftBy = <T>(
 | 
			
		||||
  predicate: (origin?: Partial<T>, target?: Partial<T>) => boolean,
 | 
			
		||||
  a: Partial<T>,
 | 
			
		||||
  b: Partial<T>
 | 
			
		||||
): Partial<T> => {
 | 
			
		||||
  if (predicate(a, b)) {
 | 
			
		||||
    return mergeLeft(a, b);
 | 
			
		||||
  } else {
 | 
			
		||||
    return clone(b);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 进行一个预判断的列表追加操作,如果给定的条件不成立,那么将不执行追加,直接返回原列表的克隆;
 | 
			
		||||
 * 如果给定的条件成立,那么将会将a对象追加进入列表b中,并返回追加后列表的新实例。
 | 
			
		||||
 * @param predicate 是否执行追加的判断条件,其中可以接受的第一个参数是即将被追加的元素本身,第二个参数是列表本身。
 | 
			
		||||
 * @param a 用于追加到列表中的元素。
 | 
			
		||||
 * @param b 用于存放数据的列表。
 | 
			
		||||
 * @returns 完成追加的新列表对象或者原始列表对象的克隆。
 | 
			
		||||
 */
 | 
			
		||||
export const appendBy = <T>(
 | 
			
		||||
  predicate: (origin?: Partial<T>, target?: Partial<T>[]) => boolean,
 | 
			
		||||
  a: Partial<T>,
 | 
			
		||||
  b: Partial<T>[]
 | 
			
		||||
): Partial<T>[] => {
 | 
			
		||||
  if (predicate(a, b)) {
 | 
			
		||||
    return append(a, b);
 | 
			
		||||
  } else {
 | 
			
		||||
    return clone(b);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 进行一个预判断的列表头部添加操作,如果给定的条件不成立,那么将不执行添加,直接返回原列表的克隆;
 | 
			
		||||
 * 如果给定的条件成立,那么将会将a对象添加进入列表b的头部,并返回添加后列表的新实例。
 | 
			
		||||
 * @param predicate 是否执行添加的判断条件,其中可以接受的第一个参数是即将被添加的元素本身,第二个参数是列表本身。
 | 
			
		||||
 * @param a 用于添加到列表中的元素。
 | 
			
		||||
 * @param b 用于存放数据的列表。
 | 
			
		||||
 * @returns 完成添加的新列表对象或者原始列表对象的克隆。
 | 
			
		||||
 */
 | 
			
		||||
export const prependBy = <T>(
 | 
			
		||||
  predicate: (origin?: Partial<T>, target?: Partial<T>[]) => boolean,
 | 
			
		||||
  a: Partial<T>,
 | 
			
		||||
  b: Partial<T>[]
 | 
			
		||||
): Partial<T>[] => {
 | 
			
		||||
  if (predicate(a, b)) {
 | 
			
		||||
    return prepend(a, b);
 | 
			
		||||
  } else {
 | 
			
		||||
    return clone(b);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 确认对象中指定键的值是否包含在可取值列表中。
 | 
			
		||||
 * @param a 指定用于筛选的对象的键。
 | 
			
		||||
 * @param b 指定对象的键可取值列表。
 | 
			
		||||
 * @returns 对象是否符合包含条件。
 | 
			
		||||
 */
 | 
			
		||||
export const includeByProp = <T, P extends keyof T>(a: P, b: T[P][]): boolean =>
 | 
			
		||||
  compose<T, boolean>(includes<T[P]>(__, b), prop<T>(a));
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 确认对象中指定键的值是否不包含在指定值的列表中。
 | 
			
		||||
 * @param a 指定用于筛选对象的键。
 | 
			
		||||
 * @param b 指定对象键的不可取值列表。
 | 
			
		||||
 * @returns 对象是被不符合包含条件。
 | 
			
		||||
 */
 | 
			
		||||
export const notIncludeByProp = <T, P extends keyof T>(a: P, b: T[P][]): boolean =>
 | 
			
		||||
  compose<T, boolean>(not, includeByProp(a, b));
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 对两个可排序对象进行减法排序,直接调用可产生升序排序效果。
 | 
			
		||||
 * @param a 参与排序的可排序对象1。
 | 
			
		||||
 * @param b 参与可排序对象的对象2。
 | 
			
		||||
 * @returns 对象1与对象2的排序字段相减的结果。
 | 
			
		||||
 */
 | 
			
		||||
export const subtractSortable = <T extends Sortable>(a: T, b: T): number => subtract(a.sort, b.sort);
 | 
			
		||||
 | 
			
		||||
type ReduceIndexedType = <T, R>(
 | 
			
		||||
  fn: (acc: R, elem: T, index: number, list: readonly T[]) => R | Reduced<R>,
 | 
			
		||||
  acc: R,
 | 
			
		||||
  list: readonly T[]
 | 
			
		||||
) => R;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 带索引的Reduce函数。其变形函的参数依次为acc、elem、index、list。
 | 
			
		||||
 */
 | 
			
		||||
export const reduceIndexed: ReduceIndexedType = addIndex<T, R>(reduce<T, R>);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用于对有精度要求的数字进行整理和输出
 | 
			
		||||
 */
 | 
			
		||||
export const outputWithPrecision: (
 | 
			
		||||
  origin: string | number | null | undefined,
 | 
			
		||||
  dp: number,
 | 
			
		||||
  defaultValue: string
 | 
			
		||||
) => string = (origin, dp, defaultValue): string => {
 | 
			
		||||
  if (isNilOrEmpty(origin)) {
 | 
			
		||||
    return defaultValue;
 | 
			
		||||
  }
 | 
			
		||||
  if (not(isFinite(dp))) {
 | 
			
		||||
    return new BigNumber(origin).toString();
 | 
			
		||||
  }
 | 
			
		||||
  return new BigNumber(origin).toFixed(dp, BigNumber.ROUND_HALF_EVEN);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 将数字金额转为大写
 | 
			
		||||
 */
 | 
			
		||||
export const digitUppercase = (n: number) => {
 | 
			
		||||
  const fraction = ['角', '分'];
 | 
			
		||||
  const digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
 | 
			
		||||
  const unit = [
 | 
			
		||||
    ['元', '万', '亿'],
 | 
			
		||||
    ['', '拾', '佰', '仟']
 | 
			
		||||
  ];
 | 
			
		||||
  n = Math.abs(n);
 | 
			
		||||
  let s = '';
 | 
			
		||||
  for (let i = 0; i < fraction.length; i++) {
 | 
			
		||||
    s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '');
 | 
			
		||||
  }
 | 
			
		||||
  s = s || '';
 | 
			
		||||
  n = Math.floor(n);
 | 
			
		||||
  for (let i = 0; i < unit[0].length && n > 0; i++) {
 | 
			
		||||
    let p = '';
 | 
			
		||||
    for (let j = 0; j < unit[1].length && n > 0; j++) {
 | 
			
		||||
      p = digit[n % 10] + unit[1][j] + p;
 | 
			
		||||
      n = Math.floor(n / 10);
 | 
			
		||||
    }
 | 
			
		||||
    s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
 | 
			
		||||
  }
 | 
			
		||||
  return s
 | 
			
		||||
    .replace(/(零.)*零元/, '元')
 | 
			
		||||
    .replace(/(零.)+/g, '零')
 | 
			
		||||
    .replace(/^整$/, '零元');
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										78
									
								
								src/utils/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/utils/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
import {message} from "antd";
 | 
			
		||||
 | 
			
		||||
export const alertError = (msg: string) => {
 | 
			
		||||
    void message.error(msg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const alertSuccess = (msg: string) => {
 | 
			
		||||
  void message.success(msg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const alertInfo = (msg: string) => {
 | 
			
		||||
  void message.info(msg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const renderEmptyData = (data: any, suffix = '') => {
 | 
			
		||||
  if (data == null || data === '') {
 | 
			
		||||
    return "-"
 | 
			
		||||
  }
 | 
			
		||||
  return `${data}${suffix}`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 节流函数
 | 
			
		||||
// eslint-disable-next-line @typescript-eslint/ban-types
 | 
			
		||||
export function throttle(fn: Function, delay: number) {
 | 
			
		||||
  let flag = true;
 | 
			
		||||
  return function() {
 | 
			
		||||
    if(!flag) return;
 | 
			
		||||
    flag = false;
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
      // eslint-disable-next-line prefer-rest-params
 | 
			
		||||
      fn.apply(this, arguments);
 | 
			
		||||
      flag = true;
 | 
			
		||||
    }, delay)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 获取列表中序号
 | 
			
		||||
export function getIndex(page: number, index: number) : string {
 | 
			
		||||
  return `${(page - 1) * 20 + Number(index) + 1}`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface Response {
 | 
			
		||||
  code: number,
 | 
			
		||||
  data: string,
 | 
			
		||||
  message: string,
 | 
			
		||||
}
 | 
			
		||||
interface FileList {
 | 
			
		||||
  crossOrigin: 'anonymous' | 'use-credentials' | '',
 | 
			
		||||
  uid: string,
 | 
			
		||||
  name: string,
 | 
			
		||||
  status: 'done' | 'uploading' | 'error' | 'removed',
 | 
			
		||||
  thumbUrl?: string
 | 
			
		||||
  url: string,
 | 
			
		||||
  response: Response
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 获取文件列表
 | 
			
		||||
export function getFileList(files: string[]): FileList[] {
 | 
			
		||||
  return files.map((item, index) => {
 | 
			
		||||
    const filename = item.slice(item.lastIndexOf('/') + 1)
 | 
			
		||||
    return {
 | 
			
		||||
      crossOrigin: 'anonymous',
 | 
			
		||||
      uid: `${Date.now() + index}`,
 | 
			
		||||
      name: filename,
 | 
			
		||||
      status: 'done',
 | 
			
		||||
      // response: '{"status": "success"}',
 | 
			
		||||
      response: { code: 0, message: '', data: item },
 | 
			
		||||
      url: item,
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 获取上传接口的文件列表
 | 
			
		||||
export function getFetchFileList(files: FileList[]) : string[] {
 | 
			
		||||
  return files.filter(item => item.status === "done").map(item => {
 | 
			
		||||
    return item?.response?.data
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								src/utils/lazyload.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/utils/lazyload.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
//@ts-nocheck
 | 
			
		||||
import { lazy } from 'react';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 惰性加载React组件工具函数。
 | 
			
		||||
 * @param loader 异步加载函数
 | 
			
		||||
 * @returns 经过异步惰性加载的组件。
 | 
			
		||||
 */
 | 
			
		||||
export const lazyLoad = <T, U extends keyof T>(loader: (x?: string) => Promise<T>) =>
 | 
			
		||||
  new Proxy({} as unknown as T, {
 | 
			
		||||
    get: (target, componentName: string | symbol) => {
 | 
			
		||||
      if (typeof componentName === 'string') {
 | 
			
		||||
        return lazy(() =>
 | 
			
		||||
          loader(componentName).then(x => ({
 | 
			
		||||
            default: x[componentName as U] as any as React.ComponentType<any>
 | 
			
		||||
          }))
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
							
								
								
									
										985
									
								
								tailwind.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										985
									
								
								tailwind.config.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,985 @@
 | 
			
		||||
const colors = require('tailwindcss/colors');
 | 
			
		||||
const palettes = require('./palette');
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  content: [],
 | 
			
		||||
  presets: [],
 | 
			
		||||
  darkMode: false, // or 'media' or 'class'
 | 
			
		||||
  important: false,
 | 
			
		||||
  corePlugins: {
 | 
			
		||||
    preflight: false
 | 
			
		||||
  },
 | 
			
		||||
  theme: {
 | 
			
		||||
    screens: {
 | 
			
		||||
      sm: '640px',
 | 
			
		||||
      md: '768px',
 | 
			
		||||
      lg: '1024px',
 | 
			
		||||
      xl: '1280px',
 | 
			
		||||
      '2xl': '1536px'
 | 
			
		||||
    },
 | 
			
		||||
    colors: {
 | 
			
		||||
      transparent: 'transparent',
 | 
			
		||||
      current: 'currentColor',
 | 
			
		||||
 | 
			
		||||
      black: colors.black,
 | 
			
		||||
      white: colors.white,
 | 
			
		||||
      gray: palettes.gray,
 | 
			
		||||
      red: palettes.red,
 | 
			
		||||
      orangered: palettes.orangered,
 | 
			
		||||
      orange: palettes.orange,
 | 
			
		||||
      gold: palettes.gold,
 | 
			
		||||
      yellow: palettes.yellow,
 | 
			
		||||
      lime: palettes.lime,
 | 
			
		||||
      green: palettes.green,
 | 
			
		||||
      sggreen: palettes.sggreen,
 | 
			
		||||
      cyan: palettes.cyan,
 | 
			
		||||
      blue: palettes.blue,
 | 
			
		||||
      arcoblue: palettes.arcoblue,
 | 
			
		||||
      indigo: colors.indigo,
 | 
			
		||||
      purple: palettes.purple,
 | 
			
		||||
      magenta: palettes.magenta,
 | 
			
		||||
      pink: colors.pink
 | 
			
		||||
    },
 | 
			
		||||
    spacing: {
 | 
			
		||||
      px: '1px',
 | 
			
		||||
      0: '0px',
 | 
			
		||||
      0.5: '0.125rem',
 | 
			
		||||
      1: '0.25rem',
 | 
			
		||||
      1.5: '0.375rem',
 | 
			
		||||
      2: '0.5rem',
 | 
			
		||||
      2.5: '0.625rem',
 | 
			
		||||
      3: '0.75rem',
 | 
			
		||||
      3.5: '0.875rem',
 | 
			
		||||
      4: '1rem',
 | 
			
		||||
      5: '1.25rem',
 | 
			
		||||
      6: '1.5rem',
 | 
			
		||||
      7: '1.75rem',
 | 
			
		||||
      8: '2rem',
 | 
			
		||||
      9: '2.25rem',
 | 
			
		||||
      10: '2.5rem',
 | 
			
		||||
      11: '2.75rem',
 | 
			
		||||
      12: '3rem',
 | 
			
		||||
      14: '3.5rem',
 | 
			
		||||
      16: '4rem',
 | 
			
		||||
      20: '5rem',
 | 
			
		||||
      24: '6rem',
 | 
			
		||||
      28: '7rem',
 | 
			
		||||
      32: '8rem',
 | 
			
		||||
      36: '9rem',
 | 
			
		||||
      40: '10rem',
 | 
			
		||||
      44: '11rem',
 | 
			
		||||
      48: '12rem',
 | 
			
		||||
      52: '13rem',
 | 
			
		||||
      56: '14rem',
 | 
			
		||||
      60: '15rem',
 | 
			
		||||
      64: '16rem',
 | 
			
		||||
      72: '18rem',
 | 
			
		||||
      80: '20rem',
 | 
			
		||||
      96: '24rem'
 | 
			
		||||
    },
 | 
			
		||||
    animation: {
 | 
			
		||||
      none: 'none',
 | 
			
		||||
      spin: 'spin 1s linear infinite',
 | 
			
		||||
      ping: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite',
 | 
			
		||||
      pulse: 'pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite',
 | 
			
		||||
      bounce: 'bounce 1s infinite'
 | 
			
		||||
    },
 | 
			
		||||
    backdropBlur: theme => theme('blur'),
 | 
			
		||||
    backdropBrightness: theme => theme('brightness'),
 | 
			
		||||
    backdropContrast: theme => theme('contrast'),
 | 
			
		||||
    backdropGrayscale: theme => theme('grayscale'),
 | 
			
		||||
    backdropHueRotate: theme => theme('hueRotate'),
 | 
			
		||||
    backdropInvert: theme => theme('invert'),
 | 
			
		||||
    backdropOpacity: theme => theme('opacity'),
 | 
			
		||||
    backdropSaturate: theme => theme('saturate'),
 | 
			
		||||
    backdropSepia: theme => theme('sepia'),
 | 
			
		||||
    backgroundColor: theme => theme('colors'),
 | 
			
		||||
    backgroundImage: {
 | 
			
		||||
      none: 'none',
 | 
			
		||||
      'gradient-to-t': 'linear-gradient(to top, var(--tw-gradient-stops))',
 | 
			
		||||
      'gradient-to-tr': 'linear-gradient(to top right, var(--tw-gradient-stops))',
 | 
			
		||||
      'gradient-to-r': 'linear-gradient(to right, var(--tw-gradient-stops))',
 | 
			
		||||
      'gradient-to-br': 'linear-gradient(to bottom right, var(--tw-gradient-stops))',
 | 
			
		||||
      'gradient-to-b': 'linear-gradient(to bottom, var(--tw-gradient-stops))',
 | 
			
		||||
      'gradient-to-bl': 'linear-gradient(to bottom left, var(--tw-gradient-stops))',
 | 
			
		||||
      'gradient-to-l': 'linear-gradient(to left, var(--tw-gradient-stops))',
 | 
			
		||||
      'gradient-to-tl': 'linear-gradient(to top left, var(--tw-gradient-stops))',
 | 
			
		||||
      'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))'
 | 
			
		||||
    },
 | 
			
		||||
    backgroundOpacity: theme => theme('opacity'),
 | 
			
		||||
    backgroundPosition: {
 | 
			
		||||
      bottom: 'bottom',
 | 
			
		||||
      center: 'center',
 | 
			
		||||
      left: 'left',
 | 
			
		||||
      'left-bottom': 'left bottom',
 | 
			
		||||
      'left-top': 'left top',
 | 
			
		||||
      right: 'right',
 | 
			
		||||
      'right-bottom': 'right bottom',
 | 
			
		||||
      'right-top': 'right top',
 | 
			
		||||
      top: 'top'
 | 
			
		||||
    },
 | 
			
		||||
    backgroundSize: {
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      cover: 'cover',
 | 
			
		||||
      contain: 'contain'
 | 
			
		||||
    },
 | 
			
		||||
    blur: {
 | 
			
		||||
      0: '0',
 | 
			
		||||
      none: '0',
 | 
			
		||||
      sm: '4px',
 | 
			
		||||
      DEFAULT: '8px',
 | 
			
		||||
      md: '12px',
 | 
			
		||||
      lg: '16px',
 | 
			
		||||
      xl: '24px',
 | 
			
		||||
      '2xl': '40px',
 | 
			
		||||
      '3xl': '64px'
 | 
			
		||||
    },
 | 
			
		||||
    brightness: {
 | 
			
		||||
      0: '0',
 | 
			
		||||
      50: '.5',
 | 
			
		||||
      75: '.75',
 | 
			
		||||
      90: '.9',
 | 
			
		||||
      95: '.95',
 | 
			
		||||
      100: '1',
 | 
			
		||||
      105: '1.05',
 | 
			
		||||
      110: '1.1',
 | 
			
		||||
      125: '1.25',
 | 
			
		||||
      150: '1.5',
 | 
			
		||||
      200: '2'
 | 
			
		||||
    },
 | 
			
		||||
    borderColor: theme => ({
 | 
			
		||||
      ...theme('colors'),
 | 
			
		||||
      DEFAULT: theme('colors.gray.200', 'currentColor')
 | 
			
		||||
    }),
 | 
			
		||||
    borderOpacity: theme => theme('opacity'),
 | 
			
		||||
    borderRadius: {
 | 
			
		||||
      none: '0px',
 | 
			
		||||
      sm: '0.125rem',
 | 
			
		||||
      DEFAULT: '0.25rem',
 | 
			
		||||
      md: '0.375rem',
 | 
			
		||||
      lg: '0.5rem',
 | 
			
		||||
      xl: '0.75rem',
 | 
			
		||||
      '2xl': '1rem',
 | 
			
		||||
      '3xl': '1.5rem',
 | 
			
		||||
      full: '9999px'
 | 
			
		||||
    },
 | 
			
		||||
    borderWidth: {
 | 
			
		||||
      DEFAULT: '1px',
 | 
			
		||||
      0: '0px',
 | 
			
		||||
      2: '2px',
 | 
			
		||||
      4: '4px',
 | 
			
		||||
      8: '8px'
 | 
			
		||||
    },
 | 
			
		||||
    boxShadow: {
 | 
			
		||||
      sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
 | 
			
		||||
      DEFAULT: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
 | 
			
		||||
      md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
 | 
			
		||||
      lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
 | 
			
		||||
      xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
 | 
			
		||||
      '2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
 | 
			
		||||
      inner: 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)',
 | 
			
		||||
      none: 'none'
 | 
			
		||||
    },
 | 
			
		||||
    caretColor: theme => theme('colors'),
 | 
			
		||||
    contrast: {
 | 
			
		||||
      0: '0',
 | 
			
		||||
      50: '.5',
 | 
			
		||||
      75: '.75',
 | 
			
		||||
      100: '1',
 | 
			
		||||
      125: '1.25',
 | 
			
		||||
      150: '1.5',
 | 
			
		||||
      200: '2'
 | 
			
		||||
    },
 | 
			
		||||
    container: {},
 | 
			
		||||
    content: {
 | 
			
		||||
      none: 'none'
 | 
			
		||||
    },
 | 
			
		||||
    cursor: {
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      default: 'default',
 | 
			
		||||
      pointer: 'pointer',
 | 
			
		||||
      wait: 'wait',
 | 
			
		||||
      text: 'text',
 | 
			
		||||
      move: 'move',
 | 
			
		||||
      help: 'help',
 | 
			
		||||
      'not-allowed': 'not-allowed'
 | 
			
		||||
    },
 | 
			
		||||
    divideColor: theme => theme('borderColor'),
 | 
			
		||||
    divideOpacity: theme => theme('borderOpacity'),
 | 
			
		||||
    divideWidth: theme => theme('borderWidth'),
 | 
			
		||||
    dropShadow: {
 | 
			
		||||
      sm: '0 1px 1px rgba(0,0,0,0.05)',
 | 
			
		||||
      DEFAULT: ['0 1px 2px rgba(0, 0, 0, 0.1)', '0 1px 1px rgba(0, 0, 0, 0.06)'],
 | 
			
		||||
      md: ['0 4px 3px rgba(0, 0, 0, 0.07)', '0 2px 2px rgba(0, 0, 0, 0.06)'],
 | 
			
		||||
      lg: ['0 10px 8px rgba(0, 0, 0, 0.04)', '0 4px 3px rgba(0, 0, 0, 0.1)'],
 | 
			
		||||
      xl: ['0 20px 13px rgba(0, 0, 0, 0.03)', '0 8px 5px rgba(0, 0, 0, 0.08)'],
 | 
			
		||||
      '2xl': '0 25px 25px rgba(0, 0, 0, 0.15)',
 | 
			
		||||
      none: '0 0 #0000'
 | 
			
		||||
    },
 | 
			
		||||
    fill: { current: 'currentColor' },
 | 
			
		||||
    grayscale: {
 | 
			
		||||
      0: '0',
 | 
			
		||||
      DEFAULT: '100%'
 | 
			
		||||
    },
 | 
			
		||||
    hueRotate: {
 | 
			
		||||
      '-180': '-180deg',
 | 
			
		||||
      '-90': '-90deg',
 | 
			
		||||
      '-60': '-60deg',
 | 
			
		||||
      '-30': '-30deg',
 | 
			
		||||
      '-15': '-15deg',
 | 
			
		||||
      0: '0deg',
 | 
			
		||||
      15: '15deg',
 | 
			
		||||
      30: '30deg',
 | 
			
		||||
      60: '60deg',
 | 
			
		||||
      90: '90deg',
 | 
			
		||||
      180: '180deg'
 | 
			
		||||
    },
 | 
			
		||||
    invert: {
 | 
			
		||||
      0: '0',
 | 
			
		||||
      DEFAULT: '100%'
 | 
			
		||||
    },
 | 
			
		||||
    flex: {
 | 
			
		||||
      1: '1 1 0%',
 | 
			
		||||
      auto: '1 1 auto',
 | 
			
		||||
      initial: '0 1 auto',
 | 
			
		||||
      none: 'none'
 | 
			
		||||
    },
 | 
			
		||||
    flexGrow: {
 | 
			
		||||
      0: '0',
 | 
			
		||||
      DEFAULT: '1'
 | 
			
		||||
    },
 | 
			
		||||
    flexShrink: {
 | 
			
		||||
      0: '0',
 | 
			
		||||
      DEFAULT: '1'
 | 
			
		||||
    },
 | 
			
		||||
    fontFamily: {
 | 
			
		||||
      sans: [
 | 
			
		||||
        'ui-sans-serif',
 | 
			
		||||
        'system-ui',
 | 
			
		||||
        '-apple-system',
 | 
			
		||||
        'BlinkMacSystemFont',
 | 
			
		||||
        '"Segoe UI"',
 | 
			
		||||
        'Roboto',
 | 
			
		||||
        '"Helvetica Neue"',
 | 
			
		||||
        'Arial',
 | 
			
		||||
        '"Noto Sans"',
 | 
			
		||||
        'sans-serif',
 | 
			
		||||
        '"Apple Color Emoji"',
 | 
			
		||||
        '"Segoe UI Emoji"',
 | 
			
		||||
        '"Segoe UI Symbol"',
 | 
			
		||||
        '"Noto Color Emoji"'
 | 
			
		||||
      ],
 | 
			
		||||
      serif: ['ui-serif', 'Georgia', 'Cambria', '"Times New Roman"', 'Times', 'serif'],
 | 
			
		||||
      mono: [
 | 
			
		||||
        'ui-monospace',
 | 
			
		||||
        'SFMono-Regular',
 | 
			
		||||
        'Menlo',
 | 
			
		||||
        'Monaco',
 | 
			
		||||
        'Consolas',
 | 
			
		||||
        '"Liberation Mono"',
 | 
			
		||||
        '"Courier New"',
 | 
			
		||||
        'monospace'
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    fontSize: {
 | 
			
		||||
      xs: ['0.75rem', { lineHeight: '1rem' }],
 | 
			
		||||
      sm: ['0.875rem', { lineHeight: '1.25rem' }],
 | 
			
		||||
      base: ['1rem', { lineHeight: '1.5rem' }],
 | 
			
		||||
      lg: ['1.125rem', { lineHeight: '1.75rem' }],
 | 
			
		||||
      xl: ['1.25rem', { lineHeight: '1.75rem' }],
 | 
			
		||||
      '2xl': ['1.5rem', { lineHeight: '2rem' }],
 | 
			
		||||
      '3xl': ['1.875rem', { lineHeight: '2.25rem' }],
 | 
			
		||||
      '4xl': ['2.25rem', { lineHeight: '2.5rem' }],
 | 
			
		||||
      '5xl': ['3rem', { lineHeight: '1' }],
 | 
			
		||||
      '6xl': ['3.75rem', { lineHeight: '1' }],
 | 
			
		||||
      '7xl': ['4.5rem', { lineHeight: '1' }],
 | 
			
		||||
      '8xl': ['6rem', { lineHeight: '1' }],
 | 
			
		||||
      '9xl': ['8rem', { lineHeight: '1' }]
 | 
			
		||||
    },
 | 
			
		||||
    fontWeight: {
 | 
			
		||||
      thin: '100',
 | 
			
		||||
      extralight: '200',
 | 
			
		||||
      light: '300',
 | 
			
		||||
      normal: '400',
 | 
			
		||||
      medium: '500',
 | 
			
		||||
      semibold: '600',
 | 
			
		||||
      bold: '700',
 | 
			
		||||
      extrabold: '800',
 | 
			
		||||
      black: '900'
 | 
			
		||||
    },
 | 
			
		||||
    gap: theme => theme('spacing'),
 | 
			
		||||
    gradientColorStops: theme => theme('colors'),
 | 
			
		||||
    gridAutoColumns: {
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      min: 'min-content',
 | 
			
		||||
      max: 'max-content',
 | 
			
		||||
      fr: 'minmax(0, 1fr)'
 | 
			
		||||
    },
 | 
			
		||||
    gridAutoRows: {
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      min: 'min-content',
 | 
			
		||||
      max: 'max-content',
 | 
			
		||||
      fr: 'minmax(0, 1fr)'
 | 
			
		||||
    },
 | 
			
		||||
    gridColumn: {
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      'span-1': 'span 1 / span 1',
 | 
			
		||||
      'span-2': 'span 2 / span 2',
 | 
			
		||||
      'span-3': 'span 3 / span 3',
 | 
			
		||||
      'span-4': 'span 4 / span 4',
 | 
			
		||||
      'span-5': 'span 5 / span 5',
 | 
			
		||||
      'span-6': 'span 6 / span 6',
 | 
			
		||||
      'span-7': 'span 7 / span 7',
 | 
			
		||||
      'span-8': 'span 8 / span 8',
 | 
			
		||||
      'span-9': 'span 9 / span 9',
 | 
			
		||||
      'span-10': 'span 10 / span 10',
 | 
			
		||||
      'span-11': 'span 11 / span 11',
 | 
			
		||||
      'span-12': 'span 12 / span 12',
 | 
			
		||||
      'span-full': '1 / -1'
 | 
			
		||||
    },
 | 
			
		||||
    gridColumnEnd: {
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      1: '1',
 | 
			
		||||
      2: '2',
 | 
			
		||||
      3: '3',
 | 
			
		||||
      4: '4',
 | 
			
		||||
      5: '5',
 | 
			
		||||
      6: '6',
 | 
			
		||||
      7: '7',
 | 
			
		||||
      8: '8',
 | 
			
		||||
      9: '9',
 | 
			
		||||
      10: '10',
 | 
			
		||||
      11: '11',
 | 
			
		||||
      12: '12',
 | 
			
		||||
      13: '13'
 | 
			
		||||
    },
 | 
			
		||||
    gridColumnStart: {
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      1: '1',
 | 
			
		||||
      2: '2',
 | 
			
		||||
      3: '3',
 | 
			
		||||
      4: '4',
 | 
			
		||||
      5: '5',
 | 
			
		||||
      6: '6',
 | 
			
		||||
      7: '7',
 | 
			
		||||
      8: '8',
 | 
			
		||||
      9: '9',
 | 
			
		||||
      10: '10',
 | 
			
		||||
      11: '11',
 | 
			
		||||
      12: '12',
 | 
			
		||||
      13: '13'
 | 
			
		||||
    },
 | 
			
		||||
    gridRow: {
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      'span-1': 'span 1 / span 1',
 | 
			
		||||
      'span-2': 'span 2 / span 2',
 | 
			
		||||
      'span-3': 'span 3 / span 3',
 | 
			
		||||
      'span-4': 'span 4 / span 4',
 | 
			
		||||
      'span-5': 'span 5 / span 5',
 | 
			
		||||
      'span-6': 'span 6 / span 6',
 | 
			
		||||
      'span-full': '1 / -1'
 | 
			
		||||
    },
 | 
			
		||||
    gridRowStart: {
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      1: '1',
 | 
			
		||||
      2: '2',
 | 
			
		||||
      3: '3',
 | 
			
		||||
      4: '4',
 | 
			
		||||
      5: '5',
 | 
			
		||||
      6: '6',
 | 
			
		||||
      7: '7'
 | 
			
		||||
    },
 | 
			
		||||
    gridRowEnd: {
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      1: '1',
 | 
			
		||||
      2: '2',
 | 
			
		||||
      3: '3',
 | 
			
		||||
      4: '4',
 | 
			
		||||
      5: '5',
 | 
			
		||||
      6: '6',
 | 
			
		||||
      7: '7'
 | 
			
		||||
    },
 | 
			
		||||
    gridTemplateColumns: {
 | 
			
		||||
      none: 'none',
 | 
			
		||||
      1: 'repeat(1, minmax(0, 1fr))',
 | 
			
		||||
      2: 'repeat(2, minmax(0, 1fr))',
 | 
			
		||||
      3: 'repeat(3, minmax(0, 1fr))',
 | 
			
		||||
      4: 'repeat(4, minmax(0, 1fr))',
 | 
			
		||||
      5: 'repeat(5, minmax(0, 1fr))',
 | 
			
		||||
      6: 'repeat(6, minmax(0, 1fr))',
 | 
			
		||||
      7: 'repeat(7, minmax(0, 1fr))',
 | 
			
		||||
      8: 'repeat(8, minmax(0, 1fr))',
 | 
			
		||||
      9: 'repeat(9, minmax(0, 1fr))',
 | 
			
		||||
      10: 'repeat(10, minmax(0, 1fr))',
 | 
			
		||||
      11: 'repeat(11, minmax(0, 1fr))',
 | 
			
		||||
      12: 'repeat(12, minmax(0, 1fr))'
 | 
			
		||||
    },
 | 
			
		||||
    gridTemplateRows: {
 | 
			
		||||
      none: 'none',
 | 
			
		||||
      1: 'repeat(1, minmax(0, 1fr))',
 | 
			
		||||
      2: 'repeat(2, minmax(0, 1fr))',
 | 
			
		||||
      3: 'repeat(3, minmax(0, 1fr))',
 | 
			
		||||
      4: 'repeat(4, minmax(0, 1fr))',
 | 
			
		||||
      5: 'repeat(5, minmax(0, 1fr))',
 | 
			
		||||
      6: 'repeat(6, minmax(0, 1fr))'
 | 
			
		||||
    },
 | 
			
		||||
    height: theme => ({
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      ...theme('spacing'),
 | 
			
		||||
      '1/2': '50%',
 | 
			
		||||
      '1/3': '33.333333%',
 | 
			
		||||
      '2/3': '66.666667%',
 | 
			
		||||
      '1/4': '25%',
 | 
			
		||||
      '2/4': '50%',
 | 
			
		||||
      '3/4': '75%',
 | 
			
		||||
      '1/5': '20%',
 | 
			
		||||
      '2/5': '40%',
 | 
			
		||||
      '3/5': '60%',
 | 
			
		||||
      '4/5': '80%',
 | 
			
		||||
      '1/6': '16.666667%',
 | 
			
		||||
      '2/6': '33.333333%',
 | 
			
		||||
      '3/6': '50%',
 | 
			
		||||
      '4/6': '66.666667%',
 | 
			
		||||
      '5/6': '83.333333%',
 | 
			
		||||
      full: '100%',
 | 
			
		||||
      screen: '100vh'
 | 
			
		||||
    }),
 | 
			
		||||
    inset: (theme, { negative }) => ({
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      ...theme('spacing'),
 | 
			
		||||
      ...negative(theme('spacing')),
 | 
			
		||||
      '1/2': '50%',
 | 
			
		||||
      '1/3': '33.333333%',
 | 
			
		||||
      '2/3': '66.666667%',
 | 
			
		||||
      '1/4': '25%',
 | 
			
		||||
      '2/4': '50%',
 | 
			
		||||
      '3/4': '75%',
 | 
			
		||||
      full: '100%',
 | 
			
		||||
      '-1/2': '-50%',
 | 
			
		||||
      '-1/3': '-33.333333%',
 | 
			
		||||
      '-2/3': '-66.666667%',
 | 
			
		||||
      '-1/4': '-25%',
 | 
			
		||||
      '-2/4': '-50%',
 | 
			
		||||
      '-3/4': '-75%',
 | 
			
		||||
      '-full': '-100%'
 | 
			
		||||
    }),
 | 
			
		||||
    keyframes: {
 | 
			
		||||
      spin: {
 | 
			
		||||
        to: {
 | 
			
		||||
          transform: 'rotate(360deg)'
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      ping: {
 | 
			
		||||
        '75%, 100%': {
 | 
			
		||||
          transform: 'scale(2)',
 | 
			
		||||
          opacity: '0'
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      pulse: {
 | 
			
		||||
        '50%': {
 | 
			
		||||
          opacity: '.5'
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      bounce: {
 | 
			
		||||
        '0%, 100%': {
 | 
			
		||||
          transform: 'translateY(-25%)',
 | 
			
		||||
          animationTimingFunction: 'cubic-bezier(0.8,0,1,1)'
 | 
			
		||||
        },
 | 
			
		||||
        '50%': {
 | 
			
		||||
          transform: 'none',
 | 
			
		||||
          animationTimingFunction: 'cubic-bezier(0,0,0.2,1)'
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    letterSpacing: {
 | 
			
		||||
      tighter: '-0.05em',
 | 
			
		||||
      tight: '-0.025em',
 | 
			
		||||
      normal: '0em',
 | 
			
		||||
      wide: '0.025em',
 | 
			
		||||
      wider: '0.05em',
 | 
			
		||||
      widest: '0.1em'
 | 
			
		||||
    },
 | 
			
		||||
    lineHeight: {
 | 
			
		||||
      none: '1',
 | 
			
		||||
      tight: '1.25',
 | 
			
		||||
      snug: '1.375',
 | 
			
		||||
      normal: '1.5',
 | 
			
		||||
      relaxed: '1.625',
 | 
			
		||||
      loose: '2',
 | 
			
		||||
      3: '.75rem',
 | 
			
		||||
      4: '1rem',
 | 
			
		||||
      5: '1.25rem',
 | 
			
		||||
      6: '1.5rem',
 | 
			
		||||
      7: '1.75rem',
 | 
			
		||||
      8: '2rem',
 | 
			
		||||
      9: '2.25rem',
 | 
			
		||||
      10: '2.5rem'
 | 
			
		||||
    },
 | 
			
		||||
    listStyleType: {
 | 
			
		||||
      none: 'none',
 | 
			
		||||
      disc: 'disc',
 | 
			
		||||
      decimal: 'decimal'
 | 
			
		||||
    },
 | 
			
		||||
    margin: (theme, { negative }) => ({
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      ...theme('spacing'),
 | 
			
		||||
      ...negative(theme('spacing'))
 | 
			
		||||
    }),
 | 
			
		||||
    maxHeight: theme => ({
 | 
			
		||||
      ...theme('spacing'),
 | 
			
		||||
      full: '100%',
 | 
			
		||||
      screen: '100vh'
 | 
			
		||||
    }),
 | 
			
		||||
    maxWidth: (theme, { breakpoints }) => ({
 | 
			
		||||
      none: 'none',
 | 
			
		||||
      0: '0rem',
 | 
			
		||||
      xs: '20rem',
 | 
			
		||||
      sm: '24rem',
 | 
			
		||||
      md: '28rem',
 | 
			
		||||
      lg: '32rem',
 | 
			
		||||
      xl: '36rem',
 | 
			
		||||
      '2xl': '42rem',
 | 
			
		||||
      '3xl': '48rem',
 | 
			
		||||
      '4xl': '56rem',
 | 
			
		||||
      '5xl': '64rem',
 | 
			
		||||
      '6xl': '72rem',
 | 
			
		||||
      '7xl': '80rem',
 | 
			
		||||
      full: '100%',
 | 
			
		||||
      min: 'min-content',
 | 
			
		||||
      max: 'max-content',
 | 
			
		||||
      prose: '65ch',
 | 
			
		||||
      ...breakpoints(theme('screens'))
 | 
			
		||||
    }),
 | 
			
		||||
    minHeight: {
 | 
			
		||||
      0: '0px',
 | 
			
		||||
      full: '100%',
 | 
			
		||||
      screen: '100vh'
 | 
			
		||||
    },
 | 
			
		||||
    minWidth: {
 | 
			
		||||
      0: '0px',
 | 
			
		||||
      full: '100%',
 | 
			
		||||
      min: 'min-content',
 | 
			
		||||
      max: 'max-content'
 | 
			
		||||
    },
 | 
			
		||||
    objectPosition: {
 | 
			
		||||
      bottom: 'bottom',
 | 
			
		||||
      center: 'center',
 | 
			
		||||
      left: 'left',
 | 
			
		||||
      'left-bottom': 'left bottom',
 | 
			
		||||
      'left-top': 'left top',
 | 
			
		||||
      right: 'right',
 | 
			
		||||
      'right-bottom': 'right bottom',
 | 
			
		||||
      'right-top': 'right top',
 | 
			
		||||
      top: 'top'
 | 
			
		||||
    },
 | 
			
		||||
    opacity: {
 | 
			
		||||
      0: '0',
 | 
			
		||||
      5: '0.05',
 | 
			
		||||
      10: '0.1',
 | 
			
		||||
      20: '0.2',
 | 
			
		||||
      25: '0.25',
 | 
			
		||||
      30: '0.3',
 | 
			
		||||
      40: '0.4',
 | 
			
		||||
      50: '0.5',
 | 
			
		||||
      60: '0.6',
 | 
			
		||||
      70: '0.7',
 | 
			
		||||
      75: '0.75',
 | 
			
		||||
      80: '0.8',
 | 
			
		||||
      90: '0.9',
 | 
			
		||||
      95: '0.95',
 | 
			
		||||
      100: '1'
 | 
			
		||||
    },
 | 
			
		||||
    order: {
 | 
			
		||||
      first: '-9999',
 | 
			
		||||
      last: '9999',
 | 
			
		||||
      none: '0',
 | 
			
		||||
      1: '1',
 | 
			
		||||
      2: '2',
 | 
			
		||||
      3: '3',
 | 
			
		||||
      4: '4',
 | 
			
		||||
      5: '5',
 | 
			
		||||
      6: '6',
 | 
			
		||||
      7: '7',
 | 
			
		||||
      8: '8',
 | 
			
		||||
      9: '9',
 | 
			
		||||
      10: '10',
 | 
			
		||||
      11: '11',
 | 
			
		||||
      12: '12'
 | 
			
		||||
    },
 | 
			
		||||
    outline: {
 | 
			
		||||
      none: ['2px solid transparent', '2px'],
 | 
			
		||||
      white: ['2px dotted white', '2px'],
 | 
			
		||||
      black: ['2px dotted black', '2px']
 | 
			
		||||
    },
 | 
			
		||||
    padding: theme => theme('spacing'),
 | 
			
		||||
    placeholderColor: theme => theme('colors'),
 | 
			
		||||
    placeholderOpacity: theme => theme('opacity'),
 | 
			
		||||
    ringColor: theme => ({
 | 
			
		||||
      DEFAULT: theme('colors.blue.500', '#3b82f6'),
 | 
			
		||||
      ...theme('colors')
 | 
			
		||||
    }),
 | 
			
		||||
    ringOffsetColor: theme => theme('colors'),
 | 
			
		||||
    ringOffsetWidth: {
 | 
			
		||||
      0: '0px',
 | 
			
		||||
      1: '1px',
 | 
			
		||||
      2: '2px',
 | 
			
		||||
      4: '4px',
 | 
			
		||||
      8: '8px'
 | 
			
		||||
    },
 | 
			
		||||
    ringOpacity: theme => ({
 | 
			
		||||
      DEFAULT: '0.5',
 | 
			
		||||
      ...theme('opacity')
 | 
			
		||||
    }),
 | 
			
		||||
    ringWidth: {
 | 
			
		||||
      DEFAULT: '3px',
 | 
			
		||||
      0: '0px',
 | 
			
		||||
      1: '1px',
 | 
			
		||||
      2: '2px',
 | 
			
		||||
      4: '4px',
 | 
			
		||||
      8: '8px'
 | 
			
		||||
    },
 | 
			
		||||
    rotate: {
 | 
			
		||||
      '-180': '-180deg',
 | 
			
		||||
      '-90': '-90deg',
 | 
			
		||||
      '-45': '-45deg',
 | 
			
		||||
      '-12': '-12deg',
 | 
			
		||||
      '-6': '-6deg',
 | 
			
		||||
      '-3': '-3deg',
 | 
			
		||||
      '-2': '-2deg',
 | 
			
		||||
      '-1': '-1deg',
 | 
			
		||||
      0: '0deg',
 | 
			
		||||
      1: '1deg',
 | 
			
		||||
      2: '2deg',
 | 
			
		||||
      3: '3deg',
 | 
			
		||||
      6: '6deg',
 | 
			
		||||
      12: '12deg',
 | 
			
		||||
      45: '45deg',
 | 
			
		||||
      90: '90deg',
 | 
			
		||||
      180: '180deg'
 | 
			
		||||
    },
 | 
			
		||||
    saturate: {
 | 
			
		||||
      0: '0',
 | 
			
		||||
      50: '.5',
 | 
			
		||||
      100: '1',
 | 
			
		||||
      150: '1.5',
 | 
			
		||||
      200: '2'
 | 
			
		||||
    },
 | 
			
		||||
    scale: {
 | 
			
		||||
      0: '0',
 | 
			
		||||
      50: '.5',
 | 
			
		||||
      75: '.75',
 | 
			
		||||
      90: '.9',
 | 
			
		||||
      95: '.95',
 | 
			
		||||
      100: '1',
 | 
			
		||||
      105: '1.05',
 | 
			
		||||
      110: '1.1',
 | 
			
		||||
      125: '1.25',
 | 
			
		||||
      150: '1.5'
 | 
			
		||||
    },
 | 
			
		||||
    sepia: {
 | 
			
		||||
      0: '0',
 | 
			
		||||
      DEFAULT: '100%'
 | 
			
		||||
    },
 | 
			
		||||
    skew: {
 | 
			
		||||
      '-12': '-12deg',
 | 
			
		||||
      '-6': '-6deg',
 | 
			
		||||
      '-3': '-3deg',
 | 
			
		||||
      '-2': '-2deg',
 | 
			
		||||
      '-1': '-1deg',
 | 
			
		||||
      0: '0deg',
 | 
			
		||||
      1: '1deg',
 | 
			
		||||
      2: '2deg',
 | 
			
		||||
      3: '3deg',
 | 
			
		||||
      6: '6deg',
 | 
			
		||||
      12: '12deg'
 | 
			
		||||
    },
 | 
			
		||||
    space: (theme, { negative }) => ({
 | 
			
		||||
      ...theme('spacing'),
 | 
			
		||||
      ...negative(theme('spacing'))
 | 
			
		||||
    }),
 | 
			
		||||
    stroke: {
 | 
			
		||||
      current: 'currentColor'
 | 
			
		||||
    },
 | 
			
		||||
    strokeWidth: {
 | 
			
		||||
      0: '0',
 | 
			
		||||
      1: '1',
 | 
			
		||||
      2: '2'
 | 
			
		||||
    },
 | 
			
		||||
    textColor: theme => theme('colors'),
 | 
			
		||||
    textOpacity: theme => theme('opacity'),
 | 
			
		||||
    transformOrigin: {
 | 
			
		||||
      center: 'center',
 | 
			
		||||
      top: 'top',
 | 
			
		||||
      'top-right': 'top right',
 | 
			
		||||
      right: 'right',
 | 
			
		||||
      'bottom-right': 'bottom right',
 | 
			
		||||
      bottom: 'bottom',
 | 
			
		||||
      'bottom-left': 'bottom left',
 | 
			
		||||
      left: 'left',
 | 
			
		||||
      'top-left': 'top left'
 | 
			
		||||
    },
 | 
			
		||||
    transitionDelay: {
 | 
			
		||||
      75: '75ms',
 | 
			
		||||
      100: '100ms',
 | 
			
		||||
      150: '150ms',
 | 
			
		||||
      200: '200ms',
 | 
			
		||||
      300: '300ms',
 | 
			
		||||
      500: '500ms',
 | 
			
		||||
      700: '700ms',
 | 
			
		||||
      1000: '1000ms'
 | 
			
		||||
    },
 | 
			
		||||
    transitionDuration: {
 | 
			
		||||
      DEFAULT: '150ms',
 | 
			
		||||
      75: '75ms',
 | 
			
		||||
      100: '100ms',
 | 
			
		||||
      150: '150ms',
 | 
			
		||||
      200: '200ms',
 | 
			
		||||
      300: '300ms',
 | 
			
		||||
      500: '500ms',
 | 
			
		||||
      700: '700ms',
 | 
			
		||||
      1000: '1000ms'
 | 
			
		||||
    },
 | 
			
		||||
    transitionProperty: {
 | 
			
		||||
      none: 'none',
 | 
			
		||||
      all: 'all',
 | 
			
		||||
      DEFAULT:
 | 
			
		||||
        'background-color, border-color, color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter',
 | 
			
		||||
      colors: 'background-color, border-color, color, fill, stroke',
 | 
			
		||||
      opacity: 'opacity',
 | 
			
		||||
      shadow: 'box-shadow',
 | 
			
		||||
      transform: 'transform'
 | 
			
		||||
    },
 | 
			
		||||
    transitionTimingFunction: {
 | 
			
		||||
      DEFAULT: 'cubic-bezier(0.4, 0, 0.2, 1)',
 | 
			
		||||
      linear: 'linear',
 | 
			
		||||
      in: 'cubic-bezier(0.4, 0, 1, 1)',
 | 
			
		||||
      out: 'cubic-bezier(0, 0, 0.2, 1)',
 | 
			
		||||
      'in-out': 'cubic-bezier(0.4, 0, 0.2, 1)'
 | 
			
		||||
    },
 | 
			
		||||
    translate: (theme, { negative }) => ({
 | 
			
		||||
      ...theme('spacing'),
 | 
			
		||||
      ...negative(theme('spacing')),
 | 
			
		||||
      '1/2': '50%',
 | 
			
		||||
      '1/3': '33.333333%',
 | 
			
		||||
      '2/3': '66.666667%',
 | 
			
		||||
      '1/4': '25%',
 | 
			
		||||
      '2/4': '50%',
 | 
			
		||||
      '3/4': '75%',
 | 
			
		||||
      full: '100%',
 | 
			
		||||
      '-1/2': '-50%',
 | 
			
		||||
      '-1/3': '-33.333333%',
 | 
			
		||||
      '-2/3': '-66.666667%',
 | 
			
		||||
      '-1/4': '-25%',
 | 
			
		||||
      '-2/4': '-50%',
 | 
			
		||||
      '-3/4': '-75%',
 | 
			
		||||
      '-full': '-100%'
 | 
			
		||||
    }),
 | 
			
		||||
    width: theme => ({
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      ...theme('spacing'),
 | 
			
		||||
      '1/2': '50%',
 | 
			
		||||
      '1/3': '33.333333%',
 | 
			
		||||
      '2/3': '66.666667%',
 | 
			
		||||
      '1/4': '25%',
 | 
			
		||||
      '2/4': '50%',
 | 
			
		||||
      '3/4': '75%',
 | 
			
		||||
      '1/5': '20%',
 | 
			
		||||
      '2/5': '40%',
 | 
			
		||||
      '3/5': '60%',
 | 
			
		||||
      '4/5': '80%',
 | 
			
		||||
      '1/6': '16.666667%',
 | 
			
		||||
      '2/6': '33.333333%',
 | 
			
		||||
      '3/6': '50%',
 | 
			
		||||
      '4/6': '66.666667%',
 | 
			
		||||
      '5/6': '83.333333%',
 | 
			
		||||
      '1/12': '8.333333%',
 | 
			
		||||
      '2/12': '16.666667%',
 | 
			
		||||
      '3/12': '25%',
 | 
			
		||||
      '4/12': '33.333333%',
 | 
			
		||||
      '5/12': '41.666667%',
 | 
			
		||||
      '6/12': '50%',
 | 
			
		||||
      '7/12': '58.333333%',
 | 
			
		||||
      '8/12': '66.666667%',
 | 
			
		||||
      '9/12': '75%',
 | 
			
		||||
      '10/12': '83.333333%',
 | 
			
		||||
      '11/12': '91.666667%',
 | 
			
		||||
      full: '100%',
 | 
			
		||||
      screen: '100vw',
 | 
			
		||||
      min: 'min-content',
 | 
			
		||||
      max: 'max-content'
 | 
			
		||||
    }),
 | 
			
		||||
    zIndex: {
 | 
			
		||||
      auto: 'auto',
 | 
			
		||||
      0: '0',
 | 
			
		||||
      10: '10',
 | 
			
		||||
      20: '20',
 | 
			
		||||
      30: '30',
 | 
			
		||||
      40: '40',
 | 
			
		||||
      50: '50'
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  variantOrder: [
 | 
			
		||||
    'first',
 | 
			
		||||
    'last',
 | 
			
		||||
    'odd',
 | 
			
		||||
    'even',
 | 
			
		||||
    'visited',
 | 
			
		||||
    'checked',
 | 
			
		||||
    'empty',
 | 
			
		||||
    'read-only',
 | 
			
		||||
    'group-hover',
 | 
			
		||||
    'group-focus',
 | 
			
		||||
    'focus-within',
 | 
			
		||||
    'hover',
 | 
			
		||||
    'focus',
 | 
			
		||||
    'focus-visible',
 | 
			
		||||
    'active',
 | 
			
		||||
    'disabled'
 | 
			
		||||
  ],
 | 
			
		||||
  variants: {
 | 
			
		||||
    accessibility: ['responsive', 'focus-within', 'focus'],
 | 
			
		||||
    alignContent: ['responsive'],
 | 
			
		||||
    alignItems: ['responsive'],
 | 
			
		||||
    alignSelf: ['responsive'],
 | 
			
		||||
    animation: ['responsive'],
 | 
			
		||||
    appearance: ['responsive'],
 | 
			
		||||
    backdropBlur: ['responsive'],
 | 
			
		||||
    backdropBrightness: ['responsive'],
 | 
			
		||||
    backdropContrast: ['responsive'],
 | 
			
		||||
    backdropFilter: ['responsive'],
 | 
			
		||||
    backdropGrayscale: ['responsive'],
 | 
			
		||||
    backdropHueRotate: ['responsive'],
 | 
			
		||||
    backdropInvert: ['responsive'],
 | 
			
		||||
    backdropOpacity: ['responsive'],
 | 
			
		||||
    backdropSaturate: ['responsive'],
 | 
			
		||||
    backdropSepia: ['responsive'],
 | 
			
		||||
    backgroundAttachment: ['responsive'],
 | 
			
		||||
    backgroundBlendMode: ['responsive'],
 | 
			
		||||
    backgroundClip: ['responsive'],
 | 
			
		||||
    backgroundColor: ['responsive', 'dark', 'group-hover', 'focus-within', 'hover', 'focus'],
 | 
			
		||||
    backgroundImage: ['responsive'],
 | 
			
		||||
    backgroundOpacity: ['responsive', 'dark', 'group-hover', 'focus-within', 'hover', 'focus'],
 | 
			
		||||
    backgroundPosition: ['responsive'],
 | 
			
		||||
    backgroundRepeat: ['responsive'],
 | 
			
		||||
    backgroundSize: ['responsive'],
 | 
			
		||||
    backgroundOrigin: ['responsive'],
 | 
			
		||||
    blur: ['responsive'],
 | 
			
		||||
    borderCollapse: ['responsive'],
 | 
			
		||||
    borderColor: ['responsive', 'dark', 'group-hover', 'focus-within', 'hover', 'focus'],
 | 
			
		||||
    borderOpacity: ['responsive', 'dark', 'group-hover', 'focus-within', 'hover', 'focus'],
 | 
			
		||||
    borderRadius: ['responsive'],
 | 
			
		||||
    borderStyle: ['responsive'],
 | 
			
		||||
    borderWidth: ['responsive'],
 | 
			
		||||
    boxDecorationBreak: ['responsive'],
 | 
			
		||||
    boxShadow: ['responsive', 'group-hover', 'focus-within', 'hover', 'focus'],
 | 
			
		||||
    boxSizing: ['responsive'],
 | 
			
		||||
    brightness: ['responsive'],
 | 
			
		||||
    clear: ['responsive'],
 | 
			
		||||
    container: ['responsive'],
 | 
			
		||||
    contrast: ['responsive'],
 | 
			
		||||
    cursor: ['responsive'],
 | 
			
		||||
    display: ['responsive'],
 | 
			
		||||
    divideColor: ['responsive', 'dark'],
 | 
			
		||||
    divideOpacity: ['responsive', 'dark'],
 | 
			
		||||
    divideStyle: ['responsive'],
 | 
			
		||||
    divideWidth: ['responsive'],
 | 
			
		||||
    dropShadow: ['responsive'],
 | 
			
		||||
    fill: ['responsive'],
 | 
			
		||||
    filter: ['responsive'],
 | 
			
		||||
    flex: ['responsive'],
 | 
			
		||||
    flexDirection: ['responsive'],
 | 
			
		||||
    flexGrow: ['responsive'],
 | 
			
		||||
    flexShrink: ['responsive'],
 | 
			
		||||
    flexWrap: ['responsive'],
 | 
			
		||||
    float: ['responsive'],
 | 
			
		||||
    fontFamily: ['responsive'],
 | 
			
		||||
    fontSize: ['responsive'],
 | 
			
		||||
    fontSmoothing: ['responsive'],
 | 
			
		||||
    fontStyle: ['responsive'],
 | 
			
		||||
    fontVariantNumeric: ['responsive'],
 | 
			
		||||
    fontWeight: ['responsive'],
 | 
			
		||||
    gap: ['responsive'],
 | 
			
		||||
    gradientColorStops: ['responsive', 'dark', 'hover', 'focus'],
 | 
			
		||||
    grayscale: ['responsive'],
 | 
			
		||||
    gridAutoColumns: ['responsive'],
 | 
			
		||||
    gridAutoFlow: ['responsive'],
 | 
			
		||||
    gridAutoRows: ['responsive'],
 | 
			
		||||
    gridColumn: ['responsive'],
 | 
			
		||||
    gridColumnEnd: ['responsive'],
 | 
			
		||||
    gridColumnStart: ['responsive'],
 | 
			
		||||
    gridRow: ['responsive'],
 | 
			
		||||
    gridRowEnd: ['responsive'],
 | 
			
		||||
    gridRowStart: ['responsive'],
 | 
			
		||||
    gridTemplateColumns: ['responsive'],
 | 
			
		||||
    gridTemplateRows: ['responsive'],
 | 
			
		||||
    height: ['responsive'],
 | 
			
		||||
    hueRotate: ['responsive'],
 | 
			
		||||
    inset: ['responsive'],
 | 
			
		||||
    invert: ['responsive'],
 | 
			
		||||
    isolation: ['responsive'],
 | 
			
		||||
    justifyContent: ['responsive'],
 | 
			
		||||
    justifyItems: ['responsive'],
 | 
			
		||||
    justifySelf: ['responsive'],
 | 
			
		||||
    letterSpacing: ['responsive'],
 | 
			
		||||
    lineHeight: ['responsive'],
 | 
			
		||||
    listStylePosition: ['responsive'],
 | 
			
		||||
    listStyleType: ['responsive'],
 | 
			
		||||
    margin: ['responsive'],
 | 
			
		||||
    maxHeight: ['responsive'],
 | 
			
		||||
    maxWidth: ['responsive'],
 | 
			
		||||
    minHeight: ['responsive'],
 | 
			
		||||
    minWidth: ['responsive'],
 | 
			
		||||
    mixBlendMode: ['responsive'],
 | 
			
		||||
    objectFit: ['responsive'],
 | 
			
		||||
    objectPosition: ['responsive'],
 | 
			
		||||
    opacity: ['responsive', 'group-hover', 'focus-within', 'hover', 'focus'],
 | 
			
		||||
    order: ['responsive'],
 | 
			
		||||
    outline: ['responsive', 'focus-within', 'focus'],
 | 
			
		||||
    overflow: ['responsive'],
 | 
			
		||||
    overscrollBehavior: ['responsive'],
 | 
			
		||||
    padding: ['responsive'],
 | 
			
		||||
    placeContent: ['responsive'],
 | 
			
		||||
    placeItems: ['responsive'],
 | 
			
		||||
    placeSelf: ['responsive'],
 | 
			
		||||
    placeholderColor: ['responsive', 'dark', 'focus'],
 | 
			
		||||
    placeholderOpacity: ['responsive', 'dark', 'focus'],
 | 
			
		||||
    pointerEvents: ['responsive'],
 | 
			
		||||
    position: ['responsive'],
 | 
			
		||||
    resize: ['responsive'],
 | 
			
		||||
    ringColor: ['responsive', 'dark', 'focus-within', 'focus'],
 | 
			
		||||
    ringOffsetColor: ['responsive', 'dark', 'focus-within', 'focus'],
 | 
			
		||||
    ringOffsetWidth: ['responsive', 'focus-within', 'focus'],
 | 
			
		||||
    ringOpacity: ['responsive', 'dark', 'focus-within', 'focus'],
 | 
			
		||||
    ringWidth: ['responsive', 'focus-within', 'focus'],
 | 
			
		||||
    rotate: ['responsive', 'hover', 'focus'],
 | 
			
		||||
    saturate: ['responsive'],
 | 
			
		||||
    scale: ['responsive', 'hover', 'focus'],
 | 
			
		||||
    sepia: ['responsive'],
 | 
			
		||||
    skew: ['responsive', 'hover', 'focus'],
 | 
			
		||||
    space: ['responsive'],
 | 
			
		||||
    stroke: ['responsive'],
 | 
			
		||||
    strokeWidth: ['responsive'],
 | 
			
		||||
    tableLayout: ['responsive'],
 | 
			
		||||
    textAlign: ['responsive'],
 | 
			
		||||
    textColor: ['responsive', 'dark', 'group-hover', 'focus-within', 'hover', 'focus'],
 | 
			
		||||
    textDecoration: ['responsive', 'group-hover', 'focus-within', 'hover', 'focus'],
 | 
			
		||||
    textOpacity: ['responsive', 'dark', 'group-hover', 'focus-within', 'hover', 'focus'],
 | 
			
		||||
    textOverflow: ['responsive'],
 | 
			
		||||
    textTransform: ['responsive'],
 | 
			
		||||
    transform: ['responsive'],
 | 
			
		||||
    transformOrigin: ['responsive'],
 | 
			
		||||
    transitionDelay: ['responsive'],
 | 
			
		||||
    transitionDuration: ['responsive'],
 | 
			
		||||
    transitionProperty: ['responsive'],
 | 
			
		||||
    transitionTimingFunction: ['responsive'],
 | 
			
		||||
    translate: ['responsive', 'hover', 'focus'],
 | 
			
		||||
    userSelect: ['responsive'],
 | 
			
		||||
    verticalAlign: ['responsive'],
 | 
			
		||||
    visibility: ['responsive'],
 | 
			
		||||
    whitespace: ['responsive'],
 | 
			
		||||
    width: ['responsive'],
 | 
			
		||||
    wordBreak: ['responsive'],
 | 
			
		||||
    zIndex: ['responsive', 'focus-within', 'focus']
 | 
			
		||||
  },
 | 
			
		||||
  plugins: []
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user