elf 4 months ago
commit 242f834edb

26
.gitignore vendored

@ -0,0 +1,26 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.history
vite.config.ts.timestamp*

@ -0,0 +1,7 @@
# Vue 3 + Vite
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously Volar) and disable Vetur

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/x-icon" href="/fav.ico" />
<title>东方保险经纪</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

4051
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,33 @@
{
"name": "my-vue-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"axios": "^0.26.1",
"element-plus": "2.2.15",
"html2canvas": "^1.4.1",
"jspdf": "^2.5.1",
"lodash-es": "^4.17.21",
"pinia": "^2.0.12",
"qs": "^6.10.3",
"vue": "^3.2.34",
"vue-router": "4"
},
"devDependencies": {
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.14.2",
"@types/qs": "^6.9.15",
"@vitejs/plugin-vue": "^2.2.0",
"prettier": "^2.6.0",
"sass": "^1.49.9",
"typescript": "^5.4.5",
"vite": "^2.8.0",
"vite-plugin-html": "^3.2.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@ -0,0 +1,12 @@
module.exports = {
semi: true,
useTabs: false,
tabWidth: 2,
printWidth: 120,
singleQuote: true,
arrowParens: 'always',
trailingComma: 'all',
bracketSpacing: true,
jsxBracketSameLine: true,
htmlWhitespaceSensitivity: 'css',
};

@ -0,0 +1,19 @@
declare namespace Common {
export type Option<V = string> = {
key: V;
label: string;
[key: string]: unknown;
};
export type VoidFunc = () => void;
export type SearchFunc<T = void> = (page?: number) => Promise<T>;
export type PromiseVoidFunc = () => Promise<void>;
export type TimeRange = null | [string, string];
export type HTMLElementWithDirective<K, V> = HTMLElement & {
[key in K]: import('vue').DirectiveBinding<V>;
};
}

@ -0,0 +1,56 @@
/**
* Extracting the value type of T
*/
declare type ValueOf<T> = T extends object ? T[keyof T] : never;
/**
* Type T may be null or undefined
*/
declare type MaybeNil<T> = T | null | undefined;
/**
* Make all properties in T optional, In-depth
*/
declare type DeepPartial<T> = T extends object
? {
-readonly [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
}
: never;
/**
* Make all properties in T writable, In-depth
*/
declare type DeepWritable<T> = T extends object | undefined
? {
-readonly [P in keyof T]: T[P] extends object | undefined ? DeepWritable<T[P]> : T[P];
}
: never;
/**
* Make all properties in T readonly, In-depth
*/
declare type DeepReadonly<T> = import('vue').DeepReadonly<T>;
/**
* Add prefix
*/
declare type AddPrefix<T extends string, P extends string> = T extends '' ? '' : `${T}${P}`;
/**
* Add suffix
*/
declare type AddSuffix<T extends string, P extends string> = T extends '' ? '' : `${P}${T}`;
/**
* Get the last character
*/
declare type GetLastChar<T extends string> = T extends `${infer F}${infer REST}`
? REST extends ''
? F
: GetLastChar<REST>
: T;
/**
* Get the first character
*/
declare type GetFirstChar<T extends string> = T extends `${infer F}${infer REST}` ? F : T;

@ -0,0 +1,26 @@
declare type App = import('vue').App;
declare type Component = import('vue').Component;
declare type CSSProperties = import('vue').CSSProperties;
declare type VNode = import('vue').VNode;
declare type VNodeProps = import('vue').VNodeProps;
declare type InjectionKey<T> = import('vue').InjectionKey<T>;
declare type WatchStopHandle = import('vue').WatchStopHandle;
declare type Ref<T> = import('vue').Ref<T>;
declare type UnwrapNestedRefs<T> = import('vue').UnwrapNestedRefs<T>;
declare type ComputedRef<T> = import('vue').ComputedRef<T>;
declare type WritableComputedRef<T> = import('vue').WritableComputedRef<T>;
declare type Directive<T, V = any> = import('vue').Directive<T, V>;
declare type DirectiveBinding<V> = import('vue').DirectiveBinding<V>;
declare module '*.vue' {
import type { DefineComponent } from 'vue';
const vueComponent: DefineComponent;
export default vueComponent;
}

@ -0,0 +1,3 @@
<template>
<router-view />
</template>

@ -0,0 +1,253 @@
// good
import request from '@/utils/request';
import { REQUEST_CONTENT_TYPE } from '@/constant/request';
export interface Invoice {
Header: string;
TaxNumber: string;
}
export interface Order {
CreatedAt: string;
UpdatedAt: string;
ID: string;
RequestID: string;
OrderSn: string;
Token: string;
User: OrderUser;
Project: OrderProject;
Assured: OrderAssured;
Applicant: OrderApplicant;
Invoice: null | Invoice;
}
export interface OrderUser {
CreatedAt: string;
ID: string;
OrderSn: string;
Mobile: string;
Username: string;
UserID: string;
UnitID: string;
UnitName: string;
BeiandiquCode: string;
BankName: string;
BankCardNum: string;
BankUserName: string;
Order: string;
}
export interface OrderProject {
CreatedAt: string;
UpdatedAt: string;
ID: string;
OrderSn: string;
Name: string;
TpID: string;
BdID: string;
BdName: string;
StartDate: string;
Amount: string;
Province: string;
City: string;
District: string;
BzjEtime: string;
CreateTime: string;
PlanDate: string;
BuildPrice: string;
BuildPlace: string;
TenderProjectType: string;
ValidPeriod: string;
TenderNoticeUrl: string;
TenderFileUrl: string;
TenderFileUrlMd5: string;
ProjectApprovalNo: string;
Order: string;
}
export interface OrderAssured {
CreatedAt: string;
UpdatedAt: string;
ID: string;
OrderSn: string;
AssuredName: string;
ComTelArea: string;
CreditCode: string;
CreditVld: string;
ContactName: string;
ContactMobile: string;
TenderBankAccount: string;
TenderBankOpenbank: string;
TenderAccountName: string;
Province: string;
City: string;
District: string;
Address: string;
ComTelNum: string;
Agency: string;
Order: string;
}
export interface OrderApplicant {
CreatedAt: string;
UpdatedAt: string;
ID: string;
OrderSn: string;
ApplicantName: string;
CreditVld: string;
CreditCode: string;
ContactName: string;
ContactMobile: string;
ComTelArea: string;
Province: string;
City: string;
District: string;
Address: string;
Email: string;
LegalName: string;
LegalNum: string;
ComTelNum: string;
LicenseFiles: string;
SignUrl: string;
Order: string;
InvoiceAcceptEmail: string;
InvoiceType: string;
}
export interface GetOrderRes {
order: Order;
}
export interface GetOrderParams {
token: string;
}
export function getOrder(params: GetOrderParams) {
return request.get<GetOrderRes>('/web/get-order', { params });
}
export interface GetSignUrlRes {
signUrl: string;
}
export interface GetSignUrlParams {
token: string;
}
export function getSignUrl(params: GetSignUrlParams) {
return request.get<GetSignUrlRes>('/web/get-sign-url', { params });
}
export interface OrderResult {
CreatedAt: string;
UpdatedAt: string;
ID: number;
OrderSn: string;
PolicyNo: string;
MinPremium: string;
Rate: string;
Status: string;
ServiceAmount: string;
GuranteeLink: string;
GuranteeLinkMd5: string;
GuranteeOfdLink: string;
GuranteeOfdLinkMd5: string;
InvoiceLink: string;
InvoiceLinkMd5: string;
ConfirmReceiptLink: string;
ConfirmReceiptLinkMd5: string;
Remark: string;
Order: null;
}
export interface GetOrderResultRes {
orderResult: OrderResult;
}
export interface GetOrderResultParams {
token: string;
}
export function getOrderResult(params: GetOrderResultParams) {
return request.get<GetOrderResultRes>('/web/get-order-result', { params });
}
export interface UploadSignedFileParams {
pdf: File;
token: string;
}
export function uploadSignedFile(data: UploadSignedFileParams) {
const formData = new FormData();
Object.entries(data).forEach(([key, value]) => {
formData.append(key, value);
});
return request.post('/web/upload-sign-file', formData, {
headers: { 'Content-Type': REQUEST_CONTENT_TYPE.FORM_DATA },
});
}
export interface GetOrderStatusRes {
status: 'signed' | 'submitted' | 'generated';
}
export interface GetOrderStatusParams {
token: string;
}
export function getOrderStatus(params: GetOrderStatusParams) {
return request.get<GetOrderStatusRes>('/web/get-order-status', { params });
}
export interface GetOrderPayUrlRes {
payUrl: string;
status: 'signed' | 'submitted' | 'generated';
}
export interface GetOrderPayUrlParams {
token: string;
}
export function getOrderPayUrl(params: GetOrderPayUrlParams) {
return request.get<GetOrderPayUrlRes>('/web/get-order-pay-url', { params });
}
export interface UpdateApplicantParams {
token: string;
applicantName: string;
creditCode: string;
contactName: string;
contactMobile: string;
bankName: string;
bankCardNum: string;
invoiceAcceptEmail: string;
invoiceType: string;
}
export function updateApplicant(data: UpdateApplicantParams) {
return request.post('/web/update-applicant', data);
}
export interface UpdateInvoiceParams {
token: string;
header: string;
taxNumber: string;
}
export function updateInvoice(data: UpdateInvoiceParams) {
return request.post('/web/update-invoice', data);
}
export interface GenerateSignFileParams {
token: string;
}
export function generateSignFile(data: GenerateSignFileParams) {
return request.post('/web/generate-sign-file', data);
}
export interface PayInfo {
TpID: string;
OrderSn: string;
OrderCreateTime: string;
PayAmount: string;
ProductName: string;
Remark: string;
Payee: Payee;
Payer: Payee;
}
export interface Payee {
BankName: string;
BankCardNum: string;
BankUserName: string;
}
export interface GetPayInfoRes {
PayInfo: PayInfo;
}
export interface GetPayInfoParams {
token: string;
}
export function getPayInfo(params: GetPayInfoParams) {
return request.get<GetPayInfoRes>('/web/get-pay-info', { params });
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@ -0,0 +1,40 @@
<script setup>
import { ref } from 'vue'
defineProps({
msg: String,
})
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
>create-vue</a
>, the official Vue + Vite starter
</p>
<p>
Install
<a href="https://github.com/vuejs/language-tools" target="_blank">Volar</a>
in your IDE for a better DX
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>

@ -0,0 +1,8 @@
<template>
<div class="d-flex align-items-center justify-content-center flex-gap-8 p-8 ft-12">
<span>北京东方保险经纪有限公司</span>
<span>联系方式010-52131008</span>
<span>备案号码京ICP备13047343号-7</span>
<span>保险中介许可证编号260453000000800</span>
</div>
</template>

@ -0,0 +1,49 @@
// good
import { defineConstants } from '@/utils/constant';
export const { TOGGLE, TOGGLE_MAP, TOGGLE_LIST } = defineConstants(
[
{ key: '1', keyAlias: 'yes', label: '是' },
{ key: '0', keyAlias: 'no', label: '否' },
] as const,
'TOGGLE',
'key',
'keyAlias',
);
export const TOGGLE_SWITCH_LIST = [
{ ...TOGGLE_LIST[0], label: '开启' },
{ ...TOGGLE_LIST[1], label: '关闭' },
] as const;
export type ToggleEnum = ValueOf<typeof TOGGLE>;
export type ToggleEnumWithNone = ToggleEnum | '';
export const { TOGGLE_EN, TOGGLE_EN_MAP, TOGGLE_EN_LIST } = defineConstants(
[
{ key: 'yes', label: '是' },
{ key: 'no', label: '否' },
] as const,
'TOGGLE_EN',
);
export type ToggleEnEnum = ValueOf<typeof TOGGLE_EN>;
export type ToggleEnEnumWithNone = ToggleEnEnum | '';
export const { TOGGLE_NUM, TOGGLE_NUM_MAP, TOGGLE_NUM_LIST } = defineConstants(
[
{ key: 1, keyAlias: 'yes', label: '是' },
{ key: 0, keyAlias: 'no', label: '否' },
] as const,
'TOGGLE_NUM',
'key',
'keyAlias',
);
export type ToggleNumEnum = ValueOf<typeof TOGGLE_NUM>;
export const { RESULT, RESULT_MAP, RESULT_LIST } = defineConstants(
[
{ key: 'fail', label: '失败' },
{ key: 'success', label: '成功' },
] as const,
'RESULT',
);
export type ResultEnum = ValueOf<typeof RESULT>;
export type ResultEnumWithNone = ResultEnum | '';

@ -0,0 +1,28 @@
// good
import { defineConstants } from '../utils/constant';
export const REQUEST_BASE_URL = '/api';
export const { REQUEST_CODE, REQUEST_CODE_MAP, REQUEST_CODE_LIST } = defineConstants(
[
{ key: '0000', label: '成功', keyAlias: 'success' },
{ key: '1000', label: '登录过期', keyAlias: 'expired' },
],
'REQUEST_CODE',
'key',
'keyAlias',
);
export type RequestCodeEnum = ValueOf<typeof REQUEST_CODE>;
export const { REQUEST_CONTENT_TYPE, REQUEST_CONTENT_TYPE_MAP, REQUEST_CONTENT_TYPE_LIST } = defineConstants(
[
{ key: 'text/html', keyAlias: 'html' },
{ key: 'application/json', keyAlias: 'json' },
{ key: 'application/x-www-form-urlencoded', keyAlias: 'formUrl' },
{ key: 'multipart/form-data', keyAlias: 'formData' },
{ key: 'application/vnd.ms-excel', keyAlias: 'excel' },
] as const,
'REQUEST_CONTENT_TYPE',
'key',
'keyAlias',
);

@ -0,0 +1 @@
export * from './useLoading';

@ -0,0 +1,48 @@
import { ElLoading } from 'element-plus';
import { ref, isRef, nextTick } from 'vue';
import type { LoadingOptions } from 'element-plus';
type OverwriteLoadingOptions = Omit<LoadingOptions, 'target'> & {
isSync?: boolean;
target?: Ref<HTMLElement> | HTMLElement | string;
};
const defaultOptions: LoadingOptions = {
text: '',
background: 'rgba(0, 0, 0, 0.5)',
};
export function useLoading(options: OverwriteLoadingOptions = { isSync: false }) {
const config = { ...defaultOptions, ...options };
const loading = ref(false);
const loadingInstance = ref<ReturnType<typeof ElLoading.service>>();
// 支持 Ref<HTMLElement>
const { target } = config;
if (target && isRef(target)) {
nextTick(() => {
config.target = target.value;
});
}
const openLoading = () => {
if (loading.value) return;
loading.value = true;
loadingInstance.value = ElLoading.service(config as LoadingOptions);
};
const closeLoading = (isSync = false) => {
if (!loading.value) return;
loading.value = false;
loadingInstance.value?.close();
(isSync || options.isSync) && loadingInstance.value?.removeElLoadingChild();
};
return {
loading,
openLoading,
closeLoading,
};
}

@ -0,0 +1,14 @@
import { createApp } from 'vue';
import ElementPlus from 'element-plus';
import App from './App.vue';
import router from '@/router';
import './style.scss';
import 'element-plus/theme-chalk/src/index.scss';
const mainApp = createApp(App);
mainApp.use(ElementPlus);
mainApp.use(router);
mainApp.mount('#app');

@ -0,0 +1,27 @@
// good
export default [
{
path: '/',
component: () => import('@/views/404/index.vue'),
},
{
name: 'Sign',
path: '/sign',
component: () => import('@/views/sign/index.vue'),
},
{
name: 'Tender',
path: '/tender',
component: () => import('@/views/tender/index.vue'),
},
{
name: 'Callback',
path: '/callback',
component: () => import('@/views/callback/index.vue'),
},
{
name: 'NotFound',
path: '/:pathMatch(.*)*',
component: () => import('@/views/404/index.vue'),
},
];

@ -0,0 +1,11 @@
import { createRouter, createWebHistory } from 'vue-router';
import routes from './constantRoutes';
const router = createRouter({
history: createWebHistory(),
scrollBehavior: () => ({ top: 0 }),
routes,
});
export default router;

@ -0,0 +1,347 @@
html,
body {
margin: 0;
padding: 0;
height: 100vh;
overflow: auto;
background-color: #eff2f9;
}
.color-warn {
color: #ff8834;
}
.color-danger {
color: #f45057;
}
.color-placeholder {
color: #909399;
}
.select-none {
user-select: none;
}
.position-center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.single-ellipsis {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.multiple-ellipsis {
word-break: break-all;
white-space: pre-wrap;
display: -webkit-box;
-webkit-line-clamp: 2;
overflow: hidden;
-webkit-box-orient: vertical;
}
.white-space-nowrap {
white-space: nowrap;
}
.visibility-hidden {
opacity: 0;
pointer-events: none;
}
@for $i from 0 through 100 {
.m-#{$i} {
margin: $i + px !important;
}
.m-t-#{$i} {
margin-top: $i + px !important;
}
.m-b-#{$i} {
margin-bottom: $i + px !important;
}
.m-l-#{$i} {
margin-left: $i + px !important;
}
.m-r-#{$i} {
margin-right: $i + px !important;
}
.m-x-#{$i} {
margin-left: $i + px !important;
margin-right: $i + px !important;
}
.m-y-#{$i} {
margin-top: $i + px !important;
margin-bottom: $i + px !important;
}
.p-#{$i} {
padding: $i + px !important;
}
.p-t-#{$i} {
padding-top: $i + px !important;
}
.p-b-#{$i} {
padding-bottom: $i + px !important;
}
.p-l-#{$i} {
padding-left: $i + px !important;
}
.p-r-#{$i} {
padding-right: $i + px !important;
}
.p-x-#{$i} {
padding-left: $i + px !important;
padding-right: $i + px !important;
}
.p-y-#{$i} {
padding-top: $i + px !important;
padding-bottom: $i + px !important;
}
}
@for $i from 12 through 40 {
.ft-#{$i} {
font-size: $i + px !important;
}
.line-height-#{$i} {
line-height: $i + px !important;
}
}
$positionMap: (
fixed: fixed,
static: static,
sticky: sticky,
relative: relative,
absolute: absolute,
);
@each $key, $val in $positionMap {
.pos-#{$key} {
position: $val;
}
}
$displayMap: (
none: none,
flex: flex,
inline-flex: inline-flex,
inline: inline,
block: block,
inline-block: inline-block,
);
@each $key, $val in $displayMap {
.d-#{$key} {
display: $val;
}
}
.flex-1 {
flex: 1;
}
$flexScaleAttrList: grow, shrink;
@each $scaleAttr in $flexScaleAttrList {
.flex-#{$scaleAttr}-0 {
flex-#{$scaleAttr}: 0;
}
.flex-#{$scaleAttr}-1 {
flex-#{$scaleAttr}: 1;
}
}
$flexAlignMap: (
end: flex-end,
start: flex-start,
center: center,
);
@each $key, $val in $flexAlignMap {
.align-self-#{$key} {
align-self: $val !important;
}
.align-items-#{$key} {
align-items: $val !important;
}
}
$flexJustifyMap: (
end: flex-end,
start: flex-start,
center: center,
around: space-around,
between: space-between,
);
@each $key, $val in $flexJustifyMap {
.justify-self-#{$key} {
justify-self: $val !important;
}
.justify-content-#{$key} {
justify-content: $val !important;
}
}
$flexWrapMap: (
wrap: wrap,
nowrap: nowrap,
);
@each $key, $val in $flexWrapMap {
.flex-#{$key} {
flex-wrap: $val !important;
}
}
$flexDirectionMap: (
row: row,
column: column,
);
@each $key, $val in $flexDirectionMap {
.flex-direction-#{$key} {
flex-direction: $val !important;
}
}
$flexGapList: 4, 8, 12, 16, 20, 24;
@each $flexGap in $flexGapList {
.flex-gap-#{$flexGap} {
gap: $flexGap + px;
}
}
$boxSizeAttrMap: (
m: margin,
p: padding,
w: width,
h: height,
);
@each $key, $val in $boxSizeAttrMap {
.#{$key}-auto {
#{$val}: auto !important;
}
.#{$key}-full {
#{$val}: 100% !important;
}
@if $key == 'm' {
.#{$key}-l-auto {
#{$val}-left: auto !important;
}
.#{$key}-r-auto {
#{$val}-right: auto !important;
}
}
}
$textAlignMap: (
l: left,
r: right,
c: center,
);
@each $key, $val in $textAlignMap {
.text-align-#{$key} {
text-align: $val;
}
}
$fontWeightMap: (
bold: bold,
normal: normal,
);
@each $key, $val in $fontWeightMap {
.font-weight-#{$key} {
font-weight: $val;
}
}
$wordBreakMap: (
all: break-all,
normal: normal,
);
@each $key, $val in $wordBreakMap {
.word-break-#{$key} {
word-break: $val;
}
}
$verticalAlignMap: (
top: top,
sub: sub,
middle: middle,
bottom: bottom,
);
@each $key, $val in $verticalAlignMap {
.vertical-align-#{$key} {
vertical-align: $val;
}
}
$decorationMap: (
none: none,
under: underline,
);
@each $key, $val in $decorationMap {
.text-decoration-#{$key} {
text-decoration: $val;
}
}
$overflowMap: (
auto: auto,
hidden: hidden,
);
@each $key, $val in $overflowMap {
.overflow-#{$key} {
overflow: $val;
}
.overflow-x-#{$key} {
overflow-x: $val;
}
.overflow-y-#{$key} {
overflow-y: $val;
}
}
$cursorMap: (
move: move,
default: default,
pointer: pointer,
no-drop: no-drop,
disable: not-allowed,
);
@each $key, $val in $cursorMap {
.cursor-#{$key} {
cursor: $val;
}
}
$eventsMap: (
all: all,
none: none,
);
@each $key, $val in $eventsMap {
.events-#{$key} {
pointer-events: $val;
}
}

@ -0,0 +1,26 @@
// good
import { ElMessage } from 'element-plus';
import type { Message } from 'element-plus';
type AlertTypeEnum = Exclude<keyof Message, 'closeAll'>;
const baseAlert = (type: AlertTypeEnum, message: string) => {
ElMessage[type]({ message, grouping: true, dangerouslyUseHTMLString: true });
};
export function infoAlert(message: string) {
baseAlert('info', message);
}
export function errorAlert(message: string) {
baseAlert('error', message);
}
export function warningAlert(message: string) {
baseAlert('warning', message);
}
export function successAlert(message: string) {
baseAlert('success', message);
}

@ -0,0 +1,112 @@
import { snakeCase } from 'lodash-es';
// helper
type Map = Record<PropertyKey, any>;
type MapList = ReadonlyArray<Map>;
type Underline = '_';
type NumString = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
type MergeMap<A> = A extends infer T ? { [Key in keyof T]: T[Key] } : never;
// list to map
type ListToMap<T extends MapList, K extends keyof T[number], ACC extends Map = object> = T['length'] extends 0
? ACC
: T extends readonly [infer F extends Map, ...infer REST extends MapList]
? ListToMap<
REST,
K,
ACC & {
readonly [Key in F[K]]: F;
}
>
: never;
type ListToKeyMap<
T extends MapList,
K extends keyof T[number],
KA extends keyof T[number],
ACC extends Map = object,
> = T['length'] extends 0
? ACC
: T extends readonly [infer F extends Map, ...infer REST extends MapList]
? ListToKeyMap<
REST,
K,
KA,
ACC & {
readonly [Key in Uppercase<SnakeCaseList<SnakeCaseString<`${F[KA]}`>>>]: F[K];
}
>
: never;
// snakeCase
type SnakeCaseList<T extends string[], ACC extends string = ''> = T['length'] extends 0
? ACC
: T extends [infer F extends string, ...infer REST extends string[]]
? F extends ''
? SnakeCaseList<REST, ACC>
: ACC extends ''
? SnakeCaseList<REST, F>
: SnakeCaseList<REST, `${ACC}${Underline}${F}`>
: never;
type SnakeCaseString<T extends string, ACC extends string = '', LIST extends Array<any> = []> = LIST extends [
...infer REST_LIST,
]
? T extends ''
? ACC extends ''
? LIST
: [...REST_LIST, ACC]
: T extends `${infer F}${infer REST}`
? F extends Underline
? ACC extends ''
? SnakeCaseString<REST, '', LIST>
: SnakeCaseString<REST, '', [...REST_LIST, ACC]>
: F extends NumString
? ACC extends ''
? SnakeCaseString<REST, F, LIST>
: GetFirstChar<ACC> extends NumString
? SnakeCaseString<REST, `${ACC}${F}`, LIST>
: SnakeCaseString<REST, F, [...REST_LIST, ACC]>
: ACC extends ''
? SnakeCaseString<REST, F, LIST>
: GetFirstChar<ACC> extends NumString
? SnakeCaseString<REST, F, [...REST_LIST, ACC]>
: F extends Uppercase<F>
? GetLastChar<ACC> extends Uppercase<GetLastChar<ACC>>
? SnakeCaseString<REST, `${ACC}${F}`, LIST>
: SnakeCaseString<REST, F, [...REST_LIST, ACC]>
: SnakeCaseString<REST, `${ACC}${F}`, LIST>
: never
: never;
export function defineConstants<
T extends MapList,
N extends string,
K extends keyof T[number] = 'key',
KA extends keyof T[number] = K,
>(list: T, namespace: N, key: K = 'key' as K, keyAlias: KA = 'key' as KA) {
keyAlias = keyAlias || (key as unknown as KA);
return {
[namespace]: list.reduce((keyMap, item) => {
const keyAliasVal = snakeCase(item[keyAlias]).toUpperCase();
keyMap[keyAliasVal] = item[key];
return keyMap;
}, {}),
[namespace + '_MAP']: list.reduce((itemMap, item) => {
itemMap[item[key]] = item;
itemMap[item[keyAlias]] = item;
return itemMap;
}, {}),
[namespace + '_LIST']: list,
} as MergeMap<
{
[Key in N]: MergeMap<ListToKeyMap<T, K, KA>>;
} & {
[Key in AddPrefix<N, '_MAP'>]: MergeMap<ListToMap<T, K> & ListToMap<T, KA>>;
} & {
[Key in AddPrefix<N, '_LIST'>]: T;
}
>;
}

@ -0,0 +1,104 @@
// good
import axios from 'axios';
import { stringify } from 'qs';
import { isNil, isEmpty, isObject } from 'lodash-es';
import { isQuery } from '@/utils/validate';
import { errorAlert } from '@/utils/alert';
import { REQUEST_CODE, REQUEST_BASE_URL, REQUEST_CONTENT_TYPE } from '@/constant/request';
import type { RequestCodeEnum } from '@/constant/request';
import type { AxiosResponse, AxiosRequestConfig } from 'axios';
const service = axios.create({
baseURL: REQUEST_BASE_URL,
timeout: 5 * 60 * 1000,
headers: { 'Content-Type': REQUEST_CONTENT_TYPE.FORM_URL },
withCredentials: true,
});
service.interceptors.request.use(dealRequest, dealRejected);
service.interceptors.response.use(dealResponse, dealRejected);
function dealRequest(config: AxiosRequestConfig) {
const { data, method, headers } = config;
switch (method?.toUpperCase()) {
case 'GET': {
if (config.params) {
config.url = getUrlWithQuery(config.url!, config.params);
config.params = undefined;
}
break;
}
case 'POST': {
if (headers?.['Content-Type'] === REQUEST_CONTENT_TYPE.FORM_URL) {
config.data = stringify(data);
}
break;
}
}
return config;
}
interface ResponseDataType {
data: { [key: string]: unknown };
code: RequestCodeEnum;
message: string;
}
async function dealResponse(response: AxiosResponse<ResponseDataType>) {
const { data } = response;
const { code, message } = data;
switch (code) {
case REQUEST_CODE.SUCCESS: {
return data;
}
default: {
errorAlert(message);
return Promise.reject(data);
}
}
}
function dealRejected(err: Error) {
errorAlert(err.message);
return Promise.reject(err);
}
export function getUrlWithQuery(url: string, params?: any) {
if (params && !isEmpty(params)) {
const querySymbol = isQuery(url) ? '&' : '?';
url = url + querySymbol + stringify(params);
}
return url;
}
export function generateFormUrl(data: object, lastKey = ''): string {
let str = '';
const list = Object.entries(data);
if (list.length) {
list.forEach(([key, value]) => {
const keyStr = lastKey ? lastKey + encodeURI('[' + key + ']') : encodeURI(key);
if (isObject(value)) {
str += generateFormUrl(value, keyStr);
} else {
const valStr = isNil(value) ? '' : encodeURIComponent(value);
str += `&${keyStr}=${valStr}`;
}
});
return lastKey ? str : str.substring(1);
} else {
return lastKey ? `&${lastKey}=` : '';
}
}
export default service;

@ -0,0 +1,31 @@
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
export async function generatePDFAndUpload(elementId: string) {
const element = document.getElementById(elementId);
if (!element) throw new Error('元素不存在');
element.style.display = 'block';
document.body.style.overflow = 'hidden';
const canvas = await html2canvas(element);
element.style.display = 'none';
document.body.style.overflow = 'auto';
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({
unit: 'px',
format: [canvas.width, canvas.height],
orientation: 'p',
});
// 添加图片到PDF
pdf.addImage(imgData, 'JPEG', 0, 0, canvas.width, canvas.height, void 0, 'FAST');
// 将PDF转换为Blob对象
const pdfBlob = await pdf.output('blob');
const file = new File([pdfBlob], '123.pdf', { type: 'application/pdf' });
const test = URL.createObjectURL(file);
console.log(test, file);
return file;
}

@ -0,0 +1,12 @@
import { isEmpty } from 'lodash-es';
import { stringify } from 'qs';
export function replaceState(replaceQuery = {}, url = '', stateObj = window.history.state, title = '') {
let address = url || window.location.pathname;
if (!isEmpty(replaceQuery)) {
address += `?${stringify(replaceQuery)}`;
}
window.history.replaceState(stateObj, title, address);
}

@ -0,0 +1,51 @@
export const isDateRegExp = /[12]\d{3}[-/]((0[1-9])|(1[0-2]))[-/]((0[1-9])|([12][0-9])|(3[0-1]))/;
export const isQueryRegExp = /\/.*\?.*=/;
export const isMobileRegExp = /^1[3456789]\d{9}$/;
export const is1688UrlRegExp = /(.*\.1688\.com\/)/;
export const isExternalRegExp = /^(http(s)?|mailto|tel|\/\/)/;
export const matchMoneyRegExp = /(0(\.[\d]{0,2})?)|([1-9]{1}[\d]*(\.)?[\d]{0,2})/gi;
export const isTelePhoneRegExp = /^(\+\d{2}-)?0\d{2,3}-?\d{7,8}$/;
export const isFixedPhoneRegExp = /^(\d{3}-\d{7,8}|\d{4}-\d{7,8})$/;
export const isVirtualPhoneRegExp = /^1[3456789]\d{9}-(\d{4})?$/;
export const is400TelePhoneRegExp = /^(\+86-)?400(-?\d{3,4}){2,3}$/;
export const isRelativeRootRegExp = /^\/[^/]+/;
export function isDate(str: string) {
return isDateRegExp.test(str);
}
export function isQuery(str: string) {
return isQueryRegExp.test(str);
}
export function isMobile(str: string) {
return isMobileRegExp.test(str);
}
export function is1688Url(str: string) {
return is1688UrlRegExp.test(str);
}
export function isExternal(str: string) {
return isExternalRegExp.test(str);
}
export function isTelePhone(str: string) {
return isTelePhoneRegExp.test(str);
}
export function isFixedPhone(str: string) {
return isFixedPhoneRegExp.test(str);
}
export function isVirtualPhone(str: string) {
return isVirtualPhoneRegExp.test(str);
}
export function is400Phone(str: string) {
return is400TelePhoneRegExp.test(str);
}
export function isRelativeRoot(str: string) {
return isRelativeRootRegExp.test(str);
}

@ -0,0 +1,14 @@
<template>
<div class="not-found-container">
<div>
<div class="not-found-text">
页面不存在
<!-- <a href="/" class="jx-trigger-primary text-decoration-none">点击返回&gt;</a> -->
</div>
</div>
</div>
</template>
<script lang="ts" setup></script>
<style lang="scss" scoped></style>

@ -0,0 +1,343 @@
<template>
<div class="page">
<div class="page-header">
<!-- <img src="@/assets/logo.png" /> -->
支付保费
</div>
<div class="d-flex flex-direction-column flex-grow-1 p-16">
<!-- 温馨提示 -->
<div class="page-notice">
<div>温馨提示</div>
<div>
<div>尊敬的投保企业投保时还请注意</div>
<div class="d-flex">
1第一次申请保函的<span class="color-danger">企业</span>如发现金额不正确请
<span class="color-danger">取消订单</span>
<span class="color-danger">重新下单</span>
即可感谢您的信任
</div>
</div>
</div>
<div style="flex-grow: 0" class="page-card">
<div class="d-flex justify-content-between m-b-20">
<div style="color: rgb(36, 127, 255)" class="ft-36">订单提交成功请尽快支付</div>
<div class="ft-24">
应付金额
<span class="ft-36 color-danger font-weight-bold">{{ payInfo.PayAmount }}</span>
</div>
</div>
<div>
<div class="d-flex m-b-12">
<div class="m-r-32">
<span class="color-placeholder">订单号{{ payInfo.OrderSn }}</span>
<span></span>
</div>
<div>
<span class="color-placeholder">提交时间{{ payInfo.OrderCreateTime }}</span>
<span></span>
</div>
</div>
<div class="d-flex">
<div>
<span class="color-placeholder">商品名称{{ payInfo.ProductName }}</span>
<span></span>
</div>
</div>
</div>
</div>
<div class="page-card">
<div class="m-b-32 ft-14">
<div class="d-flex">
请务必从公司的基本户付款
<span class="color-danger">如果不是从基本户付款或者登记的基本户账户有误因此造成的后果由贵公司负责</span>
</div>
<div class="d-flex">
打款时请务必在打款备注"、“摘要""用途"等处
<span class="color-danger">填写招标项目编号{{ payInfo.TpID }}</span>
</div>
</div>
<!-- 打款人账户 -->
<div class="m-b-20">
<div class="card-title">打款人账户</div>
<div class="card-content">
<div>
<div class="card-item">
<div class="card-label">户名</div>
<div class="card-value">{{ payInfo.Payer.BankUserName }}</div>
</div>
<div class="card-item">
<div class="card-label">账号</div>
<div class="card-value">{{ payInfo.Payer.BankCardNum }}</div>
</div>
<div class="card-item">
<div class="card-label">开户行</div>
<div class="card-value">{{ payInfo.Payer.BankName }}</div>
</div>
</div>
</div>
</div>
<!-- 收款人账户 -->
<div>
<div class="card-title">收款人账户</div>
<div class="card-content">
<div>
<div class="card-item">
<div class="card-label">户名</div>
<div class="card-value">{{ payInfo.Payee.BankUserName }}</div>
</div>
<div class="card-item">
<div class="card-label">账号</div>
<div class="card-value">{{ payInfo.Payee.BankCardNum }}</div>
</div>
<div class="card-item">
<div class="card-label">开户行</div>
<div class="card-value">{{ payInfo.Payee.BankName }}</div>
</div>
</div>
<div>
<div class="card-item">
<div class="card-label">金额</div>
<div class="card-value">{{ payInfo.PayAmount }}</div>
</div>
<div class="card-item">
<div class="card-label">备注</div>
<div class="card-value">{{ payInfo.Remark }}</div>
</div>
</div>
</div>
</div>
<div class="m-t-20">
<div class="d-flex align-items-center m-b-8">
<el-icon class="m-r-4 ft-18"><WarningFilled class="color-warn" /></el-icon>
<span class="ft-14">温馨提醒</span>
</div>
<div class="ft-12 color-placeholder">
<div class="m-b-4">
<span>1最迟请在</span>
<span class="color-danger">开标日期前一天17:00时前完成提交申请及保费转账</span>
<span>过点后无法保证及时出函</span>
</div>
<div class="m-b-4">
2晚间21:00到次日7:00之间的转账需次日7:00后才能到账建议在当天7:00-18:00时间段完成转账如需帮助可联系我们的客服我们会尽快为您处理
</div>
<div>3如需帮助可联系我们的客服我们会尽快为您处理联系人及联系方式张小姐13705008897</div>
</div>
</div>
</div>
</div>
<IPC />
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import { WarningFilled } from '@element-plus/icons-vue';
import IPC from '@/components/IPC.vue';
import { getPayInfo } from '@/api';
import type { PayInfo } from '@/api';
const route = useRoute();
const payInfo = ref<PayInfo>({ Payee: {}, Payer: {} });
initPage();
async function initPage() {
const queryToken = String(route.query.token);
const { data } = await getPayInfo({ token: queryToken });
payInfo.value = data.PayInfo;
}
</script>
<style lang="scss" scoped>
.page {
display: flex;
flex-direction: column;
height: 100vh;
}
.page-header {
position: sticky;
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
top: 0;
height: 60px;
font-size: 20px;
background-color: #fff;
> img {
position: absolute;
left: 20px;
width: 70px;
}
}
.page-notice {
display: flex;
border-radius: 6px;
background-color: #fff;
box-shadow: 0 0 10px #ddd;
overflow: hidden;
> div:first-child {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 150px;
color: #fff;
font-size: 20px;
font-weight: bold;
background-color: rgb(36, 127, 255);
&::after {
content: '';
position: absolute;
top: 50%;
left: 26px;
width: 4px;
height: 14px;
transform: translateY(-50%);
background-color: #fff;
}
}
> div:last-child {
flex-grow: 1;
padding: 8px 16px;
color: rgb(60, 124, 255);
line-height: 24px;
}
}
.page-card {
flex: 1;
margin-top: 16px;
padding: 16px;
border-radius: 6px;
background-color: #fff;
box-shadow: 0 0 10px #ddd;
.card-title {
position: relative;
display: flex;
align-items: center;
margin-bottom: 8px;
padding-left: 14px;
font-size: 16px;
&::after {
content: '';
position: absolute;
top: 50%;
left: 0;
width: 10px;
height: 10px;
border-radius: 50%;
transform: translateY(-50%);
background-color: rgb(36, 127, 255);
}
}
.card-content {
border: 1px solid #ebeef5;
overflow: hidden;
> div {
display: grid;
grid-template-columns: repeat(3, 1fr);
& + div {
border-top: 1px solid #ebeef5;
}
.card-item {
display: flex;
height: 70px;
}
.card-label {
display: flex;
align-items: center;
justify-content: center;
width: 70px;
height: 100%;
color: #606266;
font-size: 14px;
background-color: #f5f7fa;
}
.card-value {
display: flex;
align-items: center;
justify-content: center;
padding: 0 12px;
}
}
}
}
.page-footer {
display: flex;
margin-top: 16px;
height: 80px;
border-radius: 6px;
background-color: #fff;
overflow: hidden;
> div:first-child {
display: flex;
align-items: center;
justify-content: flex-end;
flex: 1;
padding: 16px;
}
> div:last-child {
display: flex;
align-items: center;
justify-content: center;
width: 200px;
color: #fff;
font-size: 20px;
font-weight: bold;
background-color: rgb(36, 127, 255);
}
}
.card-double-box {
display: flex;
gap: 16px;
> div:last-child {
.card-label {
width: calc(15em - 26px);
}
}
}
</style>

@ -0,0 +1,259 @@
<template>
<div class="page">
<div class="page-header">
<!-- <img src="@/assets/logo.png" /> -->
选择签章
</div>
<div class="page-body">
<!-- 选择CA -->
<div>
<div class="m-b-32">
<div class="m-b-4">请选择所持CA类型进行签章</div>
<div class="ft-14 color-placeholder">用户若无法确认所支持CA类型可直接选择统一签章</div>
</div>
<div class="ca-list m-b-32">
<div class="ca-item" @click="handleOpenCA">
<img src="@/assets/ca-fj.png" />
</div>
<div class="ca-item" @click="handleOpenCA">
<img src="@/assets/ca-twcx.png" />
</div>
<div class="ca-item" @click="handleOpenCA">
<img src="@/assets/ca-cf.jpg" />
</div>
<div class="ca-item" @click="handleOpenCA">
<img src="@/assets/ca-sz.png" />
</div>
</div>
</div>
<!-- 提示跳转 -->
<div class="jump-tip">
如完成签章未自动跳转请点击刷新进行尝试
<a href="#" @click="handleReload"></a>
</div>
<!-- 签章失败提示 -->
<div class="m-b-40 line-height-24">
<div>如遇CA签章失败请检查以下步骤:</div>
<div class="color-placeholder">
<div>1是否CA证书已过期</div>
<div class="d-flex align-items-center">
<span class="m-r-8">2是否已正确安装福建省公共资源交易数字证书融合客户端</span>
<div class="btn-box">
<a href="https://ggzyfw.fj.gov.cn/website/packages/福建省公共资源交易数字证书融合客户端.rar">
融合客户端下载
</a>
</div>
</div>
<div>3是否已正确安装对应的CA电子签章客户端</div>
</div>
</div>
<!-- CA驱动下载 -->
<div>
<div class="m-b-16">CA驱动下载</div>
<div class="ca-download-list">
<div class="ca-download-item">
<img src="@/assets/ca-fj.png" />
<div class="btn-box">
<a href="https://ggzyfw.fujian.gov.cn/Website/Packages/福建CA.rar">下载驱动</a>
</div>
</div>
<div class="ca-download-item">
<img src="@/assets/ca-twcx.png" />
<div class="btn-box">
<a href="https://ggzyfw.fujian.gov.cn/Website/Packages/天威诚信.rar">下载驱动</a>
</div>
</div>
<div class="ca-download-item">
<img src="@/assets/ca-cf.jpg" />
<div class="btn-box">
<a href="https://ggzyfw.fujian.gov.cn/Website/Packages/CFCA.rar">下载驱动</a>
</div>
</div>
<div class="ca-download-item">
<img src="@/assets/ca-sz.png" />
<div class="btn-box">
<a href="https://ggzyfw.fujian.gov.cn/Website/Packages/深圳CA.rar">下载驱动</a>
</div>
</div>
</div>
</div>
</div>
<IPC />
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import IPC from '@/components/IPC.vue';
import { replaceState } from '@/utils/url';
import { getSignUrl, getOrderPayUrl } from '@/api';
let timer = 0;
const route = useRoute();
const router = useRouter();
const token = ref(String(route.query.token));
const signUrl = ref('');
// replaceState({});
function handleReload() {
location.reload();
}
async function handleOpenCA() {
const { data } = await getSignUrl({ token: token.value });
signUrl.value = data.signUrl;
window.open(signUrl.value);
loopGetResult();
}
async function loopGetResult() {
clearTimeout(timer);
let isLoop = false;
try {
const { data } = await getOrderPayUrl({ token: token.value });
if (data.status === 'submitted') {
return router.push({ name: 'Callback', query: { token: token.value } });
} else {
isLoop = true;
}
} catch {
isLoop = true;
}
if (isLoop) {
timer = window.setTimeout(loopGetResult, 3000);
}
}
</script>
<style lang="scss" scoped>
.page {
display: flex;
flex-direction: column;
height: 100vh;
}
.page-header {
position: sticky;
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
top: 0;
height: 60px;
font-size: 20px;
background-color: #fff;
> img {
position: absolute;
left: 20px;
width: 70px;
}
}
.page-body {
flex-grow: 1;
margin: 16px auto;
padding: 16px;
max-width: 80vw;
background-color: #fff;
}
.btn-box {
display: inline-block;
padding: 4px 8px;
border: 1px solid rgb(60, 124, 255);
border-radius: 4px;
overflow: hidden;
color: rgb(60, 124, 255);
> a {
color: inherit;
font-size: 14px;
text-decoration: none;
}
}
.jump-tip {
position: relative;
margin-bottom: 16px;
padding-bottom: 16px;
&::after {
content: '';
position: absolute;
left: -16px;
right: -16px;
bottom: 0;
border-bottom: 1px solid #ebeef5;
}
> a {
color: rgb(60, 124, 255);
text-decoration: none;
}
}
.ca-list {
display: grid;
gap: 20px;
grid-template-columns: repeat(4, 1fr);
.ca-item {
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #ebeef5;
border-radius: 6px;
overflow: hidden;
cursor: pointer;
user-select: none;
> img {
max-width: 100%;
object-fit: none;
}
}
}
.ca-download-list {
display: grid;
gap: 20px;
grid-template-columns: repeat(4, 1fr);
.ca-download-item {
display: flex;
align-items: center;
justify-content: center;
gap: 20px;
padding: 20px 8px;
border-radius: 6px;
overflow: hidden;
cursor: pointer;
user-select: none;
background-color: rgb(249, 251, 255);
> img {
width: 150px;
}
}
}
</style>

@ -0,0 +1,120 @@
<template>
<el-dialog
v-model="visible"
:close-on-click-modal="false"
:close-on-press-escape="false"
top="5vh"
title="北京东方保险经纪有限公司"
customClass="customer-notification-dialog"
>
<div class="dialog-content-wrapper">
<div class="m-b-12 text-align-c">客户告知书暨保险经纪服务委托书</div>
<div>
<div>尊敬的客户:</div>
<div>
感谢您委托我公司(北京东方保险经纪有限公司)代为办理保险业务本公司是基于投保人的利益为投保人与保险公司订立保险合同提供中介服务的保险专业中介机构为了保护您的合法权益按照中华人民共和国保险法保险经纪机构监管规定互联网保险业务监管办法的要求本公司应履行客户告知义务现将有关事项告知如下阅读并勾选即表示贵公司完全理解并同意本告知书暨委托协议全部内容
</div>
<div class="m-t-12">
<div>公司的基本情况</div>
<div>()名称: 北京东方保险经纪有限公司</div>
<div>()地址: 北京市朝阳区北辰东路8号3号楼五层50155017</div>
<div>()许可证名称及编号:保险中介许可证编号260453000000800</div>
<div>
()业务范围在全国区域内(台除外)为投保人拟定投保方案选择保险人办理投保手续协助被保险人或者受益人进行索赔再保险经纪业务为委托人提供防灾防损或风险评估风险管理咨询服务中国保监会批准的其他业务
</div>
<div>()经营区域全国(台除外 )</div>
<div>()联系方式010-52131008</div>
</div>
<div class="m-t-12">
<div>投保提示</div>
<div>
()请仔细阅读保险条款重点关注保险责任责任免除被保险人权利义务免赔额或免赔率的计算等内容并可要求本公司业务人员对上述内容进行详细讲解实际保障期限以保单为准
</div>
<div>
()请向本公司客服人员了解中华人民共和国保险法等法律法规对于索赔时效保险公司理赔时限合同终止与失效等相关规定以及不履行如实告知义务故意制造保险事故或夸大事故损失申报年龄不真实等情形导致的法律后果
</div>
</div>
<div class="m-t-12">
<div>保险经纪委托协议内容</div>
<div>()投保人确认委托北京东方保险经纪有限公司作为保险经纪人代表或协助贵公司处理保险相关事宜</div>
<div>
()委托及服务内容本公司作为保险经纪人协助投保人办理保险投保代收代付保险保费为贵公司提供保险咨询报务
</div>
<div>
()保密条款本公司承诺将通过有效的技术手段和管理措施对投保人(被保险人或受益人)的个人信息投保交易信息等非公开信息进行保密严格限制保密信息的接触人妥善保管保密信并在与保险公司的数据交换过程中采用了加密与验证保证交易安全
</div>
<div>()违约责任任意一方违反本协议给对方造成经济损失的应当承担相应的赔偿责任</div>
</div>
<div class="m-t-12">
<div>投诉服务</div>
<div>
如果您发现本公司客服人员存在误导行为及其他损害您合法权益的行为可向本公司投诉投诉电话010-52131008
</div>
</div>
</div>
<div class="text-align-r">
<div class="m-t-12">委托人(本公司)阅读并确认上述内容</div>
<div class="m-t-12">受托人北京东方保险经纪有限公司</div>
</div>
</div>
<template #footer>
<div class="text-align-c">
<el-button type="primary" @click="handleConfirm"></el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
interface EmitsType {
(e: 'confirm'): void;
}
const emits = defineEmits<EmitsType>();
const visible = ref(false);
function open() {
visible.value = true;
}
function handleConfirm() {
emits('confirm');
visible.value = false;
}
defineExpose({
open,
});
</script>
<style lang="scss">
.customer-notification-dialog {
.el-dialog__header {
text-align: center;
}
.el-dialog__body {
padding-top: 0;
padding-bottom: 0;
color: #303030;
}
}
</style>
<style lang="scss" scoped>
.dialog-content-wrapper {
max-height: 75vh;
overflow-y: auto;
}
div {
line-height: 24px;
}
</style>

@ -0,0 +1,110 @@
<template>
<el-dialog
v-model="visible"
:close-on-click-modal="false"
:close-on-press-escape="false"
top="5vh"
title="投保须知及声明"
customClass="customer-notification-dialog2"
>
<div class="dialog-content-wrapper">
<div>
<div>
秉持着依法有序公平公正的原则坚持保密工作投标企业在购买投标保证保险电子保函阶段请认真阅读产品说明投保声明承诺书服务协议保险责任责任免除费用扣除退保投保人被保险人义务等内容请各投标人务必仔细阅读相关条款并认真对待
</div>
<div class="m-t-12">
<div>产品说明</div>
<div>1相关定义</div>
<div>
1)保险机构指经国家金融监管局原银保监会批准设立并依法进行工商登记注册向您提供保险产品及相关服务的金融机构
</div>
<div>2)申请指您借助平台技术支持向保险机构购买产品的行为</div>
<div>
3)保险保函指保险机构在您提出申请请求后经审核同意与您订立保险合同承诺履行保险合同中约定相关责任的行为
</div>
<div>2招标投标活动中的投标人可作为本保险合同的投保人</div>
<div>3招标投标活动中的招标人可作为本保险合同的被保险人</div>
<div>
4凡符合中华人民共和国招标投标法中华人民共和国招标投标法实施条例等法律法规并在中华人民共和国境内(不包括港台地区)开展的招标项目均可适用本保险
</div>
<div>
5保险期限本保险合同的保险期间由投保人与保险人协商约定具体起期日和终止日以保险单上载明的日期为准最长不超过一年
</div>
<div>
6请您根据项目招标文件规定的投标保证金缴纳载止时间前申请保函并支付保费否则一切损失由责公司自负对应保函费用不予退还
</div>
<div>7银行间跨行转账可能导致到账时间延迟为保证您顺利投标请尽量提前1小时以上支付保费</div>
<div>8系统收到保费后将自动出函投标企业可登入投标系统查看保函动态</div>
<div>
9保单形式网上投保为您提供电子保单根据中华人民共和国合同法第十一条规定数据电文是合法的合同表现形式电子保单与纸质保单具有同等法律效力
</div>
<div>10本保险产品由北京东方保险经纪提供保险经纪服务保单(保函)凭证及发票由各保险公司提供</div>
</div>
<div class="m-t-12">
<div>
投保声明本单位(或员工)已完整阅读并了解以上投保须知及投保险种的保险条款尤其是对其中免除保险人责任的条款或约定(包括但不限于责任免除投保人被保险人义务保险金申请与给付等)本人已充分理解并接受上述内容同意以此作为订立保险合同的依据
</div>
<div>
投保单中所填写的内容均属实如有隐瞒或不实告知你公司有权解除保险合同对于合同解除前发生的任何事故你公司可不承担任何责任本单位(或员工)确认并同意您在使用平台服务过程中与保险公司提供的保险凭证产生的任何争议或纠纷与招标人或招标代理人(保险受益人)因投标保证保险(凭证)产生的任何争议或纠纷均与平台无关您应与相关方自行协商解决
</div>
</div>
</div>
</div>
<template #footer>
<div class="text-align-c">
<el-button type="primary" @click="handleConfirm"></el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
interface EmitsType {
(e: 'confirm'): void;
}
const emits = defineEmits<EmitsType>();
const visible = ref(false);
function open() {
visible.value = true;
}
function handleConfirm() {
emits('confirm');
visible.value = false;
}
defineExpose({
open,
});
</script>
<style lang="scss">
.customer-notification-dialog2 {
.el-dialog__header {
text-align: center;
}
.el-dialog__body {
padding-top: 0;
padding-bottom: 0;
color: #303030;
}
}
</style>
<style lang="scss" scoped>
.dialog-content-wrapper {
max-height: 75vh;
overflow-y: auto;
}
div {
line-height: 24px;
}
</style>

@ -0,0 +1,221 @@
<template>
<el-dialog
v-model="visible"
:close-on-click-modal="false"
:close-on-press-escape="false"
top="5vh"
title="修改投保人信息"
customClass="modify-dialog"
>
<div class="dialog-content-wrapper">
<!-- 投保人信息 -->
<div class="page-card">
<div>
<div class="card-content">
<div>
<div class="d-flex align-items-center">
<div class="card-label">企业名称</div>
<el-input v-model="formData.applicantName" clearable />
</div>
<div class="d-flex align-items-center">
<div class="card-label">联系人姓名</div>
<el-input v-model="formData.contactName" clearable />
</div>
<div class="d-flex align-items-center">
<div class="card-label">开户行(基本户)</div>
<el-input v-model="formData.bankName" clearable />
</div>
<div class="d-flex align-items-center">
<div class="card-label">接收发票的邮箱</div>
<el-input v-model="formData.invoiceAcceptEmail" clearable />
</div>
</div>
<div>
<div class="d-flex align-items-center">
<div class="card-label">统一社会信用代码</div>
<el-input v-model="formData.creditCode" clearable />
</div>
<div class="d-flex align-items-center">
<div class="card-label">联系人手机号</div>
<el-input v-model="formData.contactMobile" clearable />
</div>
<div class="d-flex align-items-center">
<div class="card-label">银行账号</div>
<el-input v-model="formData.bankCardNum" clearable />
</div>
<div class="d-flex align-items-center">
<div class="card-label">发票类型</div>
<el-select v-model="formData.invoiceType" class="flex-grow-1" placeholder="请选择" disabled>
<el-option value="专票">专票</el-option>
<el-option value="普票">普票</el-option>
</el-select>
</div>
</div>
</div>
</div>
</div>
</div>
<template #footer>
<div class="text-align-c">
<el-button type="primary" @click="handleConfirm"></el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { cloneDeep } from 'lodash-es';
import { ref, reactive } from 'vue';
import { useLoading } from '@/hooks';
import { successAlert } from '@/utils/alert';
import { updateApplicant } from '@/api/index';
import type { Order } from '@/api';
import type { UpdateApplicantParams } from '@/api/index';
interface PropsType {
order: Order;
token: string;
}
interface EmitsType {
(e: 'confirm', val: Order): void;
}
const emits = defineEmits<EmitsType>();
const props = defineProps<PropsType>();
const visible = ref(false);
const formData = reactive<UpdateApplicantParams>({
token: '',
applicantName: '',
creditCode: '',
contactName: '',
contactMobile: '',
bankName: '',
bankCardNum: '',
invoiceAcceptEmail: '',
invoiceType: '',
});
const { openLoading, closeLoading } = useLoading();
function open() {
visible.value = true;
initFormData();
}
function initFormData() {
formData.token = props.token;
formData.applicantName = props.order.Applicant.ApplicantName;
formData.creditCode = props.order.Applicant.CreditCode;
formData.contactName = props.order.Applicant.ContactName;
formData.contactMobile = props.order.Applicant.ContactMobile;
formData.invoiceAcceptEmail = props.order.Applicant.InvoiceAcceptEmail;
formData.invoiceType = props.order.Applicant.InvoiceType;
formData.bankName = props.order.User.BankName;
formData.bankCardNum = props.order.User.BankCardNum;
}
async function handleConfirm() {
try {
openLoading();
await updateApplicant(formData);
const newOrder = cloneDeep(props.order);
newOrder.Applicant.ApplicantName = formData.applicantName;
newOrder.Applicant.CreditCode = formData.creditCode;
newOrder.Applicant.ContactName = formData.contactName;
newOrder.Applicant.ContactMobile = formData.contactMobile;
newOrder.Applicant.InvoiceAcceptEmail = formData.invoiceAcceptEmail;
newOrder.Applicant.InvoiceType = formData.invoiceType;
newOrder.User.BankName = formData.bankName;
newOrder.User.BankCardNum = formData.bankCardNum;
emits('confirm', newOrder);
visible.value = false;
successAlert('修改成功');
} finally {
closeLoading();
}
}
defineExpose({
open,
});
</script>
<style lang="scss">
.modify-dialog {
.el-dialog__header {
text-align: center;
}
.el-dialog__body {
padding-top: 0;
padding-bottom: 0;
color: #303030;
}
}
</style>
<style lang="scss" scoped>
.page-card {
flex: 1;
margin-top: 16px;
padding: 16px;
border-radius: 6px;
background-color: #fff;
box-shadow: 0 0 10px #ddd;
.card-title {
position: relative;
display: flex;
align-items: center;
margin-bottom: 8px;
padding-left: 10px;
font-size: 20px;
&::after {
content: '';
position: absolute;
top: 50%;
left: 0;
width: 4px;
height: 16px;
transform: translateY(-50%);
background-color: rgb(36, 127, 255);
}
}
.card-content {
display: flex;
> div {
display: flex;
flex-direction: column;
gap: 12px;
width: 50%;
.card-label {
flex-shrink: 0;
width: 10em;
color: #898b8f;
text-align: right;
font-size: 16px;
& + .card-label {
margin-top: 4px;
}
}
}
}
}
</style>

@ -0,0 +1,188 @@
<template>
<el-dialog
v-model="visible"
:close-on-click-modal="false"
:close-on-press-escape="false"
top="5vh"
title="修改开票信息"
customClass="modify-dialog"
>
<div class="dialog-content-wrapper">
<div class="page-card">
<div>
<div class="card-content">
<div>
<div class="d-flex align-items-center">
<div class="card-label">发票抬头</div>
<el-input v-model="formData.header" clearable />
</div>
<div class="d-flex align-items-center">
<div class="card-label">开户银行</div>
<el-input disabled />
</div>
<div class="d-flex align-items-center">
<div class="card-label">企业地址</div>
<el-input disabled />
</div>
</div>
<div>
<div class="d-flex align-items-center">
<div class="card-label">税号</div>
<el-input v-model="formData.taxNumber" clearable />
</div>
<div class="d-flex align-items-center">
<div class="card-label">银行账号</div>
<el-input disabled />
</div>
<div class="d-flex align-items-center">
<div class="card-label">企业电话</div>
<el-input disabled />
</div>
</div>
</div>
</div>
</div>
</div>
<template #footer>
<div class="text-align-c">
<el-button type="primary" @click="handleConfirm"></el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive } from 'vue';
import { useLoading } from '@/hooks';
import { successAlert } from '@/utils/alert';
import { updateInvoice } from '@/api/index';
import type { Invoice } from '@/api';
import type { UpdateInvoiceParams } from '@/api/index';
interface PropsType {
token: string;
invoice: null | Invoice;
}
interface EmitsType {
(e: 'confirm', val: Invoice): void;
}
const emits = defineEmits<EmitsType>();
const props = defineProps<PropsType>();
const visible = ref(false);
const formData = reactive<UpdateInvoiceParams>({
token: '',
header: '',
taxNumber: '',
});
const { openLoading, closeLoading } = useLoading();
function open() {
visible.value = true;
initFormData();
}
function initFormData() {
formData.token = props.token;
formData.header = props.invoice?.Header ?? '';
formData.taxNumber = props.invoice?.TaxNumber ?? '';
}
async function handleConfirm() {
try {
openLoading();
await updateInvoice(formData);
const newInvoice: Invoice = { Header: '', TaxNumber: '' };
newInvoice.Header = formData.header;
newInvoice.TaxNumber = formData.taxNumber;
emits('confirm', newInvoice);
visible.value = false;
successAlert('修改成功');
} finally {
closeLoading();
}
}
defineExpose({
open,
});
</script>
<style lang="scss">
.modify-dialog {
.el-dialog__header {
text-align: center;
}
.el-dialog__body {
padding-top: 0;
padding-bottom: 0;
color: #303030;
}
}
</style>
<style lang="scss" scoped>
.page-card {
flex: 1;
margin-top: 16px;
padding: 16px;
border-radius: 6px;
background-color: #fff;
box-shadow: 0 0 10px #ddd;
.card-title {
position: relative;
display: flex;
align-items: center;
margin-bottom: 8px;
padding-left: 10px;
font-size: 20px;
&::after {
content: '';
position: absolute;
top: 50%;
left: 0;
width: 4px;
height: 16px;
transform: translateY(-50%);
background-color: rgb(36, 127, 255);
}
}
.card-content {
display: flex;
> div {
display: flex;
flex-direction: column;
gap: 12px;
width: 50%;
.card-label {
flex-shrink: 0;
width: 10em;
color: #898b8f;
text-align: right;
font-size: 16px;
& + .card-label {
margin-top: 4px;
}
}
}
}
}
</style>

@ -0,0 +1,776 @@
<template>
<div style="margin: 60px; padding: 50px">
<!-- 抬头 -->
<div
style="
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 1px solid #bbb;
"
>
<img src="@/assets/pdf-logo.png" style="width: 300px" />
<div style="width: 260px; font-size: 20px; font-weight: bold">注意:请认真阅读所附条款 尤其是黑体部分内容</div>
</div>
<!-- 说明 -->
<div>
<div style="margin-bottom: 10px; text-align: center; font-size: 24px; font-weight: bold">投标保证保险投保单</div>
<div style="text-indent: 2em">
在您填写本投保单前请仔细阅读紫金财产保险股份有限公司投标保证保险条款 特别注意条款中有 关保险责任
免除保险人责任和投保人被保险人义务的规定 同时听取本公司就条款所做的说明 并可就
其中内容要求本公司做出解释在您已充分理解保险条款后请您如实填写本投保单并签章确认
</div>
</div>
<div style="margin: 20px 0; border: 1px solid #000">
<!-- 投保人 -->
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: 1em; border-right: 1px solid #000">投保人 (投标人)</div>
<div style="flex-grow: 1">
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">
法人名称/
<br />
自然人姓名
</div>
<div style="padding: 10px">{{ order.Applicant.ApplicantName }}</div>
</div>
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">证件类型</div>
<!-- TODO -->
<div style="flex-grow: 1; padding: 10px; border-right: 1px solid #000">{{}}</div>
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">证件号码</div>
<div style="padding: 10px; width: 20em">{{ order.Applicant.CreditCode }}</div>
</div>
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">法人性质</div>
<!-- TODO -->
<div style="flex-grow: 1; padding: 10px; border-right: 1px solid #000">
<span style="margin-right: 20px"><input type="checkbox" />国有</span>
<span style="margin-right: 20px"><input type="checkbox" />集体</span>
<span style="margin-right: 20px"><input type="checkbox" />民营</span>
<span style="margin-right: 20px"><input type="checkbox" />私营</span>
<span style="margin-right: 20px"><input type="checkbox" />外资</span>
<span style="margin-right: 20px"><input type="checkbox" />合资</span>
<span style="margin-right: 20px"><input type="checkbox" />其他</span>
</div>
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">法人资质</div>
<!-- TODO -->
<div style="padding: 10px; width: 20em">
<span style="margin-right: 20px"><input type="checkbox" />特级</span>
<span style="margin-right: 20px"><input type="checkbox" />一级</span>
<span style="margin-right: 20px"><input type="checkbox" />二级</span>
<span style="margin-right: 20px"><input type="checkbox" />三级</span>
</div>
</div>
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">联系人</div>
<div style="flex-grow: 1; padding: 10px; border-right: 1px solid #000">
{{ order.Applicant.ContactName }}
</div>
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">联系号码</div>
<div style="padding: 10px; width: 20em">{{ order.Applicant.ContactMobile }}</div>
</div>
<div style="display: flex">
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">地址</div>
<div style="padding: 10px">
{{ order.Applicant.Province }} {{ order.Applicant.City }} {{ order.Applicant.District }}
{{ order.Applicant.Address }}
</div>
</div>
</div>
</div>
<!-- 被保险人 -->
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: 1em; border-right: 1px solid #000">被保险人 (招标人)</div>
<div style="flex-grow: 1">
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">
法人名称/
<br />
自然人姓名
</div>
<div style="padding: 10px">{{ order.Assured.AssuredName }}</div>
</div>
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">证件类型</div>
<!-- TODO -->
<div style="flex-grow: 1; padding: 10px; border-right: 1px solid #000">{{}}</div>
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">证件号码</div>
<div style="padding: 10px; width: 20em">{{ order.Assured.CreditVld }}</div>
</div>
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">招标文件编号</div>
<div style="padding: 10px">{{ order.Project.TpID }}</div>
</div>
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">联系人</div>
<div style="flex-grow: 1; padding: 10px; border-right: 1px solid #000">
{{ order.Assured.ContactName }}
</div>
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">联系号码</div>
<div style="padding: 10px; width: 20em">{{ order.Assured.ContactMobile }}</div>
</div>
<div style="display: flex">
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">地址</div>
<div style="padding: 10px">
{{ order.Assured.Province }} {{ order.Assured.City }} {{ order.Assured.District }}
{{ order.Assured.Address }}
</div>
</div>
</div>
</div>
<!-- 投标项目 -->
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: 1em; border-right: 1px solid #000">投标项目</div>
<div style="flex-grow: 1">
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">项目名称</div>
<div style="flex-grow: 1; padding: 10px; border-right: 1px solid #000">{{ order.Project.Name }}</div>
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">立项文件号</div>
<!-- TODO -->
<div style="padding: 10px; width: 20em">{{}}</div>
</div>
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">项目性质</div>
<div style="padding: 10px">{{ order.Project.TenderProjectType }}</div>
</div>
<div style="display: flex">
<div style="padding: 10px; width: 10em; border-right: 1px solid #000">项目预计金额</div>
<div style="padding: 10px">
<div>人民币大写{{ order.Project.BuildPrice }}</div>
<div><span style="opacity: 0">人民币</span>小写:{{ order.Project.BuildPrice }}</div>
</div>
</div>
</div>
</div>
<!-- 保险金额 -->
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: calc(11em + 21px); border-right: 1px solid #000">保险金额</div>
<div style="flex-grow: 1">
<div style="display: flex">
<div style="flex-grow: 1; padding: 10px">大写{{ order.Project.Amount }}</div>
<div style="padding: 10px; width: 20em; border-right: 1px solid #000">小写{{ order.Project.Amount }}</div>
</div>
</div>
</div>
<!-- 保险费 -->
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: calc(11em + 21px); border-right: 1px solid #000">保险费</div>
<div style="flex-grow: 1">
<div style="display: flex">
<!-- TODO -->
<div style="flex-grow: 1; padding: 10px">大写{{}}</div>
<!-- TODO -->
<div style="padding: 10px; width: 20em; border-right: 1px solid #000">小写:{{}}</div>
</div>
</div>
</div>
<!-- 绝对免赔额/免赔率 -->
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: calc(11em + 21px); border-right: 1px solid #000">绝对免赔额/免赔率</div>
<!-- TODO -->
<div style="flex-grow: 1; padding: 10px">/</div>
</div>
<!-- 保险期间 -->
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: calc(11em + 21px); border-right: 1px solid #000">保险期间</div>
<!-- TODO -->
<div style="flex-grow: 1; padding: 10px">/</div>
</div>
<!-- 特别约定 -->
<div style="display: flex">
<div
style="
flex-shrink: 0;
padding: 10px;
width: calc(11em + 21px);
border-right: 1px solid #000;
border-bottom: 1px solid #000;
"
>
特别约定
</div>
<div style="flex-grow: 1; padding: 10px; border-bottom: 1px solid #000; font-size: 13px">
<div>
1本保单为见索即付保单本保单发生保险事故由保险人先行赔付后享有对
投保人的代位求偿权2本保单项下本保险在投标有效期到期后28日()内或被保
险人延长投标有效期后到期日后28日()内保持有效延长投标有效期无需通知本保险
但任何索赔要求应在投标有效期内送达我方保险失效后由平台将本保单交投标人
退回我司注销3兹承诺在收到被保险人书面通知说明下列中的任何一条时
证在10日内无条件给付给被保险人金额为不超过保险金额的款项1)投保人在投标有效
期内撤销或修改其投标文件的2)投保人在中标后非因不可抗力原因放弃中标无正
当理由不与招标人订立合同在签订合同时向招标人提出附加条件或者不按招标文件
要求提交履约担保金的3)投标人的投标文件存在福建省住房和城乡建设厅关于施工
招标项目电子投标文件置同认定与处理的指导意见 (闽建筑[2018]29)规定的雷同情
形之一4)投标人中标后因违法行为导致中标被依法确认无效的5) 法律法规规定
的其他没收投标保险金情形4我单位在收到招标人索赔申请后10日内无条件给予先
行支付预赔款赔付流程将根据我单位向宁德市公共资源交易中心提供的金融机构理
赔流程标准执行本保险项下所有权利和义务均受中华人民共和国法律管辖和制约
查验保函网址:http://www.zking.com/dzbdxzcx.jhtml
</div>
<div>
尊敬的客户您可以通过电话95312公司柜面或登陆公司网站
www.zking.com查询您的保单信息状态以及理赔情况如您对查询结果有异议 请及时致电本公司
</div>
<div>无其他特别约定</div>
</div>
</div>
<!-- 保险合同争议解决方式 -->
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: calc(11em + 21px); border-right: 1px solid #000">保险合同争议解决方式</div>
<div style="flex-grow: 1; padding: 10px">诉讼</div>
</div>
<!-- 司法管辖 -->
<div style="display: flex; border-bottom: 1px solid #000">
<div style="padding: 10px; width: calc(11em + 21px); border-right: 1px solid #000">司法管辖</div>
<div style="flex-grow: 1; padding: 10px">中华人民共和国管辖(港澳台除外)</div>
</div>
<!-- 偿付能力信息 -->
<div style="display: flex">
<div style="padding: 10px; width: calc(11em + 21px); border-right: 1px solid #000">偿付能力信息</div>
<div style="flex-grow: 1; padding: 10px">
我公司最近季度的综合偿付能力充足率和风险综合评级结果告知如下:
<br />
1我公司2024年1季度综合偿付能力充足率:339.97%已达到政府监管要求
<br />
2我公司2024年1季度核心偿付能力充足率:262.64%已达到政府监管要求
<br />
3我公司2023年4季度风险综合评级:AAA级
</div>
</div>
</div>
<div>
投保人声明贵公司已向本人交付并详细介绍了紫金财产保险股份有限公司投标保证保险条款 的内容
别是对保险合同中免除保险人责任的条款和投保人被保险人义务的内容做了明确说明本人已知悉其涵义
同意投保并以此投保单作为订立保险合同的依据
</div>
<div style="margin: 50px 0; text-align: right">
投保人签章
<span style="display: inline-block; width: 30px" />
<span style="display: inline-block; width: 30px" />
<span style="display: inline-block; width: 30px" />
</div>
<div style="margin-bottom: 50px; text-align: center; font-size: 20px; font-weight: bold">
<div style="margin-bottom: 10px">紫金财产保险股份有限公司</div>
<div style="margin-bottom: 10px">投标保证保险2021 条款</div>
<div style="margin-bottom: 10px">注册编号C00013731412021102203263</div>
<div style="margin-bottom: 10px">备案号 (紫金保险)(-保证保险)2022 () 001 </div>
</div>
<!-- 总则 -->
<div style="margin-bottom: 30px; padding: 0 50px">
<div style="margin-bottom: 30px; text-align: center; font-weight: bold">总则</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第一条</span>
本保险合同由保险条款投保单保险单保险凭证批单和特别约定组成 凡涉及本保险合同的约定均应采取书面形式
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第二条</span>
本保险合同的投保人是指响应招标人特定或不特定邀请参加投标竞争的法人 或其他组织即投标人
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第三条</span>
本保险合同的被保险人是指在招标投标活动中以择优选择中标人为目的提出招标项目进行招标的法人或其他组织即招标人
</div>
</div>
<!-- 保险责任 -->
<div style="margin-bottom: 30px; padding: 0 50px">
<div style="margin-bottom: 30px; text-align: center; font-weight: bold">保险责任</div>
<div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第四条</span>
在保险期间内投保人在投标过程中因存在如下情形导致其根据中华人民共
和国招标投标法中华人民共和国招标投标法实施条例的相关规定或招标文件的约定
须向被保险人承担经济赔偿责任的被保险人可向保险人提出索赔保险人依据本保险合同
的约定在保险金额范围内承担赔偿责任
</div>
<div>
<div style="margin-bottom: 10px">投标截止后投保人未经被保险人同意撤销投标文件</div>
<div style="margin-bottom: 10px">投保人与其他投标人互相串通</div>
<div style="margin-bottom: 10px">投保人以他人名义投标或以其他方式弄虚作假骗取中标</div>
<div style="margin-bottom: 10px">
投保人无正当理由在接到中标通知书后未在相关法律法规或招标文件要求的时限 内签订合同
</div>
<div>投保人违反招标文件或者在参加投标活动中存在其他实质性违反诚实信用原则的 行为</div>
</div>
</div>
</div>
<!-- 责任免除 -->
<div style="margin-bottom: 30px; padding: 0 50px">
<div style="margin-bottom: 30px; text-align: center; font-weight: bold">责任免除</div>
<div style="margin-bottom: 20px">
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第五条</span> 如出现下列任一情形保险人不承担保险责任
</div>
<div style="margin-bottom: 10px">
投保人与被保险人签订的合同经人民法院或仲裁机构认定不成立不生效 被撤销被解除的
</div>
<div style="margin-bottom: 10px">投保人与被保险人互相串通为投保人谋取中标</div>
<div style="margin-bottom: 10px">被保险人未按招标文件的要求履行相关义务的</div>
<div style="margin-bottom: 10px">投保人和被保险人未经保险人同意更改招标文件内容损害保险人利益的</div>
<div style="margin-bottom: 10px">
投保人与被保险人订立的协议或合同背离招标文件及中标人投标文件实质性内容
</div>
<div style="margin-bottom: 10px">被保险人及其代表的故意行为犯罪行为</div>
<div style="margin-bottom: 10px">所有投标被否决被保险人重新招标的</div>
<div style="margin-bottom: 10px">被保险人同意投保人在投标截止日后撤销投标文件</div>
</div>
<div style="margin-bottom: 20px">
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第六条</span> 下列原因造成的损失和费用保险人不负责赔偿
</div>
<div>
<div style="margin-bottom: 10px">战争敌对行为军事行为武装冲突罢工骚乱暴动恐怖活动</div>
<div style="margin-bottom: 10px">核辐射核爆炸核污染及其他放射性污染</div>
<div style="margin-bottom: 10px">大气污染土地污染水污染及其他各种污染</div>
<div style="margin-bottom: 10px">行政行为或司法行为</div>
<div style="margin-bottom: 10px">洪水台风地震海啸等自然灾害</div>
</div>
</div>
<div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第七条</span>
下列损失和费用保险人不负责赔偿
</div>
<div style="margin-bottom: 10px">
被保险人根据招标文件的要求应承担的责任 以及为收集确认证明投保人 造成损失所产生的任何费用
</div>
<div style="margin-bottom: 10px">
被保险人与投保人就招标投标活动产生纠纷所致的任何法律费用包括但不限
于诉讼或仲裁费财产保全或证据保全费强制执行费评估费拍卖费鉴定费律师 差旅费调查取证费等
</div>
<div style="margin-bottom: 10px">本保险合同载明的免赔额或根据本保险合同载明的免赔率计算的免赔额</div>
<div style="margin-bottom: 10px">被保险人以外的任何第三方的损失</div>
<div style="margin-bottom: 10px">各类间接损失</div>
<div style="margin-bottom: 10px">罚款罚金及惩罚性赔偿</div>
<div style="margin-bottom: 10px">因不可归责于投保人而导致的被保险人的损失</div>
<div style="margin-bottom: 10px">
本保险合同中载明的免赔额或按本保险合同中载明的免赔率计算的免赔额
</div>
<div style="margin-bottom: 10px">其他不属于本保险责任范围内的损失费用和责任</div>
</div>
</div>
<!-- 保险金额和免赔率 -->
<div style="margin-bottom: 30px; padding: 0 50px">
<div style="margin-bottom: 30px; text-align: center; font-weight: bold">保险金额和免赔率</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第八条</span>
保险金额是保险人承担赔偿责任的最高限额本保险合同的保险金额以招标投
标文件中投标保证金的相关要求为基础通过投保人与保险人协商确定保险金额并在保险 合同中载明
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第九条</span>
免赔率指被保险人在保险事故中自行承担损失金额的部分每次保险 事故免赔率
由投保人与保险人在签订保险合同时协商确定并在保险合同中载明
</div>
<div style="font-weight: bold">
保险合同中同时载明了免赔额和免赔率的免赔金额以免赔额和按照免赔率计算的金 额中的高者为准
</div>
</div>
<!-- 保险期间 -->
<div style="margin-bottom: 30px; padding: 0 50px">
<div style="margin-bottom: 30px; text-align: center; font-weight: bold">保险期间</div>
<div>
<span style="margin-right: 10px; font-weight: bold">第十条</span>
本保险合同保险期间自投标截止次日起或保险单载明的保险起期之日起二者
以后发生者为准至中标人与被保险人签订合同之日止或保险单载明的保险止期之日止
者以先发生者为准本保险合同保险期间最长不得超过 12 个月
</div>
</div>
<!-- 保险费 -->
<div style="margin-bottom: 30px; padding: 0 50px">
<div style="margin-bottom: 30px; text-align: center; font-weight: bold">保险费</div>
<div>
<span style="margin-right: 10px; font-weight: bold">第十一条</span>
本保险合同的保险费由保险人根据投保人企业资质等级招标项目类型 险金额等因素确定并在保险单上载明其金额
</div>
</div>
<!-- 保险人义务 -->
<div style="margin-bottom: 30px; padding: 0 50px">
<div style="margin-bottom: 30px; text-align: center; font-weight: bold">保险人义务</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第十二条</span>
订立本保险合同时采用保险人提供的格式条款的保险人向投保人提供的
投保单应当附格式条款保险人应当向投保人说明本保险合同的内容对本保险合同中免除
保险人责任的条款保险人在订立保险合同时应当在投保单保险单或者其他保险凭证上做
出足以引起投保人注意的提示并对该条款内容以书面形式或者口头形式向投保人做出明确
说明未作提示或者明确说明的该条款不产生效力
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第十三条</span>
本保险合同成立后保险人应当及时向投保人签发保险单或其他保险凭证
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第十四条</span>
保险人按照本保险合同的约定认为被保险人提供的有关索赔的证明和资料
不完整的应当及时一次性通知投保人被保险人补充
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第十五条</span>
保险人收到被保险人的赔偿保险金的请求后应当及时作出是否属于保险责
任的核定情形复杂的应当在三十日内作出核定但本保险合同另有约定的除外
</div>
<div style="margin-bottom: 10px">
保险人应当将核定结果通知被保险人对属于保险责任的在与被保险人达成赔偿保险
金的协议后十日内履行赔偿保险金义务本保险合同对赔偿保险金的期限有约定的保险
人应当按照约定履行赔偿保险金的义务保险人依照前款约定做出核定后对不属于保险责
任的应当自做出核定之日起三日内向被保险人发出拒绝赔偿保险金通知书并说明理由
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第十六条</span>
保险人自收到赔偿保险金的请求和有关证明资料之日起六十日内对其赔
偿保险金的数额不能确定的应当根据已有证明和资料可以确定的数额先予支付保险人最
终确定赔偿的数额后应当支付相应差额
</div>
</div>
<!-- 投保人被保险人义务 -->
<div style="margin-bottom: 30px; padding: 0 50px">
<div style="margin-bottom: 30px; text-align: center; font-weight: bold">投保人被保险人义务</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第十七条</span>
订立本保险合同保险人就投保风险的情况以及投保人被保险人的有关情 况提出询问的投保人应当如实告知
</div>
<div style="margin-bottom: 10px; font-weight: bold">
投保人故意或者因重大过失未履行前款规定的如实告知义务足以影响保险人决定是
否同意承保或者提高保险费率的保险人有权解除合同
</div>
<div style="margin-bottom: 10px">
前款规定的合同解除权 自保险人知道有解除事由之日起超过三十日不行使而消灭
自合同成立之日起超过二年的保险人不得解除合同发生保险事故的保险人应当承担赔 偿或者给付保险金的责任
</div>
<div style="margin-bottom: 10px">
保险人在合同订立时已经知道投保人未如实告知的情况的保险人不得解除合同发生
保险事故的保险人应当承担赔偿或者给付保险金的责任
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第十八条</span>
除本保险合同另有约定外投保人应当在本保险合同成立时一次性交清本保 险合同约定的全部保险费
<span style="font-weight: bold">
投保人未按约定交付保险费保险合同不生效对于保险费交 付前发生的保险事故保险人不承担赔偿责任
</span>
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第十九条</span>
申请投保时投保人应如实填写投保单提供保险人要求的必要证明资料 并接受保险人对其资质进行审查
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第二十条</span>
投保人有义务配合保险人的资质审查工作在保险人审查期间投保人应当
配合保险人或由保险人雇佣的审计人员或者其他独立第三方对其提供的信息和文件进行准 确的核查
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第二十一条</span>
在保险期间内被保险人应及时检查并协助保险人了解招标工作进行情况
被保险人如发现投保人存在违约风险或有任何其他可能导致本保险合同风险显著增加的情
被保险人应在其能力范围内采取一切合理且必要的措施降低或消除上述风险并应按照 本保险合同约定及时通知保险人
</div>
<div style="margin-bottom: 10px">保险事故发生后被保险人应及时做好记录并及时书面通知保险人</div>
<div style="margin-bottom: 10px">
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第二十三条</span> 知道保险事故发生后
</div>
<div style="margin-bottom: 10px">
被保险人应该尽力采取必要合理的措施防止或减少损失否则
<span style="font-weight: bold">对因此扩大 的损失保险人不负责赔偿 </span>
</div>
<div style="margin-bottom: 10px">
投保人被保险人应及时通知保险人并书面说明事故发生的原因经过损失 情况和处理情况
<span style="font-weight: bold">
故意或者因重大过失未及时通知致使保险事故的性质原因损失程
度等难以确定的保险人对无法确定的部分不承担赔偿责任
</span>
但保险人通过其他途径已 经及时知道或者应当及时知道保险事故发生的除外对涉及违法犯罪的投保人或被保险
人应立即向公安机关报案
</div>
<div style="margin-bottom: 10px">
被保险人应完整保留其项目招标投标过程中的相关文件和资料允许并协助保险 人对事故进行调查
<span style="font-weight: bold">
对于妨碍保险人进行事故调查导致无法确定事故原因或核实损失情况
保险人对无法确定或核实的部分不承担赔偿责任
</span>
</div>
</div>
<div style="margin-bottom: 10px">
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第二十四条</span>
被保险人提出索赔申请时应向保险人提供下列书面证明和资料
</div>
<div style="margin-bottom: 10px">索赔申请书</div>
<div style="margin-bottom: 10px">保险单正本</div>
<div style="margin-bottom: 10px">招标文件</div>
<div style="margin-bottom: 10px">投保人的投标文件及相关文件</div>
<div>
<div style="margin-bottom: 10px">与招标投标项目有关的文件资料分情形具体包括</div>
<div style="margin-bottom: 10px">
1.投标截止后投保人未经被保险人同意撤销投标文件的须提供投保人的撤销申请或相 关证明
</div>
<div style="margin-bottom: 10px">2.投保人与其他投标人互相串通的须提供相互串通的证明</div>
<div style="margin-bottom: 10px">
3.投保人以他人名义投标或以其他方式弄虚作假骗取中标的须提供冒名投标或其他 弄虚作假行为的证明
</div>
<div style="margin-bottom: 10px">
4.投保人无正当理由在接到中标通知书后未在相关法律法规或招标文件要求的时限内
签订合同的须提供中标通知书及被保险人就签订合同时限内未与投保人签订合同的声明
</div>
</div>
<div style="margin-bottom: 10px">
投保人被保险人所能提供的与确认保险事故的性质原因损失程度等有关的 其他证明和资料
</div>
<div style="margin-bottom: 10px">保险人要求的作为请求赔偿依据的合理有效的其他证明材料</div>
<div style="margin-bottom: 10px; font-weight: bold">
被保险人未履行前款约定的索赔材料提供义务导致保险人无法核实损失情况的
险人对无法核实的部分不承担赔偿责任
</div>
</div>
</div>
<!-- 赔偿处理 -->
<div style="margin-bottom: 30px; padding: 0 50px">
<div style="margin-bottom: 30px; text-align: center; font-weight: bold">赔偿处理</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第二十五条</span>
被保险人向保险人提出索赔申请前应按招标文件的相关要求向投保人启 动索赔程序
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第二十六条</span>
保险事故发生后保险人对于被保险人无法通过向投保人索赔获得补偿的 合理损失
<span style="font-weight: bold">
在扣减本保险合同载明的免赔额或按免赔率计算的金额后进行赔偿但最高不 超过本保险合同载明的保险金额
</span>
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第二十七条</span>
发生保险事故时如果被保险人的损失在有相同保障的其他保险合同项
下也能够获得赔偿则本保险人按照本保险合同的保险金额与其他保险合同及保险合同相
应的保险金额的总和比例承担赔偿责任
</div>
<div style="margin-bottom: 10px; font-weight: bold">
应由其他保险人承担的赔偿金额本保险人不负责垫付若被保险人未如实告知导致
保险人多支付赔偿金的保险人有权向被保险人追回多支付的部分
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第二十八条</span>
发生保险责任范围内的损失保险人自向被保险人赔偿保险金之日起
在赔偿金额范围内代为行使被保险人对投保人或其担保人如有请求赔偿的权利被保
险人应当向保险人提供必要的文件和所知道的有关情况积极协助保险人向投保人或其担 保人如有进行追偿
</div>
<div style="margin-bottom: 10px">
被保险人已经从投保人或其担保人如有处取得赔偿的保险人赔偿保险金时
以相应扣减被保险人已从投保人或其担保人如有处取得的赔偿金额
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第二十九条</span>
保险事故发生后在保险人未赔偿保险金之前被保险人放弃对投保人
或其担保人如有请求赔偿的权利保险人不承担赔偿责任保险人向被保险人赔偿保
险金后被保险人未经保险人同意放弃对投保人或其担保人如有请求赔偿的权利的 该行为无效
由于被保险人故意或者因重大过失致使保险人不能行使代位请求赔偿的权利 保险人可以扣减或者要求返还相应的保险金
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第三十条</span>
未发生保险事故被保险人谎称发生了保险事故 向保险人提出赔偿请求 保险人有权解除保险合同并不退还保险费
</div>
<div style="margin-bottom: 10px">
投保人被保险人故意制造保险事故的保险人有权解除保险合同不承担赔偿责任 不退还保险费
</div>
<div style="margin-bottom: 10px">
保险事故发生后投保人被保险人以伪造变造的有关证明资料或者其他证据
编造虚假的事故原因或夸大损失程度的保险人对其虚报的部分不承担赔偿责任
</div>
<div style="margin-bottom: 10px">
投保人被保险人有前三款规定行为之一致使保险人支付保险金或者支出费用的 应当退回或赔偿
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第三十一条</span>
保险人受理报案向被保险人提供建议等行为均不构成保险人对赔偿 责任的承诺
</div>
<div style="margin-bottom: 10px">
被保险人向保险人请求赔偿保险金的诉讼时效期间为二年自其知道或应当知道保险事 故发生之日起计算
</div>
</div>
<!-- 合同终止 -->
<div style="margin-bottom: 30px; padding: 0 50px; font-weight: bold">
<div style="margin-bottom: 30px; text-align: center">合同终止</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px">第三十二条</span>
当发生下列情形之一时以最先发生者为准本保险合同终止
</div>
<div style="margin-bottom: 10px">1保险单载明的保险期间届满</div>
<div style="margin-bottom: 10px">2投保人未中标</div>
<div style="margin-bottom: 10px">3保险人根据本保险合同支付的保险赔偿总金额已经达到保险单所载明的保险金额</div>
</div>
<!-- 争议处理和法律适用 -->
<div style="margin-bottom: 30px; padding: 0 50px">
<div style="margin-bottom: 30px; text-align: center; font-weight: bold">争议处理和法律适用</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第三十三条</span>
因履行本保险合同发生的争议由当事人协商解决协商不成的提交保
险合同载明的仲裁机构仲裁保险合同未载明仲裁机构并且争议发生后双方就仲裁机构未达
成仲裁协议的当事人均有权向中华人民共和国人民法院起诉
</div>
<div style="margin-bottom: 10px">本保险合同争议处理适用中华人民共和国法律不包括港台地区法律</div>
</div>
<!-- 其他事项 -->
<div style="margin-bottom: 30px; padding: 0 50px">
<div style="margin-bottom: 30px; text-align: center; font-weight: bold">其他事项</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第三十四条</span>
本保险合同保险责任开始后未经被保险人同意投保人不得解除本保险
合同在保险期间内经被保险人同意解除保险合同的保险人在解除保险合同时的有效保
险金额内按日比例退还未满期部分的保险费
</div>
<div style="margin-bottom: 10px">
<span style="margin-right: 10px; font-weight: bold">第三十五条</span>
保险责任开始前投保人要求解除保险合同的应当向保险人支付相当于 保险费 5%的手续费保险人应当退还保险费
</div>
</div>
<div style="margin-bottom: 30px; text-align: center; font-size: 20px; font-weight: bold">
<div style="margin-bottom: 10px">紫金财产保险股份有限公司</div>
<div style="margin-bottom: 10px">附加先行赔偿及追偿保险条款</div>
<div style="margin-bottom: 10px">附加先行赔偿及追偿保险条款</div>
<div style="margin-bottom: 10px">注册编号C00013731422020121500662</div>
<div style="margin-bottom: 10px">备案号 (紫金保险)(-保证保险)2021 () 005 </div>
</div>
<!-- 总则 -->
<div style="margin-bottom: 30px; padding: 0 50px">
<div style="margin-bottom: 30px; text-align: center; font-weight: bold">总则</div>
<div>
<span style="margin-right: 10px; font-weight: bold">第一条</span>
在投保保证保险以下简称主险 的基础上投保人可以投保本附加险
险合同效力终止本附加险效力亦同时终止主险合同无效本附加险合同亦无效本附加
险合同未约定事项以主险合同为准主险合同与本附加险合同相抵触之处以本附加险合
同为准凡涉及本附加险合同的约定均应采用书面形式
</div>
</div>
<!-- 赔偿处理 -->
<div style="margin-bottom: 30px; padding: 0 50px">
<div style="margin-bottom: 30px; text-align: center; font-weight: bold">赔偿处理</div>
<div>
<span style="margin-right: 10px; font-weight: bold">第二条</span>
在保险期间内发生主险合同约定的保险责任在被保险人向保险人以书面形
式提出赔偿要求后保险人在保险金额内向被保险人先行赔偿不以被保险人向投保人或其
担保人启动诉讼或仲裁索赔程序为前提
</div>
</div>
<!-- 追偿 -->
<div style="margin-bottom: 30px; padding: 0 50px">
<div style="margin-bottom: 30px; text-align: center; font-weight: bold">追偿</div>
<div>
<span style="margin-right: 10px; font-weight: bold">第三条</span>
自保险人向被保险人赔偿保险金之日起保险人在赔偿金额范围内代位行使被
保险人对投保人或其担保人如有请求追偿的权利被保险人应当向保险人提供必要的文
件和所知道的有关情况积极协助保险人向投保人或其担保人如有进行追偿被保险人
已经从投保人或其担保人如有处取得赔偿的保险人赔偿保险金时
<span style="font-weight: bold"> 应相应扣减被保险 人已从投保人或其担保人如有处取得的赔偿金额</span>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import type { Order } from '@/api';
interface PropsType {
order: Order;
}
const props = defineProps<PropsType>();
</script>

@ -0,0 +1,5 @@
export { default as PdfBox } from './PdfBox/index.vue';
export { default as ModifyDialog } from './ModifyDialog/index.vue';
export { default as ModifyInvoiceDialog } from './ModifyInvoiceDialog/index.vue';
export { default as CustomerNotificationDialog } from './CustomerNotificationDialog/index.vue';
export { default as CustomerNotificationDialog2 } from './CustomerNotificationDialog2/index.vue';

@ -0,0 +1,553 @@
<template>
<div>
<div class="page-header">确认投保</div>
<div class="page-body">
<!-- 温馨提示 -->
<div class="page-notice">
<div>温馨提示</div>
<div>
<div>尊敬的投保企业投保时还请注意</div>
<div class="d-flex">
1检查
<span class="color-danger">企业信息</span>
<span class="color-danger">开票信息</span>是否有误
</div>
<div class="d-flex">
2第一次申请保函的<span class="color-danger">企业</span>如发现金额不正确请
<span class="color-danger">取消订单</span>
<span class="color-danger">重新下单</span>
即可感谢您的信任
</div>
</div>
</div>
<!-- 投保人信息 -->
<div class="page-card">
<div>
<div class="card-title">
投保人信息
<span class="m-l-12 ft-14 color-danger">
投保前请检查企业信息是否有误
<span style="color: rgb(36, 127, 255)" class="cursor-pointer" @click="handleModify"></span>
</span>
</div>
<div class="card-content">
<div>
<div class="d-flex">
<div class="card-label">企业名称</div>
<span>{{ order.Applicant.ApplicantName }}</span>
</div>
<div class="d-flex">
<div class="card-label">联系人姓名</div>
<span>{{ order.Applicant.ContactName }}</span>
</div>
<div class="d-flex">
<div class="card-label">开户行(基本户)</div>
<span>{{ order.User.BankName }}</span>
</div>
<div class="d-flex">
<div class="card-label">接收发票的邮箱</div>
<span>{{ order.Applicant.InvoiceAcceptEmail }}</span>
</div>
<div class="d-flex">
<div class="card-label">营业执照</div>
<div class="d-flex flex-gap-8">
<el-popover
v-for="src of JSON.parse(order.Applicant.LicenseFiles)"
hideAfter="0"
placement="right"
transition=""
popperStyle="width: auto; min-width: auto; max-width: 1000px; pointer-events: none;"
>
<el-image :src="src" />
<template #reference>
<el-image :src="src" style="width: 100px" />
</template>
</el-popover>
</div>
</div>
</div>
<div>
<div class="d-flex">
<div class="card-label">统一社会信用代码</div>
<span>{{ order.Applicant.CreditCode }}</span>
</div>
<div class="d-flex">
<div class="card-label">联系人手机号</div>
<span>{{ order.Applicant.ContactMobile }}</span>
</div>
<div class="d-flex">
<div class="card-label">银行账号</div>
<span>{{ order.User.BankCardNum }}</span>
</div>
<div class="d-flex">
<div class="card-label">发票类型</div>
<span>{{ order.Applicant.InvoiceType }}</span>
</div>
</div>
</div>
</div>
</div>
<div class="page-card">
<div>
<div class="card-title">项目信息</div>
<div class="card-content">
<div>
<div class="d-flex">
<div class="card-label">招标项目编号</div>
<span>{{ order.Project.TpID }}</span>
</div>
<div class="d-flex">
<div class="card-label">招标项目名称</div>
<span>{{ order.Project.Name }}</span>
</div>
<div class="d-flex">
<div class="card-label">招标企业</div>
<span>{{ order.Assured.AssuredName }}</span>
</div>
<div class="d-flex">
<div class="card-label">保证金</div>
<span>{{ order.Project.Amount }}</span>
</div>
<!-- <div class="d-flex">
<div class="card-label">招标项目类型</div>
<span>{{ order.Project.TenderProjectType }}</span>
</div>
<div class="d-flex">
<div class="card-label">招标公告地址</div>
<a :href="order.Project.TenderNoticeUrl" target="_blank">点击查看</a>
</div>
<div class="d-flex">
<div class="card-label">招标文件MD5值</div>
<span>{{ order.Project.TenderFileUrlMd5 }}</span>
</div>
<div class="d-flex">
<div class="card-label">招标文件下载地址</div>
<a :href="order.Project.TenderFileUrl" target="_blank">点击下载</a>
</div>
<div class="d-flex">
<div class="card-label">计划工期</div>
<span>{{ order.Project.PlanDate }}</span>
</div> -->
</div>
<div>
<div class="d-flex">
<div class="card-label">标段编号</div>
<span>{{ order.Project.BdID }}</span>
</div>
<div class="d-flex">
<div class="card-label">标段名称</div>
<span>{{ order.Project.BdName }}</span>
</div>
<div class="d-flex">
<div class="card-label">代理机构</div>
<span>{{ order.Assured.Agency }}</span>
</div>
<div class="d-flex">
<div class="card-label">开标时间</div>
<span>{{ order.Project.StartDate }}</span>
</div>
<!-- <div class="d-flex">
<div class="card-label">项目发布时间</div>
<span>{{ order.Project.CreateTime }}</span>
</div>
<div class="d-flex">
<div class="card-label">项目预计造价</div>
<span>{{ order.Project.BuildPrice }}</span>
</div>
<div class="d-flex">
<div class="card-label">项目建设地点</div>
<span>{{ order.Project.BuildPlace }}</span>
</div>
<div class="d-flex">
<div class="card-label">项目审批文号</div>
<span>{{ order.Project.ProjectApprovalNo }}</span>
</div>
<div class="d-flex">
<div class="card-label">投标有效期</div>
<span>{{ order.Project.ValidPeriod }}</span>
</div> -->
</div>
</div>
</div>
</div>
<div class="page-card d-flex">
<div style="width: 50%">
<div class="card-title">保险信息</div>
<div class="card-content">
<div class="w-full">
<div class="d-flex">
<div class="card-label">联系人</div>
<span>张小姐</span>
</div>
<div class="d-flex">
<div class="card-label">联系方式</div>
<span>13705008897</span>
</div>
<div class="d-flex">
<div class="card-label">保函起保日</div>
<span>{{ order.Project.StartDate }}</span>
</div>
<div class="d-flex">
<div class="card-label">保函天数</div>
<span>180</span>
</div>
<div class="d-flex">
<div class="card-label">保函品种</div>
<span>投标保证保险</span>
</div>
<div class="d-flex">
<div class="card-label">出函机构</div>
<span>紫金财产保险股份有限公司福建分公司</span>
</div>
</div>
</div>
</div>
<div style="width: 50%">
<div class="card-title">
开票信息
<span style="color: rgb(36, 127, 255)" class="m-l-12 ft-14 cursor-pointer" @click="handleModifyInvoice">
修改
</span>
</div>
<div class="card-content">
<div class="w-full">
<div class="d-flex">
<div class="card-label">发票抬头</div>
<span>{{ order.Invoice?.Header }}</span>
</div>
<div class="d-flex">
<div class="card-label">税号</div>
<span>{{ order.Invoice?.TaxNumber }}</span>
</div>
<div class="d-flex">
<div class="card-label">开户银行</div>
<span>{{}}</span>
</div>
<div class="d-flex">
<div class="card-label">银行账号</div>
<span>{{}}</span>
</div>
<div class="d-flex">
<div class="card-label">企业地址</div>
<span>{{}}</span>
</div>
<div class="d-flex">
<div class="card-label">企业电话</div>
<span>{{}}</span>
</div>
</div>
</div>
</div>
</div>
<div class="page-footer">
<div>
<el-checkbox v-model="isAgree" size="large" style="transform: scale(1.25) translateX(-20px)">
<span style="#565960" class="d-flex align-items-center">
确认并同意
<span style="color: rgb(60, 124, 255)" @click.stop="openCustomerNotificationDialog">客户告知书</span>
<span style="color: rgb(60, 124, 255)" @click.stop="openCustomerNotificationDialog2">投保须知</span>
</span>
</el-checkbox>
</div>
<div class="cursor-pointer" @click="handleNext"></div>
</div>
</div>
<IPC />
<ModifyDialog ref="modifyDialogRef" :order="order" :token="token" @confirm="handleModifyCallback" />
<ModifyInvoiceDialog
ref="modifyInvoiceDialogRef"
:token="token"
:invoice="order.Invoice"
@confirm="handleModifyInvoiceCallback"
/>
<CustomerNotificationDialog ref="customerNotificationDialogRef" @confirm="isAgree = true" />
<CustomerNotificationDialog2 ref="customerNotificationDialog2Ref" @confirm="isAgree = true" />
<div id="asdfasdfafdasf" style="display: none">
<PdfBox :order="order" />
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useLoading } from '@/hooks';
import { getOrder, generateSignFile } from '@/api';
import IPC from '@/components/IPC.vue';
import {
PdfBox,
ModifyDialog,
ModifyInvoiceDialog,
CustomerNotificationDialog,
CustomerNotificationDialog2,
} from './components';
import type { Order, Invoice } from '@/api';
const route = useRoute();
const router = useRouter();
const modifyDialogRef = ref<InstanceType<typeof ModifyDialog>>();
const modifyInvoiceDialogRef = ref<InstanceType<typeof ModifyInvoiceDialog>>();
const customerNotificationDialogRef = ref<InstanceType<typeof CustomerNotificationDialog>>();
const customerNotificationDialog2Ref = ref<InstanceType<typeof CustomerNotificationDialog2>>();
const { openLoading, closeLoading } = useLoading();
const token = ref('');
const order = ref({ User: {}, Project: {}, Assured: {}, Applicant: {} } as Order);
const isAgree = ref(false);
initPage();
async function initPage() {
const queryToken = String(route.query.token);
token.value = queryToken;
const { data } = await getOrder({ token: queryToken });
order.value = data.order;
if (!order.value.Applicant.InvoiceType) {
order.value.Applicant.InvoiceType = '普票';
}
}
function openCustomerNotificationDialog() {
customerNotificationDialogRef.value?.open();
}
function openCustomerNotificationDialog2() {
customerNotificationDialog2Ref.value?.open();
}
async function handleNext() {
try {
if (!isAgree.value) return openCustomerNotificationDialog();
openLoading();
await generateSignFile({ token: token.value });
router.push({ name: 'Sign', query: { token: token.value } });
} finally {
closeLoading();
}
}
function handleModify() {
modifyDialogRef.value?.open();
}
function handleModifyCallback(editOrder: Order) {
order.value = editOrder;
}
function handleModifyInvoice() {
modifyInvoiceDialogRef.value?.open();
}
function handleModifyInvoiceCallback(editInvoice: Invoice) {
order.value.Invoice = editInvoice;
}
</script>
<style lang="scss" scoped>
.page-header {
position: sticky;
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
top: 0;
height: 60px;
font-size: 20px;
background-color: #fff;
> img {
position: absolute;
left: 20px;
width: 70px;
}
}
.page-body {
margin: 0 auto;
padding: 16px 0;
max-width: 80vw;
}
.page-notice {
display: flex;
border-radius: 6px;
background-color: #fff;
box-shadow: 0 0 10px #ddd;
overflow: hidden;
> div:first-child {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 150px;
color: #fff;
font-size: 20px;
font-weight: bold;
background-color: rgb(36, 127, 255);
&::after {
content: '';
position: absolute;
top: 50%;
left: 26px;
width: 4px;
height: 14px;
transform: translateY(-50%);
background-color: #fff;
}
}
> div:last-child {
flex-grow: 1;
padding: 8px 16px;
color: rgb(60, 124, 255);
line-height: 24px;
}
}
.page-card {
flex: 1;
margin-top: 16px;
padding: 16px;
border-radius: 6px;
background-color: #fff;
box-shadow: 0 0 10px #ddd;
.card-title {
position: relative;
display: flex;
align-items: center;
margin-bottom: 8px;
padding-left: 10px;
font-size: 20px;
&::after {
content: '';
position: absolute;
top: 50%;
left: 0;
width: 4px;
height: 16px;
transform: translateY(-50%);
background-color: rgb(36, 127, 255);
}
}
.card-content {
display: flex;
> div {
display: flex;
flex-direction: column;
gap: 4px;
width: 50%;
.card-label {
flex-shrink: 0;
width: 15em;
color: #898b8f;
text-align: right;
font-size: 16px;
& + .card-label {
margin-top: 4px;
}
}
}
}
}
.page-footer {
display: flex;
margin-top: 16px;
height: 80px;
border-radius: 6px;
background-color: #fff;
overflow: hidden;
> div:first-child {
display: flex;
align-items: center;
justify-content: flex-end;
flex: 1;
padding: 16px;
}
> div:last-child {
display: flex;
align-items: center;
justify-content: center;
width: 200px;
color: #fff;
font-size: 20px;
font-weight: bold;
background-color: rgb(36, 127, 255);
}
}
.card-double-box {
display: flex;
gap: 16px;
> div:last-child {
.card-label {
width: calc(15em - 26px);
}
}
}
</style>

@ -0,0 +1,20 @@
{
"compilerOptions": {
"baseUrl": "./",
"target": "esnext",
"module": "esnext",
"strict": true,
"moduleResolution": "node",
"forceConsistentCasingInFileNames": true,
"types": ["node", "element-plus/global", "vite/client"],
"jsx": "preserve",
"allowJs": true,
"paths": {
"@/*": ["./src/*"]
},
"allowSyntheticDefaultImports": true,
"skipLibCheck": true
},
"include": ["src/**/*.vue", "src/**/*.ts", "src/**/*.tsx", "src/**/*.d.ts"],
"exclude": ["node_modules"]
}

@ -0,0 +1,29 @@
// good
import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';
import { createHtmlPlugin } from 'vite-plugin-html';
import { REQUEST_BASE_URL } from './src/constant/request';
import type { UserConfigExport } from 'vite';
export default () => {
const target = 'http://fjtb.bj-eib.com/api';
const baseConfig: UserConfigExport = {
server: {
port: 80,
open: true,
proxy: {
[REQUEST_BASE_URL]: {
target,
changeOrigin: true,
rewrite: path => path.replace(REQUEST_BASE_URL, ''),
},
},
},
resolve: { alias: { '@': resolve(process.cwd(), './src') } },
plugins: [vue(), createHtmlPlugin({ entry: '/src/main.ts', minify: true })],
};
return baseConfig;
};
Loading…
Cancel
Save