chore: 初始开源发布
iotlcm-onelink-mock:OneLink 挡板服务(本地测试替身)。 - Go module 迁移至 git.5iot.com/iotlcm-public/iotlcm-onelink-mock - 修复同毫秒内多次生成卡导致 ICCID/IMSI 唯一约束冲突 - 补 Apache-2.0 LICENSE,README 重写并新增 docs/deploy.md - 移除内部部署资产(CI 触发器 / 镜像推送脚本 / 指定环境部署文档) - 测试凭据改为 demo_appid / demo_password,真实手机号与内网 IP 脱敏 - 统一 LF 行尾并加 .gitattributes
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func exportInboundCardsXLSX(cards []SIMCard) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
zw := zip.NewWriter(&buf)
|
||||
files := map[string]string{
|
||||
"[Content_Types].xml": contentTypesXML,
|
||||
"_rels/.rels": rootRelsXML,
|
||||
"xl/workbook.xml": workbookXML,
|
||||
"xl/_rels/workbook.xml.rels": workbookRelsXML,
|
||||
"xl/sharedStrings.xml": sharedStringsXML(),
|
||||
"xl/styles.xml": stylesXML,
|
||||
"xl/worksheets/sheet1.xml": sheetXML(cards),
|
||||
}
|
||||
for _, name := range []string{"[Content_Types].xml", "_rels/.rels", "xl/workbook.xml", "xl/_rels/workbook.xml.rels", "xl/sharedStrings.xml", "xl/styles.xml", "xl/worksheets/sheet1.xml"} {
|
||||
w, err := zw.Create(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := w.Write([]byte(files[name])); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := zw.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func sheetXML(cards []SIMCard) string {
|
||||
var b strings.Builder
|
||||
b.WriteString(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>`)
|
||||
b.WriteString(`<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
|
||||
b.WriteString(`<dimension ref="A1:R`)
|
||||
b.WriteString(strconv.Itoa(len(cards) + 1))
|
||||
b.WriteString(`"/><sheetViews><sheetView tabSelected="true" workbookViewId="0"/></sheetViews>`)
|
||||
b.WriteString(`<sheetFormatPr defaultRowHeight="15"/><cols><col min="1" max="18" width="9.140625" style="1"/></cols><sheetData>`)
|
||||
writeSharedStringRow(&b, 1, len(inboundExportHeaders))
|
||||
for i, card := range cards {
|
||||
row := inboundExportRow(card)
|
||||
values := make([]string, 0, len(inboundExportColumns))
|
||||
for _, column := range inboundExportColumns {
|
||||
values = append(values, row[column.Key])
|
||||
}
|
||||
writeSheetRow(&b, i+2, values)
|
||||
}
|
||||
b.WriteString(`</sheetData></worksheet>`)
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func writeSharedStringRow(b *strings.Builder, rowNum, count int) {
|
||||
b.WriteString(`<row r="`)
|
||||
b.WriteString(strconv.Itoa(rowNum))
|
||||
b.WriteString(`">`)
|
||||
for i := 0; i < count; i++ {
|
||||
ref := fmt.Sprintf("%s%d", columnName(i+1), rowNum)
|
||||
b.WriteString(`<c r="`)
|
||||
b.WriteString(ref)
|
||||
b.WriteString(`" s="1" t="s"><v>`)
|
||||
b.WriteString(strconv.Itoa(i))
|
||||
b.WriteString(`</v></c>`)
|
||||
}
|
||||
b.WriteString(`</row>`)
|
||||
}
|
||||
|
||||
func writeSheetRow(b *strings.Builder, rowNum int, values []string) {
|
||||
b.WriteString(`<row r="`)
|
||||
b.WriteString(strconv.Itoa(rowNum))
|
||||
b.WriteString(`">`)
|
||||
for i, value := range values {
|
||||
ref := fmt.Sprintf("%s%d", columnName(i+1), rowNum)
|
||||
b.WriteString(`<c r="`)
|
||||
b.WriteString(ref)
|
||||
b.WriteString(`" s="1" t="inlineStr"><is><t>`)
|
||||
b.WriteString(xmlEscape(value))
|
||||
b.WriteString(`</t></is></c>`)
|
||||
}
|
||||
b.WriteString(`</row>`)
|
||||
}
|
||||
|
||||
func sharedStringsXML() string {
|
||||
var b strings.Builder
|
||||
b.WriteString(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>`)
|
||||
b.WriteString(`<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="`)
|
||||
b.WriteString(strconv.Itoa(len(inboundExportHeaders)))
|
||||
b.WriteString(`" uniqueCount="`)
|
||||
b.WriteString(strconv.Itoa(len(inboundExportHeaders)))
|
||||
b.WriteString(`">`)
|
||||
for _, header := range inboundExportHeaders {
|
||||
b.WriteString(`<si><t>`)
|
||||
b.WriteString(xmlEscape(header))
|
||||
b.WriteString(`</t></si>`)
|
||||
}
|
||||
b.WriteString(`</sst>`)
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func columnName(index int) string {
|
||||
var out []byte
|
||||
for index > 0 {
|
||||
index--
|
||||
out = append([]byte{byte('A' + index%26)}, out...)
|
||||
index /= 26
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func xmlEscape(value string) string {
|
||||
var b strings.Builder
|
||||
_ = xml.EscapeText(&b, []byte(value))
|
||||
return b.String()
|
||||
}
|
||||
|
||||
const contentTypesXML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
||||
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
||||
<Default Extension="xml" ContentType="application/xml"/>
|
||||
<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
|
||||
<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>
|
||||
<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>
|
||||
<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>
|
||||
</Types>`
|
||||
|
||||
const rootRelsXML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
||||
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
|
||||
</Relationships>`
|
||||
|
||||
const workbookXML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
||||
<sheets>
|
||||
<sheet name="Sheet1" sheetId="1" r:id="rId1"/>
|
||||
</sheets>
|
||||
</workbook>`
|
||||
|
||||
const workbookRelsXML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
||||
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>
|
||||
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
|
||||
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>
|
||||
</Relationships>`
|
||||
|
||||
const stylesXML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
||||
<fonts count="1"><font><sz val="11"/><color theme="1"/><name val="Calibri"/><family val="2"/></font></fonts>
|
||||
<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>
|
||||
<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>
|
||||
<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>
|
||||
<cellXfs count="2"><xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/><xf numFmtId="49" fontId="0" fillId="0" borderId="0" xfId="0" applyNumberFormat="1"/></cellXfs>
|
||||
<cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>
|
||||
<dxfs count="0"/><tableStyles count="0" defaultPivotStyle="PivotStyleLight16" defaultTableStyle="TableStyleMedium2"/>
|
||||
</styleSheet>`
|
||||
Reference in New Issue
Block a user