Compare commits
13 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
18956dfa58 | |
|
|
1799d404bf | |
|
|
4ac19f78fd | |
|
|
49634c9285 | |
|
|
d607c2abcf | |
|
|
e35f1999fb | |
|
|
0f1f099144 | |
|
|
eb126006a1 | |
|
|
2be569f8eb | |
|
|
57811df6e2 | |
|
|
f46a01daf2 | |
|
|
45862052c7 | |
|
|
4e231ec401 |
|
|
@ -54,6 +54,30 @@
|
|||
<div class="content unicode" style="display: block;">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">标记-copy</div>
|
||||
<div class="code-name">&#xe78c;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">标记</div>
|
||||
<div class="code-name">&#xe604;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">取消标记</div>
|
||||
<div class="code-name">&#xe710;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">双击</div>
|
||||
<div class="code-name">&#xe6f0;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">export</div>
|
||||
|
|
@ -204,9 +228,9 @@
|
|||
<pre><code class="language-css"
|
||||
>@font-face {
|
||||
font-family: 'iconfont';
|
||||
src: url('iconfont.woff2?t=1741245710478') format('woff2'),
|
||||
url('iconfont.woff?t=1741245710478') format('woff'),
|
||||
url('iconfont.ttf?t=1741245710478') format('truetype');
|
||||
src: url('iconfont.woff2?t=1750298885691') format('woff2'),
|
||||
url('iconfont.woff?t=1750298885691') format('woff'),
|
||||
url('iconfont.ttf?t=1750298885691') format('truetype');
|
||||
}
|
||||
</code></pre>
|
||||
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
||||
|
|
@ -232,6 +256,42 @@
|
|||
<div class="content font-class">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-biaoji-copy"></span>
|
||||
<div class="name">
|
||||
标记-copy
|
||||
</div>
|
||||
<div class="code-name">.icon-biaoji-copy
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-biaoji"></span>
|
||||
<div class="name">
|
||||
标记
|
||||
</div>
|
||||
<div class="code-name">.icon-biaoji
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-quxiaobiaoji"></span>
|
||||
<div class="name">
|
||||
取消标记
|
||||
</div>
|
||||
<div class="code-name">.icon-quxiaobiaoji
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-shuangji"></span>
|
||||
<div class="name">
|
||||
双击
|
||||
</div>
|
||||
<div class="code-name">.icon-shuangji
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-export"></span>
|
||||
<div class="name">
|
||||
|
|
@ -457,6 +517,38 @@
|
|||
<div class="content symbol">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-biaoji-copy"></use>
|
||||
</svg>
|
||||
<div class="name">标记-copy</div>
|
||||
<div class="code-name">#icon-biaoji-copy</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-biaoji"></use>
|
||||
</svg>
|
||||
<div class="name">标记</div>
|
||||
<div class="code-name">#icon-biaoji</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-quxiaobiaoji"></use>
|
||||
</svg>
|
||||
<div class="name">取消标记</div>
|
||||
<div class="code-name">#icon-quxiaobiaoji</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-shuangji"></use>
|
||||
</svg>
|
||||
<div class="name">双击</div>
|
||||
<div class="code-name">#icon-shuangji</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-export"></use>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 4257468 */
|
||||
src: url('iconfont.woff2?t=1741245710478') format('woff2'),
|
||||
url('iconfont.woff?t=1741245710478') format('woff'),
|
||||
url('iconfont.ttf?t=1741245710478') format('truetype');
|
||||
src: url('iconfont.woff2?t=1750298885691') format('woff2'),
|
||||
url('iconfont.woff?t=1750298885691') format('woff'),
|
||||
url('iconfont.ttf?t=1750298885691') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
|
|
@ -13,6 +13,22 @@
|
|||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-biaoji-copy:before {
|
||||
content: "\e78c";
|
||||
}
|
||||
|
||||
.icon-biaoji:before {
|
||||
content: "\e604";
|
||||
}
|
||||
|
||||
.icon-quxiaobiaoji:before {
|
||||
content: "\e710";
|
||||
}
|
||||
|
||||
.icon-shuangji:before {
|
||||
content: "\e6f0";
|
||||
}
|
||||
|
||||
.icon-export:before {
|
||||
content: "\e61e";
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -5,6 +5,34 @@
|
|||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "44653522",
|
||||
"name": "标记-copy",
|
||||
"font_class": "biaoji-copy",
|
||||
"unicode": "e78c",
|
||||
"unicode_decimal": 59276
|
||||
},
|
||||
{
|
||||
"icon_id": "14559255",
|
||||
"name": "标记",
|
||||
"font_class": "biaoji",
|
||||
"unicode": "e604",
|
||||
"unicode_decimal": 58884
|
||||
},
|
||||
{
|
||||
"icon_id": "33872224",
|
||||
"name": "取消标记",
|
||||
"font_class": "quxiaobiaoji",
|
||||
"unicode": "e710",
|
||||
"unicode_decimal": 59152
|
||||
},
|
||||
{
|
||||
"icon_id": "39084114",
|
||||
"name": "双击",
|
||||
"font_class": "shuangji",
|
||||
"unicode": "e6f0",
|
||||
"unicode_decimal": 59120
|
||||
},
|
||||
{
|
||||
"icon_id": "10124054",
|
||||
"name": "export",
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -23,10 +23,7 @@ class CalculateService extends BasicService {
|
|||
delete queryParams[key];
|
||||
}
|
||||
}
|
||||
return this.post(
|
||||
url,
|
||||
queryParams
|
||||
);
|
||||
return this.post(url, queryParams);
|
||||
};
|
||||
//获取系统配置项
|
||||
getSysconfcode = async ({ code }: any) => {
|
||||
|
|
@ -73,7 +70,7 @@ class CalculateService extends BasicService {
|
|||
return this.post(`/api/bs/hrmsalary/salaryacct/acctresult/sum`, queryParams);
|
||||
};
|
||||
//合计行
|
||||
getAcctResultsum = async (url: string, params: any) => (this.post(url, params));
|
||||
getAcctResultsum = async (url: string, params: any) => this.post(url, params);
|
||||
//社保合计行
|
||||
getSyMixSum = async (params: any) => {
|
||||
return this.post(`/api/bs/hrmsalary/siaccount/detail/list/syMixSum`, params);
|
||||
|
|
@ -86,8 +83,12 @@ class CalculateService extends BasicService {
|
|||
getAcctresultSum = async (params: any) => {
|
||||
return this.post(`/api/bs/hrmsalary/salaryacct/acctresult/sjjtReportSum`, params);
|
||||
};
|
||||
//工资单查询
|
||||
getMySalaryBill = async (salaryInfoId: string) => {
|
||||
return this.get(`/api/bs/hrmsalary/salaryBill/mySalaryBill?salaryInfoId=${salaryInfoId}`);
|
||||
};
|
||||
}
|
||||
|
||||
const calculateService = new CalculateService();
|
||||
|
||||
export default calculateService;
|
||||
export default calculateService;
|
||||
|
|
@ -23,6 +23,7 @@ module.exports = {
|
|||
"/unitTable.*": "blank",
|
||||
"/aliTable.*": "blank",
|
||||
"/custom-project.*": "blank",
|
||||
"/MPayroll.*": "blank",
|
||||
"/hiprintDesign.*": "hiPrint",
|
||||
"/manage.*": "manage",
|
||||
"/portal.*": "template",
|
||||
|
|
@ -36,4 +37,4 @@ module.exports = {
|
|||
"/500": "blank",
|
||||
"/": "template"
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
.pbmc_body {
|
||||
height: calc(100% - 50px);
|
||||
background: #f6f6f6;
|
||||
overflow: auto;
|
||||
font-size: 12px;
|
||||
|
||||
.weapp-salary-payroll-mobile-preview {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
|
||||
.bill-container {
|
||||
background: #f6f6f6;
|
||||
|
||||
.space {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.ant-btn {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.bill-info-header {
|
||||
padding-top: 16px;
|
||||
|
||||
.title {
|
||||
padding: 0 16px;
|
||||
font-size: 19px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.time {
|
||||
padding: 0 16px;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.img {
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.top {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.corporate-culture-text {
|
||||
text-align: left;
|
||||
color: #111;
|
||||
padding: 8px 16px;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.salary-detail-table-container {
|
||||
padding-top: 8px;
|
||||
|
||||
.salary-group {
|
||||
border-top: 1px solid #f2f2f2;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.group-title {
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 45px;
|
||||
padding: 0 16px;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
font-weight: bolder;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.group-list {
|
||||
.list-item {
|
||||
display: flex;
|
||||
min-height: 45px;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
|
||||
.item-name {
|
||||
padding: 8px 16px;
|
||||
width: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #fbfbfb;
|
||||
border-right: 1px solid #f2f2f2;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.item-count {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pbmc_footer {
|
||||
position: relative;
|
||||
height: 50px;
|
||||
|
||||
.pbmcf_indicator {
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
left: 50%;
|
||||
-webkit-transform: translateX(-50%);
|
||||
transform: translateX(-50%);
|
||||
width: 110px;
|
||||
height: 4px;
|
||||
background-color: #ebebeb;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import styles from "./index.less";
|
||||
import { Util } from "@/utils";
|
||||
import cs from "classnames";
|
||||
import API from "@/api";
|
||||
|
||||
interface OwnProps {}
|
||||
|
||||
type Props = OwnProps;
|
||||
|
||||
const MPayroll: React.FC<Props> = (props) => {
|
||||
const [mySalaryBillData, setMySalaryBillData] = useState<any>({});
|
||||
useEffect(() => {
|
||||
getMySalaryBill();
|
||||
return () => {};
|
||||
}, []);
|
||||
const getMySalaryBill = useCallback(() => {
|
||||
API.CalculateService.getMySalaryBill(Util.getUrlData("salaryInfoId")).then(({ data: res }) => {
|
||||
const { data, status } = res || {};
|
||||
if (status) setMySalaryBillData(data);
|
||||
});
|
||||
}, []);
|
||||
const dealTemplate = (itemTypeList: any, type: string) => {
|
||||
let cloneItemTypeList = _.cloneDeep(itemTypeList);
|
||||
let showData: any = [],
|
||||
onlyOneGrup = false;
|
||||
cloneItemTypeList.forEach((group: any) => {
|
||||
const { items, groupName, groupId } = group;
|
||||
if (items.length !== 0) {
|
||||
items.forEach((item: any) => {
|
||||
item.salaryItemValue = !_.isNil(item.salaryItemValue) ? item.salaryItemValue : "";
|
||||
});
|
||||
if (items.length % 2 && type === "pc") items.push({});
|
||||
showData.push({ groupId, groupName, items });
|
||||
}
|
||||
});
|
||||
if (cloneItemTypeList.length === 1) {
|
||||
onlyOneGrup = true;
|
||||
cloneItemTypeList[0].name = "";
|
||||
}
|
||||
return { onlyOneGrup, showData };
|
||||
};
|
||||
const salaryTemplate = useMemo(() => {
|
||||
return !_.isEmpty(mySalaryBillData) ? mySalaryBillData?.salaryTemplate : {};
|
||||
}, [mySalaryBillData]);
|
||||
const itemTypeList = useMemo(() => {
|
||||
return !_.isEmpty(mySalaryBillData) ? [mySalaryBillData?.employeeInformation, ...mySalaryBillData?.salaryGroups] : [];
|
||||
}, [mySalaryBillData]);
|
||||
const payrollData: any = useMemo(() => {
|
||||
return !_.isEmpty(itemTypeList)
|
||||
? dealTemplate(
|
||||
_.filter(itemTypeList, (o) => !!o),
|
||||
"mobile"
|
||||
)
|
||||
: {};
|
||||
}, [mySalaryBillData, itemTypeList]);
|
||||
console.log(payrollData);
|
||||
return (
|
||||
<>
|
||||
<div className={styles.pbmc_body}>
|
||||
<div className={styles["weapp-salary-payroll-mobile-preview"]}>
|
||||
<div className={styles["bill-container"]}>
|
||||
<div className={styles["bill-info-header"]}>
|
||||
<div className={styles["title"]}>{salaryTemplate?.theme || ""}</div>
|
||||
</div>
|
||||
{!payrollData?.onlyOneGrup && salaryTemplate?.textContentPosition == 1 && salaryTemplate.textContent && (
|
||||
<div className={cs(styles["corporate-culture-text"], styles["top"])} title={salaryTemplate.textContent} dangerouslySetInnerHTML={{ __html: salaryTemplate.textContent }} />
|
||||
)}
|
||||
<div className={styles["salary-detail-table-container"]}>
|
||||
{!_.isEmpty(payrollData?.showData) &&
|
||||
payrollData?.showData.map((groupItem: any, index: number) => {
|
||||
if (!groupItem) return null;
|
||||
const { groupId, groupName, items = [] } = groupItem;
|
||||
return (
|
||||
<div className={styles["salary-group"]} key={groupId || index}>
|
||||
{groupName ? <div className={styles["group-title"]}>{groupName}</div> : null}
|
||||
<div className={styles["group-list"]}>
|
||||
{payrollData?.onlyOneGrup && salaryTemplate?.textContentPosition == "1" && salaryTemplate.textContent && (
|
||||
<div className={cs(styles["list-item"], styles["top"])}>
|
||||
<div>发放说明</div>
|
||||
<div>{salaryTemplate.textContent}</div>
|
||||
</div>
|
||||
)}
|
||||
{items.map((templatItem: any, index: number) => {
|
||||
const { salaryItemValue, name, salaryItemShowName } = templatItem || {};
|
||||
return (
|
||||
<div className={styles["list-item"]} key={index}>
|
||||
<div className={styles["item-name"]} title={salaryItemShowName || name}>
|
||||
<span>{salaryItemShowName || name || ""}</span>
|
||||
</div>
|
||||
<div className={styles["item-count"]}>{salaryItemValue}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{payrollData?.onlyOneGrup && salaryTemplate?.textContentPosition == "2" && salaryTemplate.textContent && (
|
||||
<div className={styles["list-item"]}>
|
||||
<div>发放说明</div>
|
||||
<div>{salaryTemplate.textContent}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{!payrollData?.onlyOneGrup && salaryTemplate?.textContentPosition == 2 && salaryTemplate.textContent && (
|
||||
<div className={cs(styles["corporate-culture-text"], styles["footer"])} title={salaryTemplate.textContent} dangerouslySetInnerHTML={{ __html: salaryTemplate.textContent }} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.pbmc_footer}>
|
||||
<div className={styles.pbmcf_indicator}></div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MPayroll;
|
||||
|
|
@ -65,10 +65,10 @@ const OCTable: FC = (props) => {
|
|||
<span>{excelResultValue}</span>
|
||||
</div>
|
||||
{
|
||||
showDifference &&
|
||||
showDifference && !!parseInt(calculateDifference(acctResultValue, excelResultValue || 0)) &&
|
||||
<div className={cs(styles["danger"], styles["comparison-single-row"])}>
|
||||
<span>{lanObj["差值"]}:</span>
|
||||
<span>{calculateDifference(acctResultValue, excelResultValue)}</span>
|
||||
<span>{calculateDifference(acctResultValue, excelResultValue || 0)}</span>
|
||||
</div>
|
||||
}
|
||||
</div>;
|
||||
|
|
@ -104,7 +104,7 @@ const OCTable: FC = (props) => {
|
|||
return <Table
|
||||
rowKey="id" className={styles.tableWrapper}
|
||||
columns={columns} dataSource={dataSource} bordered size="small"
|
||||
scroll={{ x: 1200, y: `calc(100vh - 137px)` }}
|
||||
scroll={{ x: 1200, y: `calc(100vh - 165px)` }}
|
||||
pagination={{
|
||||
...paginationFun(pageInfo, sizeChange, onChange, i18n),
|
||||
size: "default"
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ const index: FunctionComponent<Props> = (props) => {
|
|||
return (
|
||||
<Dropdown menu={{ items: !item.calcDetail || item.rightClickType ? items : [] }} trigger={["contextMenu"]} overlayClassName={styles.contextMenu} destroyPopupOnHide>
|
||||
<span className={styles.contentSpan}>
|
||||
<span title={text} className={styles.contentTitle} style={{ color: `${record?.[item.dataIndex + "_color"]}` }}>
|
||||
<span title={text} className={styles.contentTitle} style={record?.[item.dataIndex + "_color"] ? { color: `${record?.[item.dataIndex + "_color"]}` } : {}}>
|
||||
{text}
|
||||
</span>
|
||||
{record.lockItems && record.lockItems.includes(item.dataIndex) ? <LockOutlined title={item.i18n["锁定的项目值"]} /> : null}
|
||||
|
|
@ -240,8 +240,8 @@ const index: FunctionComponent<Props> = (props) => {
|
|||
};
|
||||
const rowSelection = {
|
||||
columnWidth: 50,
|
||||
columnTitle: isDetailTable ? "序号" : "",
|
||||
renderCell: (value: boolean, record: any, index: number, originNode: React.ReactNode) => (isDetailTable ? <span>{index + 1}</span> : originNode),
|
||||
columnTitle: isDetailTable && _.isNil(showSee) ? "序号" : "",
|
||||
renderCell: (value: boolean, record: any, index: number, originNode: React.ReactNode) => (isDetailTable && _.isNil(showSee) ? <span>{index + 1}</span> : originNode),
|
||||
selectedRowKeys,
|
||||
preserveSelectedRowKeys: true,
|
||||
onChange: (rowKeys: React.Key[]) => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
.block {
|
||||
height: 300px;
|
||||
border: 3px solid #ccc;
|
||||
margin-bottom: 20px;
|
||||
color: white;
|
||||
padding: 24px;
|
||||
line-height: 32px;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.lazyloadImg{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
&>li{
|
||||
width: 400px;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
img{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import React, { useEffect, useRef } from "react";
|
||||
import styles from "../../index.less";
|
||||
|
||||
interface OwnProps {}
|
||||
|
||||
type Props = OwnProps;
|
||||
|
||||
const Index: React.FC<Props> = (props) => {
|
||||
const itemRef = useRef<HTMLElement[]>([]);
|
||||
const ob = new IntersectionObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting) {
|
||||
const img: any = entry.target;
|
||||
img.src = img.dataset.src;
|
||||
ob.unobserve(entry.target);
|
||||
}
|
||||
}
|
||||
});
|
||||
useEffect(() => {
|
||||
if (itemRef.current) {
|
||||
_.forEach(itemRef.current, (item) => {
|
||||
ob.observe(item);
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (itemRef.current) {
|
||||
_.forEach(itemRef.current, (item) => {
|
||||
ob.unobserve(item);
|
||||
});
|
||||
}
|
||||
};
|
||||
}, [itemRef.current]);
|
||||
return (
|
||||
<ul className={styles.lazyloadImg}>
|
||||
{_.map(
|
||||
Array.from({ length: 200 }, () => Math.floor(Math.random() * 100)),
|
||||
(item, index) => (
|
||||
<li key={index}>
|
||||
<img data-src={`https://picsum.photos/300/300?random=${index}`} alt="" src={require("../default.jpeg")} ref={(el) => (itemRef.current[index] = el as HTMLElement)} />
|
||||
</li>
|
||||
)
|
||||
)}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
export default Index;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.0 KiB |
|
|
@ -0,0 +1,43 @@
|
|||
import React from "react";
|
||||
import SlideInItem from "./slideInItem";
|
||||
|
||||
interface OwnProps {}
|
||||
|
||||
type Props = OwnProps;
|
||||
|
||||
const list = [
|
||||
{ id: 1, bg: "red" },
|
||||
{ id: 2, bg: "blue" },
|
||||
{ id: 3, bg: "green" },
|
||||
{ id: 4, bg: "yellowgreen" },
|
||||
{ id: 5, bg: "orange" },
|
||||
{ id: 6, bg: "pink" },
|
||||
{ id: 7, bg: "antiquewhite" },
|
||||
{ id: 8, bg: "darkseagreen" },
|
||||
{ id: 9, bg: "purple" },
|
||||
{ id: 10, bg: "red" },
|
||||
{ id: 11, bg: "black" }
|
||||
];
|
||||
const Index: React.FC<Props> = (props) => {
|
||||
const map = new WeakMap();
|
||||
const ob = new IntersectionObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting) {
|
||||
const animation = map.get(entry.target);
|
||||
if (animation) {
|
||||
animation.play();
|
||||
ob.unobserve(entry.target);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return (
|
||||
<>
|
||||
{list.map((item, index) => {
|
||||
return <SlideInItem key={index} item={item} ob={ob} map={map}></SlideInItem>;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Index;
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
import React, { useEffect, useRef } from "react";
|
||||
import styles from "../index.less";
|
||||
|
||||
interface OwnProps {
|
||||
item: any;
|
||||
ob: any;
|
||||
map: any;
|
||||
}
|
||||
|
||||
type Props = OwnProps;
|
||||
const SLIDE_FADE_DISTANCE = 50;
|
||||
const SLIDE_FADE_DURATION = 1000;
|
||||
|
||||
const isBelowViewport = (el: HTMLDivElement) => {
|
||||
const rect = el.getBoundingClientRect();
|
||||
return rect.top - SLIDE_FADE_DISTANCE > window.innerHeight;
|
||||
};
|
||||
const slideInItem: React.FC<Props> = (props) => {
|
||||
const { item, ob, map } = props;
|
||||
const itemRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (itemRef.current && ob) {
|
||||
if (!isBelowViewport(itemRef.current)) {
|
||||
return;
|
||||
}
|
||||
const animation = itemRef.current.animate(
|
||||
[
|
||||
{
|
||||
transform: `translateY(${SLIDE_FADE_DISTANCE}px)`,
|
||||
opacity: 0.1
|
||||
},
|
||||
{
|
||||
transform: `translateY(0)`,
|
||||
opacity: 1
|
||||
}
|
||||
],
|
||||
{
|
||||
duration: SLIDE_FADE_DURATION,
|
||||
easing: "ease-in-out",
|
||||
fill: "forwards" // 当动画完成后,保留最后一个关键帧的样式
|
||||
}
|
||||
);
|
||||
animation.pause();
|
||||
map.set(itemRef.current, animation);
|
||||
ob.observe(itemRef.current);
|
||||
}
|
||||
|
||||
return () => {
|
||||
ob.unobserve(itemRef.current);
|
||||
};
|
||||
}, [itemRef.current]);
|
||||
|
||||
return (
|
||||
<div className={styles.block} ref={itemRef} style={{ backgroundColor: item.bg }}>
|
||||
<h3>The most popular component library</h3>
|
||||
|
||||
<h5>for Tailwind CSS</h5>
|
||||
<p>daisyUI adds component class names to Tailwind CSS so you can make beautiful websites faster than ever.</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default slideInItem;
|
||||
|
|
@ -46,7 +46,7 @@ export function renderCols(initialState: any[], type: string, i18n?: AnyObject,
|
|||
};
|
||||
break;
|
||||
case "paymentOrganization":
|
||||
col = { ...col, width: 200 };
|
||||
col = { ...col, width: g.width || 200 };
|
||||
break;
|
||||
case "socialNum":
|
||||
case "otherNum":
|
||||
|
|
@ -434,6 +434,72 @@ export function renderCols(initialState: any[], type: string, i18n?: AnyObject,
|
|||
return col;
|
||||
})
|
||||
];
|
||||
} else if (type === "attendanceView") {
|
||||
return [
|
||||
..._.map(initialState, (g) => {
|
||||
let col = { ...g, ellipsis: true };
|
||||
switch (g.dataIndex) {
|
||||
case "operate":
|
||||
col = {
|
||||
...col,
|
||||
ellipsis: false,
|
||||
width: 120,
|
||||
render: (__: string, record: any) => {
|
||||
return (
|
||||
<Space>
|
||||
{_.map(col?.operateType, (o) => (
|
||||
<Button key={o.key} type="link" onClick={() => postMessageToParent(o.key, record)}>
|
||||
{o.label}
|
||||
</Button>
|
||||
))}
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
};
|
||||
break;
|
||||
default:
|
||||
col = { ...col };
|
||||
break;
|
||||
}
|
||||
return col;
|
||||
})
|
||||
];
|
||||
} else if (type === "declare") {
|
||||
return [
|
||||
..._.map(initialState, (g) => {
|
||||
let col = { ...g, ellipsis: true };
|
||||
switch (g.dataIndex) {
|
||||
case "operate":
|
||||
col = {
|
||||
...col,
|
||||
ellipsis: false,
|
||||
width: 120,
|
||||
render: (__: string, record: any) => {
|
||||
return (
|
||||
<Space>
|
||||
{_.map(col?.operateType, (o) => (
|
||||
<Button key={o.key} type="link" onClick={() => postMessageToParent(o.key, record)}>
|
||||
{o.label}
|
||||
</Button>
|
||||
))}
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
};
|
||||
break;
|
||||
default:
|
||||
col = { ...col };
|
||||
break;
|
||||
}
|
||||
return col;
|
||||
})
|
||||
];
|
||||
} else if (type === "cusTitle") {
|
||||
return [
|
||||
..._.map(initialState, (g) => {
|
||||
return { ...g, title: <span dangerouslySetInnerHTML={{ __html: g.title }} /> };
|
||||
})
|
||||
];
|
||||
}
|
||||
return initialState;
|
||||
}, [initialState, type, i18n, extraParams]);
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ export const exceptStr = (str) => {
|
|||
};
|
||||
|
||||
export const paginationFun = (tableListPageObj, sizeChange, onChange, i18n = {}) => {
|
||||
const pageSizeOptions= tableListPageObj?.pageSizeOptions || ["10", "20", "50", "100"];
|
||||
return {
|
||||
current: tableListPageObj.pageNum || tableListPageObj.current,
|
||||
pageSize: tableListPageObj.size || tableListPageObj.pageSize,
|
||||
|
|
@ -78,7 +79,7 @@ export const paginationFun = (tableListPageObj, sizeChange, onChange, i18n = {})
|
|||
showTotal: total => `${i18n["共"] ? i18n["共"] : "共"} ${total} ${i18n["条"] ? i18n["条"] : "条"}`,
|
||||
showQuickJumper: true,
|
||||
showSizeChanger: true,
|
||||
pageSizeOptions: ["10", "20", "50", "100"],
|
||||
pageSizeOptions,
|
||||
onShowSizeChange: (page, size) => {
|
||||
const { total } = tableListPageObj;
|
||||
sizeChange({
|
||||
|
|
@ -122,4 +123,4 @@ export const toDecimal_n = (num, decimalPlaces) => {
|
|||
const multiplier = Math.pow(10, decimalPlaces);
|
||||
const roundedNum = Math.round(num * multiplier) / multiplier;
|
||||
return roundedNum.toFixed(decimalPlaces);
|
||||
};
|
||||
};
|
||||
Loading…
Reference in New Issue