Ver código fonte

feat(custom): decl

linyuanjie 1 semana atrás
pai
commit
3914e6288e

+ 2 - 0
package.json

@@ -60,6 +60,7 @@
     "@iconify/react": "^4.1.1",
     "@tanstack/react-query": "^5.50.1",
     "@tanstack/react-query-devtools": "^5.50.1",
+    "@types/lodash-es": "^4.17.12",
     "@vanilla-extract/css": "^1.17.0",
     "@vanilla-extract/vite-plugin": "^4.0.19",
     "@vercel/analytics": "^1.2.2",
@@ -78,6 +79,7 @@
     "highlight.js": "^11.9.0",
     "i18next": "^23.5.1",
     "i18next-browser-languagedetector": "^7.1.0",
+    "lodash-es": "^4.17.21",
     "nanoid": "^5.1.0",
     "nprogress": "^0.2.0",
     "numeral": "^2.0.6",

+ 6 - 0
pnpm-lock.yaml

@@ -65,6 +65,9 @@ importers:
       '@tanstack/react-query-devtools':
         specifier: ^5.50.1
         version: 5.60.2(@tanstack/react-query@5.60.2(react@18.2.0))(react@18.2.0)
+      '@types/lodash-es':
+        specifier: ^4.17.12
+        version: 4.17.12
       '@vanilla-extract/css':
         specifier: ^1.17.0
         version: 1.17.0(babel-plugin-macros@3.1.0)
@@ -119,6 +122,9 @@ importers:
       i18next-browser-languagedetector:
         specifier: ^7.1.0
         version: 7.2.1
+      lodash-es:
+        specifier: ^4.17.21
+        version: 4.17.21
       nanoid:
         specifier: ^5.1.0
         version: 5.1.0

+ 1590 - 0
src/api/services/riskcontrol/data.d.ts

@@ -0,0 +1,1590 @@
+declare namespace API {
+  interface BaseInfo {
+    lastUpdateTime?: string
+    mongoId: string
+    keyNo: string
+    entName: string
+    entCode: string
+    operName: string
+    status: string
+    startDate: string
+    registCapi: string
+    realCapi: string
+    orgNo: string
+    bizNo: string
+    taxNo: string
+    econKind: string
+    termStart: string
+    termEnd: string
+    taxpayerType: string
+    personScope: string
+    insuredCount: string
+    checkDate: string
+    areaCode: string
+    belongOrg: string
+    imExCode: string
+    englishName: string
+    address: string
+    annualAddress: string
+    scope: string
+    entType: string
+    logo: string
+    isSmall: string
+    scale: string
+    isOfficialEnglish: string
+  }
+  interface TaxCreditRating {
+    taxNo: string
+    year: string
+    level: string
+    org: string
+  }
+  interface TaxCreditRatingInfo {
+    mongoId: string
+    taxCreditRatings: TaxCreditRating[]
+    lastUpdateTime?: string
+  }
+  interface MoreEmailList {
+    email: string
+    source: string
+  }
+  interface MoreTelList {
+    tel: string
+    source: string
+  }
+  interface ContactInfo {
+    webSiteList: string[]
+    email: string
+    moreEmailList: MoreEmailList[]
+    tel: string
+    moreTelList: MoreTelList[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface PubEmployee {
+    name: string
+    job: string
+  }
+
+  interface pubEmployeeInfo {
+    pubEmployees: PubEmployee[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface PubPartner {
+    stockName: string
+    stockPercent: string
+    holdType: string
+    amount: string
+    creditCode: string
+    area: string
+  }
+  interface PubPartnerInfo {
+    pubPartners: PubPartner[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  /** 当前企业自己的风控信息分页 */
+  type EntRiskPageResultItem = {
+    baseInfo?: BaseInfo
+    modifiedTime: string
+    initTime: string
+    createdBy: string
+    taxCreditRatingInfo?: TaxCreditRatingInfo
+    createdTime: string
+    relationId: string
+    regCode: string
+    modifiedBy: string
+    entType: string
+    enterpriseName: string
+    pubPartnerInfo?: PubPartnerInfo
+    contactInfo?: ContactInfo
+    pubEmployeeInfo?: pubEmployeeInfo
+    deptIdList?: string[]
+  }
+  type EntRiskPageResult = EntRiskPageResultItem[]
+
+  /** 绑定企业风控关系入参 */
+  type EntRiskBindParam = {
+    entName: string
+    regCode: string
+    entType: string
+  }
+
+  type EntTypeUpdateParams = {
+    relationId: string
+    entType: string
+    // deptIdList: string[]
+  }
+
+  /** 绑定企业检查 */
+  interface EntRiskCheckBindResult {
+    hasBond: boolean
+    entType: string
+    entName: string
+    regCode: string
+  }
+
+  /** 刷新风险关系数据入参 */
+  type EntRiskRefreshParam = {
+    relationId: number | string
+    regCode: string
+    forceRefresh: boolean
+  }
+
+  interface Partner {
+    keyNo: string
+    stockName: string
+    stockType: string
+    stockPercent: string
+    shouldCapi: string
+    shoudDate: string
+    stakeDate: string
+    creditCode: string
+    area: string
+  }
+  interface PartnerInfo {
+    partners: Partner[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface Pledge {
+    registerDate: string
+    id: string
+    registerNo: string
+    pledgorList: string[]
+    pledgeeList: string[]
+    relatedCompany: string
+    pledgedAmount: string
+    status: string
+  }
+  interface EquityPledgeInfo {
+    pledges: Pledge[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface Employee {
+    keyNo: string
+    name: string
+    post: string
+  }
+  interface EmployeeInfo {
+    employees: Employee[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface RegistrationWebsite {
+    name: string
+    webAddress: string
+    domainName: string
+    licenseNo: string
+    auditDate: string
+  }
+  interface RegistrationWebsiteInfo {
+    websites: RegistrationWebsite[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface EntRiskChangeInfos {
+    projectName: string
+    changeDate: string
+    beforeList: string[]
+    afterList: string[]
+    beforeInfoList: any[]
+    afterInfoList: any[]
+  }
+  interface EntRiskChangeInfo {
+    changeInfos: EntRiskChangeInfos[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface AdministrativeLicense {
+    licenseDocNo: string
+    licenseDocName: string
+    validityFrom: string
+    validityTo: string
+    licenseOffice: string
+    licenseContent: string
+    source: string
+  }
+  interface AdministrativeLicenseInfo {
+    licenses: AdministrativeLicense[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface EntBankInfo {
+    bank: string
+    bankAccount: string
+    name: string
+    creditCode: string
+    address: string
+    tel: string
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface QccIndustryInfo {
+    AName: string
+    BName: string
+    CName: string
+    DName: string
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface EntGeoInfo {
+    longitude: string
+    latitude: string
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface EntProduct {
+    mongoId?: any
+    name: string
+    startDate: string
+    roundDesc: string
+    location: string
+    description: string
+  }
+  interface EntProductInfo {
+    products: EntProduct[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface EntPenalty {
+    id: string
+    punishDate: string
+    punishReason: string
+    punishResult: string
+    punishAmt: string
+    punishOffice: string
+    docNo: string
+  }
+  interface AdministrativePenaltyInfo {
+    penalties: EntPenalty[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface EntFreeze {
+    id: string
+    freezeStartDate: string
+    freezeEndDate: string
+    status: string
+    docNo: string
+    beExecuted: string
+    freezeCompany: string
+    equityAmount: string
+    executeCourt: string
+  }
+  interface EquityFreezeInfo {
+    freezes: EntFreeze[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface EmergingIndustrySecondaryList {
+    secondaryCode: string
+    secondaryDes: string
+    tertiaryList: any[]
+  }
+  interface EmergingIndustryModel {
+    primaryCode: string
+    primaryDes: string
+    secondaryList: EmergingIndustrySecondaryList[]
+  }
+  interface EmergingIndustryInfo {
+    models: EmergingIndustryModel[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface OriginalName {
+    name: string
+    changeDate: string
+  }
+  interface OriginalNameInfo {
+    originalNames: OriginalName[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface ActualController {
+    keyNo: string
+    name: string
+    finalBenefitPercent: string
+    controlPercent: string
+    isActual: string
+  }
+  interface ActualControllerInfo {
+    actualControllers: ActualController[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface EntTag {
+    type: string
+    name: string
+  }
+  interface EntTagInfo {
+    tags: EntTag[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface IndustryInfo {
+    industryCode: string
+    industry: string
+    subIndustryCode: string
+    subIndustry: string
+    middleCategoryCode: string
+    middleCategory: string
+    smallCategoryCode: string
+    smallCategory: string
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface EntBranchArea {
+    mongoId?: any
+    province: string
+    city: string
+    county: string
+  }
+  interface EntBranch {
+    keyNo: string
+    name: string
+    operName: string
+    startDate: string
+    status: string
+    area: EntBranchArea
+  }
+  interface EntBranchInfo {
+    branchs: EntBranch[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface EntGroupInfo {
+    groupId: string
+    name: string
+    logo: string
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface EntAreaInfo {
+    province: string
+    city: string
+    county: string
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface EntIndustry {
+    mongoId?: any
+    industryCode: string
+    industry: string
+    subIndustryCode: string
+    subIndustry: string
+    middleCategoryCode: string
+    middleCategory: string
+    smallCategoryCode: string
+    smallCategory: string
+  }
+  interface EntInvestmentArea {
+    mongoId?: any
+    province: string
+    city: string
+    county: string
+  }
+  interface EntInvestment {
+    keyNo: string
+    name: string
+    startDate: string
+    status: string
+    fundedRatio: string
+    shouldCapi: string
+    creditCode?: any
+    oper?: any
+    industry: EntIndustry
+    area: EntInvestmentArea
+  }
+  interface EntInvestmentInfo {
+    investments: EntInvestment[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface EntJudicialAction {
+    auctionTime: string
+    id: string
+    name: string
+    caseNo: string
+    executeGov: string
+  }
+  interface EntJudicialActionInfo {
+    judicialActions: EntJudicialAction[]
+    mongoId: string
+    lastUpdateTime: string
+  }
+  /** CreditRatingReportGradeInfo */
+  interface RatingModule {
+    ratingScore: number
+    shiXinScore: number
+    zhiXingScore: number
+    blacklistScore: number
+    severeAdminPenaltyScore: number
+    safetyHazardScore: number
+    breakOrderScore: number
+    generalAdminPenaltyScore: number
+    adminEnforceScore: number
+    otherShiXinScore: number
+    abnormalOperationScore: number
+    endLevelEvaluationScore: number
+    contractSXScore: number
+    businessSXScore: number
+    negativeOpinionScore: number
+    seniorStaffSXScore: number
+    operCriminalJudgmentScore: number
+    branchCreditScore: number
+  }
+  interface BusinessDevelop {
+    businessDevelopScore: number
+    branchNumScore: number
+    investmentNumScore: number
+  }
+  interface MarketActivity {
+    marketActivityScore: number
+    winBiddingNumScore: number
+    bidInvitingNumScore: number
+  }
+  interface IntegerellectualProperty {
+    brandNumScore: number
+    patentCopyrightNumScore: number
+    iprscore: number
+  }
+  interface CommunityActivity {
+    charitableGivingScore: number
+    volunteerNumScore: number
+    cascore: number
+  }
+  interface PovertyRelief {
+    disabledReemploymentScore: number
+    supportPRScore: number
+    prscore: number
+  }
+  interface TirdEvaluation {
+    tirdEvaluationScore: number
+    industryEvaluationScore: number
+    creditRatingScore: number
+  }
+  interface AdjustModule {
+    adjustScore: number
+    registcapiScore: number
+    operationTimeScore: number
+    eciChangeScore: number
+    businessDevelop: BusinessDevelop
+    marketActivity: MarketActivity
+    integerellectualProperty: IntegerellectualProperty
+    honourScore: number
+    redListScore: number
+    communityActivity: CommunityActivity
+    povertyRelief: PovertyRelief
+    tirdEvaluation: TirdEvaluation
+    qlicensingScore: number
+  }
+  interface CreditRatingReportGradeInfo {
+    level: string
+    score: string
+    ratingModule: RatingModule
+    adjustModule: AdjustModule
+    mongoId: string
+    lastUpdateTime: string
+  }
+  interface TaxArrearListItem {
+    taxpayerId: string
+    taxpayerName: string
+    declarationDate?: any
+    beginDate: string
+    endDate: string
+    collectionProjectName?: any
+    collectionItemsName: string
+    projectName: string
+    supplementTaxAmount: number
+    payMentDeadline: string
+    taxPaid?: any
+    taxType: string
+    taxStatus: string
+    taxBureau: string
+    authTime?: any
+    amountUnit?: string
+  }
+  /** 企业风控信息详情 */
+  type EntRiskControlDetail = {
+    modifiedTime: string
+    baseInfo?: BaseInfo
+    partnerInfo?: PartnerInfo
+    contactInfo?: ContactInfo
+    equityPledgeInfo?: EquityPledgeInfo
+    regCode: string
+    employeeInfo?: EmployeeInfo
+    registrationWebsiteInfo?: RegistrationWebsiteInfo
+    creditRatingReportGradeInfo?: CreditRatingReportGradeInfo
+    liquidationInfo?: any
+    changeInfo?: EntRiskChangeInfo
+    administrativeLicenseInfo?: AdministrativeLicenseInfo
+    taxIllegalInfo?: any
+    taxCreditRatingInfo?: TaxCreditRatingInfo
+    createdTime: string
+    bankInfo?: EntBankInfo
+    qccIndustryInfo?: QccIndustryInfo
+    geoInfo?: EntGeoInfo
+    abnormalOperationInfo?: any
+    chattelMortgageInfo?: any
+    productInfo?: EntProductInfo
+    pubPartnerInfo?: any
+    dishonestPersonInfo?: any
+    beneficiaryInfo?: any
+    sumptuaryInfo?: any
+    administrativePenaltyInfo?: AdministrativePenaltyInfo
+    equityFreezeInfo?: EquityFreezeInfo
+    emergingIndustryInfo?: EmergingIndustryInfo
+    bankruptcyInfo?: any
+    actualControllerInfo?: ActualControllerInfo
+    originalNameInfo?: OriginalNameInfo
+    industryInfo?: IndustryInfo
+    environmentalPenaltyInfo?: any
+    revokeInfo?: any
+    tagInfo?: EntTagInfo
+    branchInfo?: EntBranchInfo
+    modifiedBy: string
+    groupInfo?: EntGroupInfo
+    randomInspectionInfo?: any
+    enterpriseName: string
+    pubEmployeeInfo?: any
+    taxArrearsAnnouncementInfo?: any
+    relationId: string
+    parentCompanyInfo?: any
+    executedPersonInfo?: any
+    areaInfo?: EntAreaInfo
+    investmentInfo?: EntInvestmentInfo
+    stockInfo?: any
+    createdBy: string
+    judicialActionInfo?: EntJudicialActionInfo
+    seriousIllegalInfo?: any
+    standardName: string
+    processState: string
+    entType: string
+    entTypeName: string
+    taxCreditRating?: string
+    taxPenaltyList?: any[]
+    taxArrearList?: TaxArrearListItem[]
+    dishonestPersonList?: any[]
+    seriousIllegalList?: any[]
+  }
+
+  /** 以下为发票相关类型 */
+  /** 发票分页 */
+  type InvPageResultItem = {
+    modifiedTime: string
+    signature?: any
+    sellerName: string
+    buyerRegCode: string
+    invoiceState?: any
+    invoiceAmount: number
+    sellerAddress: string
+    stamped: boolean
+    vehicleMark: boolean
+    sellerTaxLevel: string
+    sellerBankInfo: string
+    buyerAddress: string
+    tollMark: boolean
+    qrInvNum: string
+    invoiceNumber: string
+    invoiceType: string
+    createdTime: string
+    modifiedBy: string
+    invoiceDetails: string
+    ossLink: string
+    invoicePayee: string
+    invoiceReviewer: string
+    invoicePrintNum: string
+    invoiceEncode: string
+    qrInvCode: string
+    invoiceOriginal: string
+    oilMark: boolean
+    invoiceIssuer: string
+    agentMark: boolean
+    buyerName: string
+    amountInWord: string
+    invoiceCode: string
+    checkCode?: any
+    billingDate: string
+    sellerRegCode: string
+    totalAmount: number
+    invoicePrintCode: string
+    invoiceProperty?: any
+    createdBy: string
+    machineNumber: string
+    buyerBankInfo: string
+    invoiceId: string
+    taxAmount: number
+    invoiceQr: string
+    remarks?: any
+    fileId: string
+    invoiceState: string
+  }
+  type InvPageResult = InvPageResultItem[]
+  /** 发票详情 */
+  interface InvoiceDetail {
+    name: string
+    content: string
+    description: string
+  }
+  interface VerifyHistories {
+    createdBy: string
+    modifiedBy: string
+    createdTime: string
+    modifiedTime: string
+    historyId: string
+    invoiceId: string
+    invoiceInfo: InvoiceInfo[]
+    invoiceDetails: [[InvoiceDetail[]]]
+    invoiceState: string
+  }
+  type InvDetailData = {
+    invoiceId: string
+    fileId: string
+    invoiceType: string
+    invoiceCode: string
+    invoiceNumber: string
+    billingDate: string
+    machineNumber?: any
+    buyerRegCode: string
+    sellerRegCode: string
+    invoiceAmount: number
+    taxAmount: number
+    totalAmount: number
+    checkCode: string
+    invoiceQr: string
+    invoiceEncode: string
+    buyerName: string
+    sellerName: string
+    amountInWord: string
+    buyerAddress: string
+    buyerBankInfo: string
+    sellerAddress: string
+    sellerBankInfo: string
+    invoicePayee: string
+    invoiceReviewer: string
+    invoiceIssuer: string
+    invoiceOriginal?: any
+    invoiceDetails: string
+    invoicePrintCode: string
+    invoicePrintNum: string
+    invoiceProperty?: any
+    qrInvCode: string
+    qrInvNum: string
+    stamped: boolean
+    vehicleMark: boolean
+    oilMark: boolean
+    agentMark: boolean
+    tollMark: boolean
+    signature: string
+    remarks?: any
+    delFlag: string
+    createdBy: string
+    modifiedBy: string
+    createdTime: string
+    modifiedTime: string
+    ossLink: string
+    verifyHistories?: VerifyHistories[]
+  }
+  /** 购买销售双方树 */
+  interface InvTargetTreeDataItem {
+    regCode: string
+    name: string
+    tenantId?: string
+    children: Omit<InvTargetTreeDataItem, 'children'>[]
+  }
+  type InvTargetTreeData = InvTargetTreeDataItem[]
+  /** 发票状态统计 */
+  type InvRiskStatResult = {
+    total: string
+    uncheck: string
+    normal: string
+    abnormal: string
+    revStat: string
+    allRevStat: string
+    partRevStat: string
+  }
+
+  // 以下为自主申报相关
+  interface DeclareSender {
+    senderName: string
+    senderEmail: string
+    senderPhone: string
+    senderAvatar: string
+  }
+  interface DeclareRecipient {
+    recipientEmail: string
+  }
+  interface DeclareListPageResultItem {
+    createdBy: string
+    modifiedBy: string
+    createdTime: string
+    modifiedTime: string
+    declarationId: string
+    declarationSn: string
+    enterpriseName: string
+    regCode: string
+    declarationType: string
+    url: string
+    secretKey: string
+    issueDate: string
+    expiryDate: string
+    declarationState: import('./enum').DeclState
+    openInfo?: any
+    submitInfo?: any
+    checkInfo?: any
+    formStruct?: any
+    declarationResult?: any
+    sender: DeclareSender
+    recipient: DeclareRecipient
+  }
+  type DeclareListPageResult = DeclareListPageResultItem[]
+
+  /** 创建申报模板入参 */
+  interface TmplItem {
+    checkRules?: { [key: string]: any }[]
+    itemDeli?: { [key: string]: any }[]
+    itemStruct?: API.WidgetParams
+    markResult?: { [key: string]: any }
+    weight?: number | string
+  }
+  type AddDeclTmplParams = {
+    /** 模板项 */
+    items: TmplItem[]
+    /** 模板名称 */
+    templateName: string
+    /** 模板版本,非手填 */
+    version: string
+    lockFlag: string
+    vendorType: string
+  }
+
+  type TmplStatusUpdateBody = {
+    templateId: string
+    lockFlag: string
+  }
+  /** 申报模板分页 */
+
+  interface DeclareTmplListPageResultItem {
+    createdBy: string
+    modifiedBy: string
+    createdTime: string
+    modifiedTime: string
+    templateId: string
+    templateName: string
+    version: string
+    items: TmplItem[]
+    lockFlag: string
+    delFlag: string
+    vendorType: string
+  }
+  type DeclareTmplListPageResult = DeclareTmplListPageResultItem[]
+
+  /** 申报模板列表结果 */
+  type DeclareTmplListResult = DeclareTmplListPageResultItem[]
+
+  /** 创建企业申报单入参 */
+
+  type AddEntDeclParams = {
+    /** 申报类型 */
+    declarationType: import('./enum').DeclarationType
+    /** 企业名称 */
+    enterpriseName: string
+    /** 申报开始时间,不能早于当天, yyyy-MM-dd */
+    issueDate: string
+    items: TmplItem[]
+    /** 申报周期,1, 3, 5, 7, 15 */
+    period: number
+    /** 收件人 */
+    recipientEmail?: string
+    /** 统一信用代码 */
+    regCode: string
+    /** 提取码 */
+    secretKey: string
+    parentId?: number | string
+    relationId: string
+  }
+
+  interface SendEmailParams {
+    /** 附件 */
+    attachment: { [key: string]: any }
+    /** 邮件内容,文本邮件必填 */
+    content?: string
+    templateName?: string
+    /** 发件人 */
+    emailType: import('./enum').EmailType
+    /** 主题 */
+    subject: string
+    /** 收件人 */
+    to: string[]
+  }
+
+  interface Recipient {
+    recipientEmail: string
+  }
+  interface SenderInfo {
+    senderAvatar: string
+    senderEmail: string
+    senderName: string
+    senderPhone: string
+  }
+  interface AddEntDeclResult {
+    createdTime: string
+    title: string
+    recipient: Recipient
+    deadline: string
+    url: string
+    secret: string
+    senderInfo: SenderInfo
+    suggestion: string
+  }
+
+  interface OpenDeclFormParams {
+    tId: string
+    declSn: string
+    secretKey: string
+  }
+  interface PayDetail {
+    reqSn: any
+    amount: string
+    orderState: string
+    paymentTime: any
+    issueTime: string
+    expireTime: string
+    payType: any
+    bizPayType: string
+  }
+  interface PaymentQrcodeInfo {
+    qrcodeBase64?: string
+    reqSn?: string
+    orderState?: string
+  }
+  interface PaymentPayResult {
+    reqSn: string
+    amount: string
+    orderState: string
+    paymentTime: string
+    issueTime: string
+    expireTime: string
+    payType: string
+    bizPayType: string
+  }
+  interface OpenDeclFormResult {
+    checkMsg: string
+    checkState: string
+    remarks: string
+    declarationId: string
+    declarationSn: string
+    enterpriseName: string
+    regCode: string
+    declarationType: string
+    url: string
+    secretKey: string
+    issueDate: string
+    expiryDate: string
+    declarationState: import('./enum').DeclState
+    openInfo: any
+    submitInfo: any
+    checkInfo: any
+    formItems: TmplItem[]
+    sender: SenderInfo
+    recipient: Recipient
+    tenantId: string
+    payDetail: PayDetail
+    rollbackRemark?: string
+    isTenantApplied: boolean
+  }
+  /** 提交申报入参 */
+  interface SubmitDeclFormParams {
+    /** 申报ID */
+    declarationId: number | string
+    /** 提交类型,最终提交:true, 否则:false */
+    finalSubmit: boolean
+    /** 申报项 */
+    items: TmplItem[]
+    /** 租户ID */
+    tenantId: number | string
+  }
+  interface ReviewItemConfigParams {
+    declSwitch: boolean
+    manualReviewSwitch: boolean
+    manualReviewRequired: boolean
+    admissionOpinionsSwitch: boolean
+    signRequired: boolean
+    remarks: string
+  }
+  type ReviewItemConfigResult = {
+    configId: string
+    delFlag: string
+    tenantId: string
+    createdBy: string
+    createdTime: string
+  } & ReviewItemConfigParams
+  /** 申报审核 */
+  interface DeclCheckParams {
+    declarationId: string | number
+    items: TmplItem[]
+  }
+
+  /** 企业申报的最新评分 */
+  interface DeclLastScoreResult {
+    createdBy: string
+    modifiedBy: string
+    createdTime: string
+    modifiedTime: string
+    declarationId: string
+    declarationSn: string
+    enterpriseName: string
+    regCode: string
+    declarationType: string
+    url: string
+    secretKey: string
+    issueDate: string
+    expiryDate: string
+    declarationState: import('./enum').DeclState
+    openInfo: any
+    submitInfo: any
+    checkInfo: any
+    formItems: TmplItem[]
+    sender: SenderInfo
+    recipient: Recipient
+  }
+
+  interface SupplierLevelMapItem {
+    level: string
+    desc: string
+    total: number
+    relId: string[]
+  }
+  interface RiskInfoStatDetailItem {
+    desc: string
+    itemLabel: string
+    total: number
+    relIds: string[]
+    title: string
+  }
+  interface RiskInfoStatDetail {
+    [key: string]: RiskInfoStatDetailItem
+  }
+
+  interface RiskInfoStatSummary {
+    [key: string]: number
+  }
+  interface RiskInfoStat {
+    taxRisk: RiskInfoStatDetail
+    enterpriseRisk: RiskInfoStatDetail
+    otherRisk: RiskInfoStatDetail
+    legalRepresentativeRisk: RiskInfoStatDetail
+    bizRisk: RiskInfoStatDetail
+    summary?: RiskInfoStatSummary
+    statEntTypeList: any
+    statList: any
+  }
+  interface SupplierLevelMap {
+    [key: string]: SupplierLevelMapItem
+  }
+  interface RiskInfoStatResult {
+    riskInfoStat: RiskInfoStat
+    supplierTaxLevelStat: SupplierLevelMap
+    entStat: any
+  }
+
+  interface RiskInfoDeclStatResult {
+    submitted: number
+    sum: number
+  }
+
+  /** 创建前端校验规则参数 */
+  interface AddRiskCheckParams {
+    ruleName: string
+    rules: RiskCheckRule[]
+  }
+
+  /** 前端校验规则列表 */
+  interface RiskCheckRule {
+    name: string
+    type: string
+    field: string
+    value: string
+    pattern: string
+  }
+  interface RiskCheckRuleListItem {
+    createdBy: string
+    modifiedBy: string
+    createdTime: string
+    modifiedTime: string
+    ruleId: string
+    ruleName: string
+    rules: RiskCheckRule[]
+  }
+  type RiskCheckRuleList = RiskCheckRuleListItem[]
+
+  type RiskCheckRulePageResult = RiskCheckRuleListItem[]
+
+  /** 企业风险信息校验入参(手动) */
+  interface EntRiskInfoCheckParams {
+    relationId: number | string
+    regCode: string
+    enterpriseName: string
+    standardName: string
+  }
+
+  interface EntRiskCheckItemListItem {
+    createdBy: string
+    modifiedBy: string
+    createdTime: string
+    modifiedTime: string
+    itemId: string
+    checkId: string
+    itemName: string
+    description: string
+    checkType: string
+    actualValue: string
+    targetValue: string
+    logicType: string
+    autoResult: boolean
+    autoMsg: string
+    manualResult?: any
+    manualMsg?: any
+    remarks?: any
+    score: string
+    autoScore: string
+    manualScore: string
+  }
+
+  interface EntRiskCheckDetailsDecl {
+    recipient: {
+      recipientEmail: string
+    }
+    checkbox: { [key: string]: string }
+    declType: string
+    tmplLabelMap: { [key: string]: string }
+    parentId: string
+  }
+  interface EntRiskCheckDetails {
+    createdTime: string
+    checkId: string
+    checkState: string
+    decl: EntRiskCheckDetailsDecl
+    items: EntRiskCheckItemListItem[]
+    relationId: string
+    relationRefreshTime: string
+    remarks: string
+    reportUrl: string
+    ruleName: string
+    signedBy: string
+    stat: {
+      noInfoItemCount: number
+      riskItemCount: number
+    }
+  }
+
+  interface EntRiskCheckDetailsV2ItemList {
+    itemId: string
+    checkId: string
+    itemLabel: string
+    itemName: string
+    description: string
+    checkType: string
+    actualValue: string
+    targetValue: string
+    logicType: string
+    autoResult: boolean
+    autoMsg: string
+    manualResult: boolean
+    manualMsg: string
+    score: string
+    autoScore: string
+    manualScore: string
+    remarks?: any
+    actualValueType?: any
+    scoreFlag: boolean
+    valueType: 'TABLE' | 'PDF' | 'IMG'
+  }
+  interface EntRiskCheckDetailsV2DetailList {
+    categoryName: string
+    categoryLabel: string
+    scoreFlag: boolean
+    cktFlag: boolean
+    score: string
+    manualScore: string
+    cktFlag: boolean
+    cktRequiredFlag: boolean
+    cktMsg: string
+    cktReview: string
+    categoryId: string
+    itemList: EntRiskCheckDetailsV2ItemList[]
+  }
+  interface EntRiskCheckDetailsV2Stat {
+    noInfoItemCount: number
+    riskItemCount: number
+  }
+  interface EntRiskCheckDetailsV2Recipient {
+    recipientEmail: string
+  }
+  interface EntRiskCheckDetailsV2Checkbox {
+    biz_scope_risk: string
+    employee_risk: string
+    tax_level_error: string
+  }
+  interface EntRiskCheckDetailsV2TmplLabelMap {
+    biz_scope_risk: string
+    scan_shell_error: string
+    same_person_error: string
+    legal_repr_risk: string
+    biz_term_risk: string
+    dishonest_person_error: string
+    ent_state_risk: string
+    same_tel_error: string
+    serious_illegal_error: string
+    tax_error: string
+    same_addr_error: string
+    employee_risk: string
+    ent_addr_error: string
+    ann_biz_error: string
+    biz_error: string
+    ent_type_risk: string
+    ent_name_risk: string
+    admin_error: string
+    reg_capital_risk: string
+    tax_level_error: string
+  }
+  interface EntRiskCheckDetailsV2Decl {
+    recipient: EntRiskCheckDetailsV2Recipient
+    checkbox: EntRiskCheckDetailsV2Checkbox
+    declType: string
+    tmplLabelMap: EntRiskCheckDetailsV2TmplLabelMap
+    parentId: string
+  }
+  interface EntRiskCheckDetailsV2 {
+    plusVersion: string
+    checkId: string
+    relationId: string
+    checkState: string
+    relationRefreshTime: string
+    reportUrl: string
+    signedBy: string
+    remarks: string
+    createdTime: string
+    ruleName: string
+    detailList: EntRiskCheckDetailsV2DetailList[]
+    stat: EntRiskCheckDetailsV2Stat
+    decl: EntRiskCheckDetailsV2Decl
+  }
+
+  interface EntRiskInfoCheckAssertParams {
+    /** 校验ID */
+    checkId: number | string
+    /** 校验结果 */
+    checkMsg: string
+    /** 断言状态 */
+    checkState: string
+    /** 企业名称 */
+    entName: string
+    /** 备注信息 */
+    remarks: string
+    /** 签名 */
+    signedBy: string
+    relationId: string
+  }
+
+  interface EntRiskInfoCheckItemAssertParams {
+    itemId: number | string
+    manualResult: boolean
+    manualMsg: string
+    manualScore: string | number
+  }
+
+  interface EntRiskInfoCheckRedoParams {
+    relationId: string
+    regCode: string
+    forceRefresh: boolean
+  }
+
+  interface RiskItemListItem {
+    actualValue: string
+    criterion: string
+    entName: string
+    checkTime: string
+    autoResult: boolean
+    manualResult: any
+    manualMsg: any
+    autoMsg: string
+    relationId: string
+    checkId?: string
+  }
+  type RiskItemList = RiskItemListItem[]
+
+  interface RiskItemListItem {
+    departmentName: string
+    number: string
+    penaltyData: string
+  }
+  type PenaltyInfoList = RiskItemListItem[]
+
+  interface StatListItem {
+    count: number
+    type: string
+    name: string
+  }
+  interface FinancialTaxRiskStatResult {
+    statList: StatListItem[]
+    summary?: RiskInfoStatSummary
+  }
+
+  interface FinancialTaxAuthPageParams {
+    entName?: string
+    checkState?: string
+    authState?: string
+    authTimes?: string[]
+  }
+  interface FinancialTaxAuthPageResultItem {
+    entName: string
+    regCode: string
+    checkState: string
+    checkStateName: string
+    authState: string
+    authStateName: string
+    authTime: string
+    emailNotifyTime?: any
+    email?: string
+  }
+
+  type FinancialTaxAuthPageResult = FinancialTaxAuthPageResultItem[]
+
+  interface FinancialTaxAuthUrlParams {
+    entName?: string
+    regCode?: string
+    tenantId?: string | number
+    cburl?: string
+  }
+
+  interface FinancialTaxAuthUrlResult {
+    cburl: string
+    orderNo: string
+    message: string
+    fullUrl: string
+    authEndpoint: string
+    channelCode: string
+  }
+  interface FinancialTaxAuthSendEmailParams {
+    regCode: string
+    email: string
+  }
+  interface FinancialTaxAuthBatchSendEmailParams {
+    regCodes: string[]
+    refresh: boolean
+  }
+  interface FinancialTaxAuthBatchSendEmailResult {
+    no_email: number
+    send_success: number
+    send_fail: number
+  }
+
+  interface SameInvoiceAddressPageResultItem {
+    entName: string
+    authTime: string
+    address: string
+  }
+  type SameInvoiceAddressPageResult = SameInvoiceAddressPageResultItem[]
+  interface AbnormalBusinessPageResultItem {}
+  type AbnormalBusinessPageResult = AbnormalBusinessPageResultItem[]
+  interface InvoiceWithSameIndustryPageResultItem {}
+  type InvoiceWithSameIndustryPageResult = InvoiceWithSameIndustryPageResultItem[]
+  interface InvoiceWithSameEntPageResultItem {}
+  type InvoiceWithSameEntPageResult = InvoiceWithSameEntPageResultItem[]
+  interface LessPeopleHighInvoicePageResultItem {}
+  type LessPeopleHighInvoicePageResult = LessPeopleHighInvoicePageResultItem[]
+  interface TaxArrearsPageResultItem {}
+  type TaxArrearsPageResult = TaxArrearsPageResultItem[]
+  interface TaxAuditsPageResultItem {}
+  type TaxAuditsPageResult = TaxAuditsPageResultItem[]
+  interface TaxViolationsPageResultItem {}
+  type TaxViolationsPageResult = TaxViolationsPageResultItem[]
+
+  interface TaxRiskDetailGradeCount {
+    highRisk: number
+    lowRisk: number
+    mediumRisk: number
+  }
+  interface TaxRiskDetailRiskAsses {
+    grade: string
+    firstRisk: string
+    secondRisk: string
+  }
+  interface TaxRiskDetailRiskSummaryItem {
+    riskCount: number
+    riskLevel: string
+  }
+  interface TaxRiskDetailRiskSummary {
+    financeRisk: TaxRiskDetailRiskSummaryItem
+    taxRisk: TaxRiskDetailRiskSummaryItem
+    fpRisk: TaxRiskDetailRiskSummaryItem
+  }
+  interface TaxRiskDetailAllRiskScan {
+    backEndFieldName: string
+    frontEndFieldName: string
+    result: string
+  }
+  interface TaxRiskDetailResult {
+    gradeCount: TaxRiskDetailGradeCount
+    riskAssess: TaxRiskDetailRiskAsses[]
+    overviewHint: string
+    riskSummary: TaxRiskDetailRiskSummary
+    periodStart: string
+    periodEnd: string
+    allRiskScan: TaxRiskDetailAllRiskScan[]
+  }
+  interface EntListByKeyResultItem {
+    entName: string
+    regCode: string
+    tenantId?: string
+  }
+  type EntListByKeyResult = EntListByKeyResultItem[]
+
+  interface PlusCheckReportResult {
+    status: 'NOT_GENERATE' | 'GENERATING' | 'GENERATED' | 'ERROR'
+    latestUrl?: string
+    ttl?: string
+    createTime?: string
+    errorMsg?: string
+  }
+
+  interface ConfigIndicatorPageResultItem {
+    standardId: string
+    relationId: string
+    standardName: string
+    entType: string
+    usageSceneType: string
+    state: string
+    remarks?: any
+    delFlag: string
+    publishTime: string
+    deptList: string[]
+  }
+  type ConfigIndicatorPageResult = ConfigIndicatorPageResultItem[]
+  interface StandardIndicatorDetailListItem {
+    itemId: string
+    standardId: string
+    itemLabel: string
+    itemName: string
+    itemTypes: string[]
+    itemDesc: string
+    itemBrief: string
+    checkType: string
+    standardType: string
+    categoryType: string
+    checkFlag: boolean
+    logicType: string
+    tarVal: string
+    score: string
+    remarks?: any
+    fineRule: StandardIndicatorPlatformItemFineRule
+  }
+  interface StandardIndicatorDetailList {
+    categoryId: string
+    standardId: string
+    relationId: string
+    categoryName: string
+    categoryLabel: string
+    scoreFlag: boolean
+    cktFlag: boolean
+    cktRequiredFlag: boolean
+    score: string
+    itemList: StandardIndicatorDetailListItem[]
+  }
+  interface StandardIndicatorDetailData {
+    standardId: string
+    relationId?: any
+    standardName: string
+    state: string
+    entType: string
+    usageSceneType: string
+    publishTime: string
+    deptList: string[]
+    categoryList: string[]
+    detailList: StandardIndicatorDetailList[]
+  }
+
+  interface EntRiskCheckFinancialDetailItem {
+    createdBy: string
+    modifiedBy: string
+    createdTime: string
+    modifiedTime: string
+    itemId: string
+    checkId: string
+    itemLabel: string
+    itemName: string
+    description: string
+    checkType: string
+    actualValue: string
+    targetValue?: any
+    logicType: string
+    autoResult: boolean
+    autoMsg: string
+    manualResult?: any
+    manualMsg?: any
+    score: string
+    autoScore: string
+    manualScore?: any
+    remarks?: any
+    delFlag: string
+    actualValueType: 'importantFinancialData' | 'financialDataOne' | 'financialDataTwo'
+  }
+  type EntRiskCheckFinancialDetail = EntRiskCheckFinancialDetailItem[]
+
+  interface EntRiskCheckFinancialAssertDetail {
+    manualScore?: any
+    review: string
+    financialDataTwo: string[]
+    manualMsg?: any
+    financialDataOne: string[]
+    importantFinancialData: string[]
+    score?: string
+  }
+
+  interface EntRiskCheckFinancialAssertParams {
+    relationId: number | string
+    manualScore: number | string
+    manualMsg: string
+    review: string
+  }
+
+  interface EntRiskInfoCheckCategroyAssertParams {
+    categoryId: string
+    cktReview: string
+    cktMsg: string
+  }
+  interface EntRiskInfoCheckMetaResult {
+    checkId: string
+    relationId: string
+    checkState: string
+    checkTime: string
+    relationRefreshTime: string
+    reportUrl: string
+    signedBy: string
+    advice: string
+    remarks: string
+    review?: any
+    standardId: string
+  }
+
+  interface CreateStandardIndicatorParams {
+    entType: string
+    usageSceneType: string
+    standardName: string
+    remarks: string
+    deptList: (string | number)[]
+    weight: number
+  }
+
+  interface StandardIndicatorDetailItem {
+    categoryName: string
+    categoryLabel: string
+    scoreFlag: boolean
+    cktFlag: boolean
+    cktRequiredFlag: boolean
+    score: string
+    itemList: StandardIndicatorDetailListItem[]
+  }
+  interface UpdateStandardIndicatorParams {
+    standardId: string
+    entType: string
+    usageSceneType: string
+    standardName: string
+    remarks?: string
+    deptList: string[]
+    weight?: number
+    categoryList: string[]
+    detailList: StandardIndicatorDetailItem[]
+  }
+
+  interface StandardIndicatorPlatformItemRuleItem {
+    itemType: string
+    ruleType: string
+    rule: string | string[]
+    targetScore: number | string
+    targetStatus: 'PASS' | 'FAIL'
+    logicType: string
+    nanoId?: string | number
+    unitType: Nullable<string>
+    dataType: Nullable<string>
+  }
+  interface StandardIndicatorPlatformItemFineRule {
+    logicToValueRuleMap: Nullable<
+      Record<
+        string,
+        {
+          decimalPlacesNumber: number
+          dataTypeEnable: string[]
+          dataTypeDict: any[]
+          unitType: string
+          min: Nullable<number>
+          max: Nullable<number>
+        }
+      >
+    >
+    logicTypeEnable: Nullable<string[]>
+    ruleItems: StandardIndicatorPlatformItemRuleItem[]
+  }
+  interface StandardIndicatorPlatformItemItemList {
+    itemId: string
+    standardId?: any
+    itemLabel: string
+    itemName: string
+    itemBrief: string
+    itemDesc: string
+    checkType: string
+    entType: string
+    standardType: string
+    categoryType: string
+    checkFlag: boolean
+    logicType: string
+    tarVal: string
+    score: string
+    remarks?: any
+    fineRule: StandardIndicatorPlatformItemFineRule
+    scoreFlag?: any
+  }
+
+  interface StandardIndicatorPlatformItem {
+    categoryName: string
+    categoryLabel: string
+    itemList: StandardIndicatorPlatformItemItemList[]
+  }
+  type StandardIndicatorPlatformItemList = StandardIndicatorPlatformItem[]
+  interface DeptRelatedStandardListResultItem {}
+  type DeptRelatedStandardListResult = Record<string, string[]>
+
+  interface IRuleRecordPageListItem {
+    itemId: string
+    platformItemId: string
+    regCode: string
+    entName: string
+    itemLabel: string
+    itemName: string
+    itemGroup: string
+    riskLevelName: string
+    itemGroupName: string
+    riskLevel: string
+    content: string
+    result: boolean
+    changeData?: any
+    changeNum: number
+    createdTime: string
+    fineRule: string
+  }
+
+  interface INotifyRecordPageListItem {
+    createTime: string
+    frequency: string
+    frequencyName: string
+    riskLevel: string
+    riskLevelName: string
+    content?: any
+    notificationWay?: any
+    notificationScope: string
+  }
+}

+ 29 - 0
src/api/services/riskcontrol/declare.ts

@@ -0,0 +1,29 @@
+import Request from '../..'
+
+/**
+ * 申报记录 - 用户申报
+ */
+
+// 打开申报单
+export function openDeclForm(data: API.OpenDeclFormParams) {
+  return Request.post<API.OpenDeclFormResult>({
+    url: '/cms/ent/risk/info/decl/form',
+    params: data
+  })
+}
+
+export interface ITenantApplyInfo {
+  declId?: any
+  regCode: string
+  tenantName: string
+  username: string
+  passwordHint: string
+  status: string
+}
+// 查询创建租户申请
+export function getTenantApply(query: { declId: string; regCode: string }) {
+  return Request.get<ITenantApplyInfo>({
+    url: '/cms/ent/risk/info/decl/tenant/apply',
+    params: query
+  })
+}

+ 61 - 0
src/api/services/riskcontrol/enum.ts

@@ -0,0 +1,61 @@
+/** 是否小微企业 */
+export enum EntIsSamll {
+  '不是' = 0,
+  '是' = 1
+}
+export enum EntType {
+  '大陆企业' = 0,
+  '社会组织' = 1,
+  '中国香港公司' = 3,
+  '事业单位' = 4,
+  '中国台湾公司' = 5,
+  '医院' = 7,
+  '海外' = 8
+}
+/** 企业规模 */
+export enum EntScale {
+  L = '大型',
+  M = '中型',
+  S = '小型',
+  XS = '微型'
+}
+/** 英文名来源 */
+export enum EntIsOfficialEndlish {
+  '官方标识' = 1,
+  '非官方表示' = 0,
+  '未标识' = -1
+}
+/** 申报类型 */
+export enum DeclarationType {
+  Self = 'SELF'
+}
+/** 发件人 */
+export enum EmailType {
+  // 文本邮件
+  Emal = 'EMAL',
+  // 富文本邮件
+  MIMEEmail = 'MIME_EMAIL',
+  // 模板邮件
+  TmplEmail = 'TMPL_EMAIL'
+}
+/** 申报单状态 */
+export enum DeclState {
+  // 未读
+  UNREAD = 'UNREAD',
+  // 已读
+  READ = 'READ',
+  // 已提交
+  SUBMITTED = 'SUBMITTED',
+  // 已查验
+  CHECKED = 'CHECKED',
+  // 已退回
+  ROLLBACK = 'ROLLBACK'
+}
+
+export enum DeclStateText {
+  UNREAD = '未读',
+  READ = '已读',
+  SUBMITTED = '已提交',
+  CHECKED = '已查验',
+  ROLLBACK = '已退回'
+}

+ 287 - 0
src/api/services/task/data.d.ts

@@ -0,0 +1,287 @@
+declare namespace API {
+  /** 新增组件入参 */
+  type FDComAlign = 'LEFT' | 'CENTER' | 'RIGHT'
+  type FDComPosition = 'LEFT' | 'TOP'
+  type FDDeaultValueFormat = 'PLAIN' | 'JSON' | 'XML'
+  type FDValidItem = {
+    expression: {
+      body: string
+      modifier: string
+    }
+    format: string
+    message: string
+  }
+  /** 每个组件的expand参数 */
+  type FD_EXPAND_INPUT = {
+    /** 前缀 */
+    prefix: string
+    /** 后缀 */
+    suffix: string
+    /** 最大字符数 */
+    maxChars: string
+    /** 前缀icon */
+    fIcon: string
+    /** 后缀icon */
+    bIcon: string
+    limitVisible: boolean
+  }
+  type FD_EXPAND_AMOUNT_INPUT = FD_EXPAND_INPUT & {
+    /** 单位 */
+    unit: string
+    /** 输入数字类型 */
+    numberType: string
+    /** 货币类型 */
+    // currencyType: string
+    /** 小数点位数 */
+    decimalPlacesNumber: number | undefined
+    /** 最小值 */
+    min: number | undefined
+    /** 最大值 */
+    max: number | undefined
+  }
+  type FD_EXPAND_NUMBER_INPUT = FD_EXPAND_INPUT & {
+    /** 输入功能类型 */
+    featureType: 'NUMBER' | 'PERCENT'
+    /** 单位 */
+    unit: string
+    /** 输入数字类型 */
+    numberType: string
+    /** 货币类型 */
+    // currencyType: string
+    /** 小数点位数 */
+    decimalPlacesNumber: number | undefined
+    /** 最小值 */
+    min: number | undefined
+    /** 最大值 */
+    max: number | undefined
+  }
+  type FD_EXPAND_RADIO = {
+    /** 数据来源类型: 用户输入/数据字典 */
+    sourceType: 'USER_INPUT' | 'DICT'
+    /** 用户输入内容 */
+    userInput: { label: string; value: string; nanoid: string }[]
+  }
+  type FD_EXPAND_SELECT = {
+    /** 数据来源类型: 用户输入/数据字典 */
+    sourceType: 'USER_INPUT' | 'DICT'
+    /** 用户输入内容 */
+    userInput: { label: string; value: string; nanoid: string }[]
+    multiple: boolean
+  }
+  type FD_EXPAND_OBJECT_PICKER = {
+    label: string
+    value: string
+    child: string
+    level: number
+    animateLoading: boolean
+  }
+  type FD_EXPAND_FILE_PICKER = {
+    accept?: string
+    multiAcceptList: string[]
+    fileSize: number
+    sizeUnit: string
+    listType: string
+    btnText: string
+    showTip: boolean
+    multiple: boolean
+    limit: number
+    requiredLimit: number
+    animateLoading: boolean
+    hasTemplate: boolean
+    templateTip: string
+    templateList: any[]
+  }
+  type FD_EXPAND_DATETIME_PICKER = {
+    dateType: string
+    format: string
+    periodStart: string
+    periodEnd: string
+  }
+  type FD_EXPAND_TIME_PICKER = {
+    format: string
+    periodStart: string
+    periodEnd: string
+  }
+  type FD_EXPAND_INPUT_MAP = {
+    /** false:可选地点 true:不可能选地点, 只能打卡 */
+    fixed: boolean
+    centre: {
+      site: Nullable<string>
+      longitude: Nullable<string>
+      latitude: Nullable<string>
+      cityCode: Nullable<string>
+      addressCode: Nullable<string>
+    }
+    distance: number
+    periodStart: string
+    periodEnd: string
+  }
+  type FD_EXPAND_BUTTON = {
+    /** 按钮类型 */
+    type: any
+    /** 按钮文字 */
+    text: string
+    /** 按钮大小 */
+    size: string
+  }
+  type FD_EXPAND_TITLE = {
+    /** 标题 */
+    title: string
+    /** 描述 */
+    desc: string
+  }
+  interface FD_COM {
+    INPUT: API.FD_EXPAND_INPUT
+    AMOUNT_INPUT: API.FD_EXPAND_AMOUNT_INPUT
+    NUMBER_INPUT: API.FD_EXPAND_NUMBER_INPUT
+    RADIO: API.FD_EXPAND_RADIO
+    SELECT: API.FD_EXPAND_SELECT
+    OBJECT_PICKER: API.FD_EXPAND_OBJECT_PICKER
+    FILE_PICKER: API.FD_EXPAND_FILE_PICKER
+    DATETIME_PICKER: API.FD_EXPAND_DATETIME_PICKER
+    TIME_PICKER: API.FD_EXPAND_TIME_PICKER
+    INPUT_MAP: API.FD_EXPAND_INPUT_MAP
+    BUTTON: API.FD_EXPAND_BUTTON
+    TITLE: API.FD_EXPAND_TITLE
+  }
+  type FD_EXPAND_INVOICE_PICKER = API.FD_EXPAND_FILE_PICKER & {
+    /** 发票识别 */
+    recognize: boolean
+    /** 发票验真 */
+    check: boolean
+  }
+  interface FD_COM_ENHANCE {
+    INVOICE_PICKER: API.FD_EXPAND_INVOICE_PICKER
+  }
+  type FD_EXPAND_FINANCE_PICKER = API.FD_EXPAND_FILE_PICKER & {
+    /** 填写形式 */
+    fillType: string
+    /** 文件解析类型 */
+    fileParserType: string
+    /** 是否开启解析 */
+    enableParse: boolean
+  }
+  interface FD_COM_ENHANCE {
+    FINANCE_PICKER: FD_EXPAND_FINANCE_PICKER
+  }
+
+  interface FDEventParams {
+    runCode: Nullable<string>
+    pluginId: Nullable<string>
+    plugin?: Nullable<FD_Plugin>
+    toastContent?: Nullable<string>
+    toUrl?: Nullable<string>
+  }
+  interface FD_Header {
+    key: string
+    val: string
+  }
+  interface FD_QueryParameter {
+    key: string
+    val: string
+  }
+
+  interface FD_ActionConfiguration {
+    body: string
+    path: string
+    headers: FD_Header[]
+    httpMethod: string
+    bodyFormData: any[]
+    formDataType?: any
+    queryParameters: FD_QueryParameter[]
+  }
+  interface FD_Plugin {
+    pluginId: string
+    pluginType: string
+    label: string
+    actionConfiguration: FD_ActionConfiguration
+    datasource?: any
+  }
+
+  type FDDynamicTriggersItem = {
+    eventType?: string
+    runCode: Nullable<string>
+    pluginId: Nullable<string>
+    toastContent?: string
+    onSuccess: Nullable<FDEventParams> & Nullable<{ apiResult?: any }>
+    onError: Nullable<FDEventParams>
+    plugin?: Nullable<FD_Plugin>
+  }
+  type FDDynamicTriggers = {
+    [formId: string]: {
+      [eventType: string]: FDDynamicTriggersItem
+    }
+  }
+
+  type WidgetParams = {
+    categoryId: string
+    tenantId: string
+    formId: string
+    type: string
+    label: {
+      text: string
+      align: FDComAlign
+      position: FDComPosition
+      visible: boolean
+    }
+    desc: string
+    visible: boolean
+    defaultValue: {
+      format: FDesignDeaultValueFormat
+      value: string
+    }
+    score?: number | string
+    required: boolean
+    placeholder: string
+    span: number
+    valid: FDValidItem[]
+    expand?:
+      | FD_COM['INPUT']
+      | FD_COM['OBJECT_PICKER']
+      | FD_COM['FILE_PICKER']
+      | FD_COM['DATETIME_PICKER']
+      | FD_COM['TIME_PICKER']
+      | FD_COM['INPUT_MAP']
+      | FD_COM['BUTTON']
+      | Record<string, any>
+    weight?: string
+    widgetId?: string
+    dynamicTriggers?: FDDynamicTriggersItem[]
+  }
+  type AddWidgetParams = Omit<WidgetParams, 'weight' | 'widgetId' | 'dynamicTriggers'>
+  /** 新增组件返回结果 */
+  type AddWidgetResult = {
+    weight: string
+    widgetId: string
+    success: boolean
+  }
+  /** 组件列表 */
+  type WidgetList = WidgetParams[]
+
+  /** 分类树 */
+  type CategoryTreeItem = {
+    id: string
+    parentId: string
+    weight: number
+    name: string
+    value: string
+    children: CategoryTreeItem[]
+  }
+  type CategoryTree = CategoryTreeItem[]
+
+  type Category = {
+    categoryId: string
+    categoryName: string
+    gigType: string
+    parentId: string
+    weight: number
+    categoryValue: string
+  }
+
+  /** 组件排序入参 */
+  type WidgetSortParams = {
+    widgetId: string
+    beforePosition: string
+    afterPosition: string
+  }
+}

+ 89 - 0
src/api/services/task/formDesigner.ts

@@ -0,0 +1,89 @@
+import Request from '../..'
+
+// 获取分类树
+export function getCategoryTree(data: any) {
+  return Request.get<API.CategoryTree>({
+    url: '/ware/category/tree',
+    params: data
+  })
+}
+
+// 增加分类
+export function addFormCategory(data: any) {
+  return Request.post<API.Category>({
+    url: '/ware/category/form/create',
+    data: data
+  })
+}
+
+// 获取租户分类组件列表
+export function getWidgetList(data: any) {
+  return Request.get<API.WidgetList>({
+    url: '/ware/widget/list',
+    params: data
+  })
+}
+
+// 创建分类组件
+export function addWidget(data: API.AddWidgetParams) {
+  return Request.post<API.AddWidgetResult>({
+    url: '/ware/widget/create',
+    data
+  })
+}
+
+// 更新分类组件
+export function updateWidget(data: any) {
+  return Request.post({
+    url: '/ware/widget/update',
+    data
+  })
+}
+
+// 删除组件
+export function deleteWidget(widgetId: number | string) {
+  return Request.post({
+    url: '/ware/widget/del',
+    data: { widgetId, deleteType: 'SOFT' }
+  })
+}
+
+// 组件排序
+export function widgetSort(data: API.WidgetSortParams) {
+  return Request.post({
+    url: '/ware/widget/sort',
+    data
+  })
+}
+
+// 获取插件列表
+export function getPluginList(data: any) {
+  return Request.get({
+    url: '/ware/plugin/list',
+    params: data
+  })
+}
+
+// 创建插件
+export function addPlugin(data: any) {
+  return Request.post({
+    url: '/ware/plugin/create',
+    data
+  })
+}
+
+// 更新插件信息
+export function updatePlugin(data: any) {
+  return Request.put({
+    url: '/ware/plugin',
+    method: 'put',
+    data
+  })
+}
+
+// 删除插件
+export function deletePlugin(pluginId: number) {
+  return Request.delete({
+    url: `/ware/plugin/${pluginId}`
+  })
+}

BIN
src/assets/images/qrcode/wechat_qrcode.png


+ 25 - 0
src/components/formParse/constants/orderState.ts

@@ -0,0 +1,25 @@
+export const orderStateMap = {
+  '-': '未支付',
+  '0000': '交易成功',
+  '1001': '交易不存在',
+  // 如果是实时交易(例如刷卡支付,交易撤销,退货),建议每隔一段时间(10秒)查询交易
+  '2008': '交易处理中,请查询交易',
+  // 如果是实时交易(例如刷卡支付,交易撤销,退货),建议每隔一段时间(10秒)查询交易
+  '2000': '交易处理中,请查询交易',
+  // 3开头的错误码代表交易失败
+  '3888': '流水号重复',
+  '3889': '交易控制失败,具体原因看errmsg',
+  '3099': '渠道商户错误',
+  '3014': '交易金额小于应收手续费',
+  '3031': '校验实名信息失败',
+  '3088': '交易未支付(在查询时间区间内未成功支付,如已影响资金24小时内会做差错退款处理)',
+  '3089': '撤销异常,如已影响资金24小时内会做差错退款处理',
+  '3045': '其他错误,具体原因看errmsg',
+  '3050': '交易已被撤销',
+  '3999': '其他错误,具体原因看errmsg'
+}
+
+export enum PayType {
+  W01 = '微信扫码支付',
+  A01 = '支付宝扫码支付'
+}

+ 135 - 0
src/components/formParse/index.tsx

@@ -0,0 +1,135 @@
+import { forwardRef, memo, useImperativeHandle, useState } from 'react'
+import { cloneDeep } from 'lodash-es'
+import { getTenantApply, ITenantApplyInfo } from '@/api/services/riskcontrol/declare'
+import { orderStateMap } from './constants/orderState'
+
+export interface FormParseRef {}
+
+interface FormParseProps {
+  declFormData: Nullable<API.OpenDeclFormResult>
+  formData: Record<string, any>
+  formRule?: any
+  disabled?: boolean
+  state?: string
+  expiry?: string
+  isExpiry?: boolean
+  className?: string
+}
+
+const checkStateMap = {
+  PASSED: '通过',
+  REJECTED: '拒绝',
+  TO_RECT: '整改'
+}
+
+const FormParse = memo(
+  forwardRef<FormParseRef, FormParseProps>(
+    ({ declFormData, formData, formRule, disabled, state, expiry, isExpiry }, ref) => {
+      console.log(formData)
+      console.log(formRule)
+      console.log(disabled)
+      // 对外暴露方法
+      useImperativeHandle(ref, () => {
+        return {}
+      })
+
+      const formItemsCopy = cloneDeep(declFormData?.formItems)
+      console.log(formItemsCopy)
+
+      const [showViewPayInfoDialog, setShowViewPayInfoDialog] = useState(false)
+      console.log(showViewPayInfoDialog)
+      const [payInfo, setPayInfo] = useState<Partial<API.PayDetail>>({
+        reqSn: '',
+        amount: '',
+        orderState: '',
+        paymentTime: '',
+        issueTime: '',
+        expireTime: '',
+        payType: ''
+      })
+      console.log(payInfo)
+      const viewPayInfoDialog = () => {
+        setPayInfo(declFormData!.payDetail)
+        setShowViewPayInfoDialog(true)
+      }
+
+      const [tennantInfo, setTennantInfo] = useState<Partial<ITenantApplyInfo>>()
+      console.log(tennantInfo)
+      const [showAccountDialog, setShowAccountDialog] = useState(false)
+      console.log(showAccountDialog)
+      const viewAccountInfoDialog = async () => {
+        const res = await getTenantApply({
+          declId: declFormData!.declarationId,
+          regCode: declFormData!.regCode
+        })
+        if (res?.code === '2000') {
+          setTennantInfo(res.data)
+          setShowAccountDialog(true)
+        }
+      }
+
+      return (
+        <div>
+          {state && (
+            <div className='text-[14px] pl-[12px] mb-[8px] text-text-secondary f-b-c'>
+              <div>
+                <span>
+                  {typeof isExpiry === 'boolean'
+                    ? isExpiry
+                      ? '已结束'
+                      : `有效期至:${expiry}`
+                    : ''}
+                </span>
+                <span className='ml-[20px]'>填报状态:{state}</span>
+                {declFormData?.declarationState === 'ROLLBACK' && (
+                  <span className='ml-[20px]'>退回原因:{declFormData?.rollbackRemark}</span>
+                )}
+              </div>
+              <div className='flex'>
+                {declFormData?.payDetail?.bizPayType === 'HYBRID_PAID' && (
+                  <div>
+                    <span>
+                      准入管理费支付状态:
+                      {
+                        orderStateMap[
+                          declFormData?.payDetail?.orderState as keyof typeof orderStateMap
+                        ]
+                      }
+                    </span>
+                    <span
+                      className='text-primary ml-[6px] cursor-pointer'
+                      onClick={viewPayInfoDialog}>
+                      详情
+                    </span>
+                  </div>
+                )}
+                {declFormData?.isTenantApplied && (
+                  <div className='ml-[16px]'>
+                    <span>登录账号:</span>
+                    <span
+                      className='text-primary ml-[6px] cursor-pointer'
+                      onClick={viewAccountInfoDialog}>
+                      查看
+                    </span>
+                  </div>
+                )}
+              </div>
+            </div>
+          )}
+          <div className='mb-[12px] text-[14px] text-text-secondary bg-[#F6FAFF] rounded-[4px] px-[12px] py-[8px]'>
+            <span>
+              企业审核结果:
+              {declFormData?.checkState
+                ? checkStateMap[declFormData.checkState as keyof typeof checkStateMap]
+                : '-'}
+            </span>
+            <span className='ml-20'>审核意见:{declFormData?.checkMsg || '-'}</span>
+            <span className='ml-20 break-all'>原因说明:{declFormData?.remarks || '-'}</span>
+          </div>
+        </div>
+      )
+    }
+  )
+)
+
+export default FormParse

+ 4 - 4
src/main.tsx

@@ -9,14 +9,14 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
 import { Analytics } from '@vercel/analytics/react'
 // svg icons
 import 'virtual:svg-icons-register'
+// css
+import './styles/common.scss'
 import './theme/theme.css'
 import ProgressBar from './components/progress-bar'
 // mock api
-import worker from './_mock'
+// import worker from './_mock'
 // root component
 import App from './App'
-// css
-import './global.css'
 // i18n
 import './locales/i18n'
 
@@ -36,4 +36,4 @@ root.render(
 )
 
 // 🥵 start service worker mock in development mode
-worker.start({ onUnhandledRequest: 'bypass' })
+// worker.start({ onUnhandledRequest: 'bypass' })

+ 200 - 0
src/pages/decl/index.tsx

@@ -0,0 +1,200 @@
+import { useEffect, useMemo, useRef, useState } from 'react'
+import { useSearchParams } from '@/router/hooks'
+import imgQR from '@/assets/images/qrcode/wechat_qrcode.png'
+import classNames from 'classnames'
+import dayjs from 'dayjs'
+import { toast } from 'sonner'
+import { openDeclForm } from '@/api/services/riskcontrol/declare'
+import { DeclState, DeclStateText } from '@/api/services/riskcontrol/enum'
+import { Button, Divider, Input, Layout, Result } from 'antd'
+import { LoadingOutlined } from '@ant-design/icons'
+import FormParse, { type FormParseRef } from '@/components/formParse'
+
+const { Search } = Input
+
+type IPageState = 'secretInput' | 'missParams' | 'decl' | 'loading' | 'success'
+
+const maskWrapperClass = 'absolute top-0 left-0 w-full h-full'
+const maskDialogWrapperClass =
+  'w-[300px] h-[160px] bg-[white] absolute-content-center rounded-[4px] box-border px-[24px] py-[24px]'
+
+function Decl() {
+  const [pageState, setPageState] = useState<IPageState>('success')
+  const [orderState, setOrderState] = useState('')
+  const [declFormData, setDeclFormData] = useState<API.OpenDeclFormResult>()
+  const [imgOSS] = useState('')
+
+  const FormParseRef = useRef<FormParseRef>(null)
+
+  // 问卷是否过期
+  const isExpiry = useMemo(() => {
+    const expiryDate = declFormData?.expiryDate
+    const isExpiryVal = expiryDate && dayjs(expiryDate).isBefore(dayjs().format('YYYY-MM-DD'))
+    return !!isExpiryVal
+  }, [])
+
+  const searchParams = useSearchParams()
+  const tId = searchParams.get('tId') || ''
+  const declSn = searchParams.get('declSn') || ''
+  const secretKey = searchParams.get('secretKey') || ''
+
+  const [formData, setFormData] = useState<Record<string, any>>({})
+  const [formRule, setFormRule] = useState({})
+  type ISubmitType = 'save' | 'submit' | 'onlySave' | 'autoSave'
+  const [resultType, setResultType] = useState<Nullable<ISubmitType>>(null)
+
+  const [btnLoading, setBtnLoading] = useState(false)
+  const confirmSecretFn = async () => {
+    setFormData({})
+    setFormRule({})
+    setBtnLoading(true)
+    const res = await openDeclForm({
+      tId,
+      declSn,
+      secretKey
+    })
+    setBtnLoading(false)
+    if (res?.code === '2000') {
+      setDeclFormData(res.data)
+      setPageState('decl')
+      setOrderState(declFormData?.payDetail?.orderState as string)
+    }
+  }
+  useEffect(() => {
+    if (!tId || !declSn) {
+      setPageState('missParams')
+      toast.warning('链接缺少关键参数', { position: 'top-center' })
+    } else if (secretKey) {
+      confirmSecretFn()
+    } else {
+      setPageState('secretInput')
+    }
+  }, [])
+
+  const [isAutoSaveing, setIsAutoSaveing] = useState(false)
+
+  // 配置保存数据的格式
+  const submitFn = async (type: ISubmitType, isAfterPayment = false) => {
+    console.log(type)
+    console.log(isAfterPayment)
+  }
+
+  return (
+    <Layout>
+      <div className='decl-page relative !h-screen bg-gradient-to-b from-[#F2F7FE] to-[#FAFBFC]'>
+        {pageState === 'loading' && (
+          <div className='loading-mask absolute-content-center text-primary text-[20px]'>
+            <LoadingOutlined />
+            <span className='ml-[12px]'>内容加载中...</span>
+          </div>
+        )}
+
+        {pageState === 'secretInput' && (
+          <div className={classNames('bg-[black] bg-opacity-50', maskWrapperClass)}>
+            <div className={classNames(maskDialogWrapperClass)}>
+              <div className='mb-[20px] font-[500] text-[16px]'>打开申报单</div>
+              <Search
+                placeholder='请输入提取码'
+                allowClear
+                onSearch={confirmSecretFn}
+                style={{ width: '100%' }}
+              />
+            </div>
+          </div>
+        )}
+
+        {pageState === 'missParams' && (
+          <div className={classNames('bg-#f5f7fa', maskWrapperClass)}>
+            <div className={classNames(maskDialogWrapperClass)}>
+              <h2>缺少关键参数</h2>
+              <span className='text-text-secondary'>请检查您的链接是否正确</span>
+            </div>
+          </div>
+        )}
+
+        {pageState === 'decl' && (
+          <div className='decl-form-wrapper h-full py-[80px] box-border'>
+            <div className='decl-content mx-auto w-[880px]'>
+              <div className='px-[30px] py-[40px] rounded-[8px] bg-[white]'>
+                <div className='text-[20px] text-center font-500'>
+                  {`“${declFormData?.enterpriseName}”,请填写申报`}
+                </div>
+                <Divider />
+                {declFormData?.formItems && (
+                  <FormParse
+                    ref={FormParseRef}
+                    formData={formData}
+                    formRule={formRule}
+                    declFormData={declFormData}
+                    state={DeclStateText[declFormData.declarationState!]}
+                    expiry={declFormData?.expiryDate}
+                    isExpiry={isExpiry}
+                    disabled={
+                      declFormData?.declarationState === DeclState.SUBMITTED ||
+                      declFormData?.declarationState === DeclState.CHECKED ||
+                      isExpiry
+                    }
+                    className='mt-10'
+                  />
+                )}
+                <div className='fixed right-[10px] top-[50%] -translate-y-[50%]'>
+                  <img className='w-[300px]' src={imgOSS || imgQR} alt='' />
+                </div>
+              </div>
+            </div>
+          </div>
+        )}
+
+        {pageState === 'success' && (
+          <div className={classNames('bg-#f5f7fa', maskWrapperClass)}>
+            <div className={classNames('!h-[330px]', maskDialogWrapperClass)}>
+              <Result
+                status='success'
+                title={resultType === 'save' ? '保存成功' : '申报成功'}
+                subTitle={`“${declFormData?.enterpriseName}”邀请您填写的申报已${
+                  resultType === 'save' ? '保存,未提交申报' : '成功'
+                }`}
+                extra={
+                  <Button type='primary' loading={btnLoading} onClick={confirmSecretFn}>
+                    返回查看
+                  </Button>
+                }
+              />
+            </div>
+          </div>
+        )}
+
+        {(declFormData?.declarationState === DeclState.UNREAD ||
+          declFormData?.declarationState === DeclState.READ ||
+          declFormData?.declarationState === DeclState.ROLLBACK) &&
+          !isExpiry &&
+          pageState !== 'success' && (
+            <div
+              className='fixed bottom-0 left-0 w-full bg-[white] h-[64px]'
+              style={{ boxShadow: '0px -1px 2px 0px rgba(0, 0, 0, 0.06)' }}>
+              <div className='w-[880px] mx-auto flex items-center justify-end h-full'>
+                <span className='text-[12px] text-[#F54A45] mr-[16px]'>
+                  填写过程中请及时保存,避免页面关闭后信息丢失
+                </span>
+                {isAutoSaveing && (
+                  <span className='text-[12px] text-[primary] mr-[16px]'>自动保存中...</span>
+                )}
+                <Button loading={btnLoading} onClick={() => submitFn('save')}>
+                  保 存
+                </Button>
+                <Button
+                  loading={btnLoading}
+                  type='primary'
+                  className='ml-[8px] mr-[30px]'
+                  onClick={() => submitFn('submit')}>
+                  提 交
+                </Button>
+              </div>
+            </div>
+          )}
+      </div>
+    </Layout>
+  )
+}
+
+export default Decl

+ 20 - 9
src/router/index.tsx

@@ -6,20 +6,31 @@ import ProtectedRoute from '@/router/components/protected-route'
 import { usePermissionRoutes } from '@/router/hooks'
 import { ERROR_ROUTE } from '@/router/routes/error-routes'
 import DashboardLayout from '@/layouts/dashboard'
+import Decl from '@/pages/decl'
 import PageError from '@/pages/sys/error/PageError'
 import Login from '@/pages/sys/login/Login'
 import { SetupNavigation } from './components/SetupNavigation'
 
 const { VITE_APP_HOMEPAGE: HOMEPAGE } = import.meta.env
 
-const PUBLIC_ROUTE: AppRouteObject = {
-  path: '/login',
-  element: (
-    <ErrorBoundary FallbackComponent={PageError}>
-      <Login />
-    </ErrorBoundary>
-  )
-}
+const PUBLIC_ROUTES: AppRouteObject[] = [
+  {
+    path: '/login',
+    element: (
+      <ErrorBoundary FallbackComponent={PageError}>
+        <Login />
+      </ErrorBoundary>
+    )
+  },
+  {
+    path: '/decl',
+    element: (
+      <ErrorBoundary FallbackComponent={PageError}>
+        <Decl />
+      </ErrorBoundary>
+    )
+  }
+]
 
 const NO_MATCHED_ROUTE: AppRouteObject = {
   path: '*',
@@ -42,7 +53,7 @@ export default function Router() {
     children: [{ index: true, element: <Navigate to={HOMEPAGE} replace /> }, ...permissionRoutes]
   }
 
-  const routes = [PUBLIC_ROUTE, PROTECTED_ROUTE, ERROR_ROUTE, NO_MATCHED_ROUTE] as RouteObject[]
+  const routes = [...PUBLIC_ROUTES, PROTECTED_ROUTE, ERROR_ROUTE, NO_MATCHED_ROUTE] as RouteObject[]
   // console.log(routes)
 
   const router = createHashRouter(routes)

+ 2 - 0
src/styles/common.scss

@@ -0,0 +1,2 @@
+@import url(./global.css);
+@import url(./shortcuts.scss);

+ 12 - 0
src/global.css → src/styles/global.css

@@ -12,6 +12,18 @@
 @import 'tailwindcss/components';
 @import 'tailwindcss/utilities';
 
+@layer base {
+  h1 {
+    @apply text-2xl font-extrabold;
+  }
+  h2 {
+    @apply text-xl font-bold;
+  }
+  h3 {
+    @apply text-lg font-semibold;
+  }
+}
+
 :root {
   --c-bg: transparent;
   --c-scrollbar: #aaa;

+ 15 - 0
src/styles/shortcuts.scss

@@ -0,0 +1,15 @@
+.absolute-content-center {
+  @apply absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%];
+}
+
+.f-c-c {
+  @apply flex justify-center items-center;
+}
+
+.f-b-c {
+  @apply flex justify-between items-center;
+}
+
+.f-n-c {
+  @apply flex items-center;
+}