Back to skills
extension
Category: OtherNo API key required

电商数据清洗skill正式版

退回成SKILL_最新版_颜色回退版_焦糖桶修订版

personAuthor: user_cf88f39ehubcommunity

销售主表终极重构与跨表检索专家规则 (Skill V16)

📌 技能概述

当接收到销售“主表”以及用于检索京东买家姓名的“人名对照表”时,立即激活本技能。Agent 将作为极其严谨的数据清洗专家,在内存中调度类似 Excel 的 VLOOKUP 检索与多表关联逻辑,严格执行以下定义的 16 列重构、条件清洗、字号规范、复合排序与全行色彩渲染规则。 🚨 终极铁律:绝对不能无中生有!如出现 Agent 无法完成或缺少源数据的情况,对应单元格必须留白(全空格或保持空单元格),严禁胡乱捏造。

---

🚨 第一阶段:最高优先级——全局自动脱壳清洗工序

  • 执行时机:在读取、检索、匹配或加工任意一列数据的任何单元格内容之前,必须首先无条件执行此工序。
  • 清洗法则:无论面对哪个字段(如子单原始单号、拆自组合装、店铺、收货地区等),只要发现开头有 = 或者整个文本被双引号 " 包裹(例如:="330174...""焦"),Agent 必须自动将它们剥离,只留下中间最纯净的明文文本,然后再进行后续的逻辑拼接、条件判断与公式生成。

---

📐 第二阶段:全局样式与字号规范

  1. 全局对齐:最终生成的 Excel 所有单元格(包括行表头与所有数据行)一律设置为 居中对齐

  2. 默认字号:全表所有单元格的字体大小如无特殊说明,一律默认为 12 号字大小。

  3. 特殊列字号:以下四列强制覆盖设置为 11 号字大小:

    • 第 5 列(餐饮配料)
    • 第 6 列(直销)
    • 第 12 列(含税金额)
    • 第 13 列(不含税金额)

---

📋 第三阶段:行表头定义

生成的 Excel 必须包含以下 16 列,行表头文字必须完全一致,展示时不思考含义,仅作表头: \["日期", "省份", "区域", "客户", "餐饮配料", "直销", "品种", "规格", "香型", "数量", "含税单价", "含税金额", "不含税金额", "备注", "订单号", "所属公司"]

---

⚙️ 第四阶段:各列核心转换与清洗逻辑

  1. A列 - 日期:不进行逻辑填充,全列留白,保持全列空格或空单元格。【字号:12号】

  2. B列 - 省份:提取主表【收货地区】字段的首段省份/自治区名称。无条件去掉“省”、“自治区”、“市”等所有行政后缀。【字号:12号】

    • 示例:“湖南省 湘西...” ➡️ 湖南;“广西壮族自治区 ...” ➡️ 广西;“北京市 ...” ➡️ 北京
  3. C列 - 区域:严格根据 B 列已经清洗出的【省份】进行条件匹配。必须100%忽略你自带的地理常识,必须100%严格执行以下映射规则:【字号:12号】

    • ① 如果包含 "吉林"、"黑龙"、"辽宁",输出:东北
    • ② 如果包含 "北京"、"天津"、"安徽"、"山东"、"内蒙"、"河北",输出:华北注:遇到安徽必须输出华北
    • ③ 如果包含 "陕西"、"甘肃"、"宁夏"、"河南"、"青海"、"山西",输出:西北
    • ④ 如果包含 "浙江"、"福建"、"江西",输出:华中
    • ⑤ 如果包含 "云南"、"贵州"、"四川"、"重庆"、"广西"、"湖北",输出:西南
    • ⑥ 如果包含 "江苏"、"上海",输出:华东
    • ⑦ 如果包含 "新疆"、"西藏"、"海南",输出:华南
    • ⑧ 如果包含 "广东",输出:广东
    • ⑨ 如果包含 "湖南",输出:湖南
  4. D列 - 客户(直辖市防重与京东跨表VLOOKUP双轨制):【字号:12号】

    • 【核心拦截:直辖市防重规则】:首先审查主表的【收货地区】。如果属于直辖市(北京、上海、重庆、天津),地理前缀强制固定为单个词(即 北京上海重庆天津),绝对禁止拼接二级城市或区县名,从源头上彻底阻断出现“北京北京3305...”等重复地名的现象!

    • 【非直辖市地理清洗规则】:若非直辖市,地理前缀格式为 省份/自治州 + 地级市。清洗逻辑具备严格的先后顺序: ①【关键剥离顺序】:必须优先检查并剥离末尾的“地区”(两个字)后缀!确认不包含“地区”后,再剥离“市”、“县”、“区”、“盟”等单字行政后缀。严禁先切单字。(例如:“新疆塔城地区”,必须先匹配并切除“地区”变为“新疆塔城”;严禁因先切除“区”字而错误残留为“新疆塔城地”)。 ② 移除“哈尼族”、“土家族”、“苗族”、“彝族”、“壮族”、“自治州”等所有民族和自治谓称。 ③ 安全兜底防御:针对“杭州”、“温州”、“广州”等本身自带“州”字的城市,如果去掉“州”字会导致核心名变成单字(如 杭、温、广),必须强制保留“州”字。只有当去掉“州”字后剩余文本长度 >= 2 时(如“红河州”->“红河”),才允许切除。

      • 非直辖市示例:浙江省 杭州市 ➡️ 浙江杭州;云南省 红河哈尼族彝族自治州 ➡️ 云南红河;广西壮族自治区 桂林市 ➡️ 广西桂林;新疆维吾尔自治区 塔城地区 ➡️ 新疆塔城
    • 【双轨制分流拼接逻辑】

      • 渠道一:若当前行备注(店铺)为“京东”:启动跨表 VLOOKUP 检索。以本行的【子单原始单号】作为 Key,去关联的“人名对照表”中检索对应的【买家姓名/收件人】。最终拼接格式为:地理前缀 + 检索到的人名(例如:浙江杭州张三北京李四)。若对照表中无此单号或姓名为空,则人名留空,仅保留地理前缀。
      • 渠道二:若当前行备注(店铺)为非京东渠道(淘宝、天猫、拼多多、抖音等):拼接格式严格执行:地理前缀 + 子单原始单号(例如:云南红河5116035746666059715北京3305519328451029988)。
  5. E列 - 餐饮配料:全列所有行数据统一固定填充文本:餐饮配料【字号:强制 11 号】

  6. F列 - 直销:全列所有行数据统一固定填充文本:直销【字号:强制 11 号】

  7. G列 - 品种:检索主表【拆自组合装】字段(优先经过第一阶段脱壳清洗),严格按照以下优先级判定逻辑链输出:【字号:12号】

    • ① 凡是出现 盐焗粉浓缩鲜香粉烧腊香味素去腥增香调味油凉拌菜调味油 之一的 ➡️ 统一输出:调味品
    • ② 包含 "I+G" ➡️ 输出:I+G
    • ③ 包含 "呋喃酮" ➡️ 输出:呋喃酮
    • ④ 包含 "甲基环戊烯醇酮" 或 "MCP" ➡️ 输出:MCP
    • ⑤ 包含 "甲基"(且不含环戊烯醇酮) ➡️ 输出:甲基
    • ⑥ 包含 "香兰素" ➡️ 输出:香兰素
    • ⑦ 上述皆不满足 ➡️ 统一输出默认值:乙基
  8. H列 - 规格:检索主表【拆自组合装】字段,严格按照以下特异性优先度从高到低的拦截链进行映射输出:【字号:12号】

    • ① 包含 "30g*3盐焗粉" ➡️ 输出:12KG箱
    • ② 包含 "1kg凉拌菜调味油" 或 "1kg去腥增香调味油" ➡️ 输出:1kg/瓶
    • ③ 包含 "500g凉拌菜调味油" 或 "500g去腥增香调味油" ➡️ 输出:0.5kg/瓶
    • ④ 包含 "250克" ➡️ 输出:5KG箱
    • ⑤ 包含 "焦桶"、"纯桶"、"特醇桶"、"焦糖桶" 之一 ➡️ 输出:10大小
    • ⑥ 包含 {"焦","纯","特醇","I+G","香兰素","呋喃酮","甲基","焦箱","纯箱","特醇箱","甲基环戊烯醇酮","香虎粉","焦糖香瓶"} 之一 ➡️ 输出:
    • ⑦ 若上述均未命中 ➡️ 统一输出默认值:
  9. I列 - 香型【注意:此步骤在重构的倒数第二步统一批量操作】。直接复制主表【拆自组合装】字段的纯文本,然后严格、彻底地将文本中的 "250克""箱""瓶"、"桶""500g""1kg""30g*3"关键字予以剔除并剥离。(*示例*:“250克纯瓶”转换为;“焦箱”转换为 焦`)。【字号:12号】

  10. J列 - 数量:直接映射主表的【实发数量】数值。【字号:12号】

  11. K列 - 含税单价:计算数值,计算公式为:主表【单品支付金额】 / 主表【实发数量】。【字号:12号】

  12. L列 - 含税金额:单元格内不填入死值,必须保留 Excel 原生计算公式字符串:=J{行号}\*K{行号}(例如第12725行,单元格公式为 =J12725\*K12725)。【字号:强制 11 号】

  13. M列 - 不含税金额:单元格内必须保留 Excel 原生计算公式字符串,公式为前一列除以 1.13:=L{行号}/1.13(例如第12690行,单元格公式为 =L12690/1.13)。重中之重:针对该整列单元格,必须在 Excel 中将单元格格式设置为“数值”格式,并严格保留 2 位小数。 【字号:强制 11 号】

  14. N列 - 备注:提取主表【店铺】字段,抹除所有多余文字,仅保留 淘宝天猫京东拼多多抖音 这五个标准核心核心词。

  15. O列 - 订单号:直接映射主表的【子单原始单号】。【字号:12号】

  16. P列 - 所属公司:根据 N 列【备注】进行拦截判断:【字号:12号】

    • 若备注为 "淘宝" ➡️ 输出:肇庆香料
    • 备注为其他任意店铺(天猫、京东、拼多多、抖音) ➡️ 统一输出:华宝星湖

---

📊 第五阶段:多级置顶复合排序与全行高亮渲染 (最后一步)

  1. 跨渠道店内多级置顶复合排序逻辑

    • 第一级大排序(店铺渠道排队):全表所有行严格按照 淘宝 ➡️ 天猫 ➡️ 京东 ➡️ 拼多多 ➡️ 抖音 的先后顺序进行大排队,形成 5 个连续的渠道区块。

    • 第二级大排序(店铺内部块的三级品种置顶):在上述每一个独立的店铺区块内部,必须再执行以下细分品种排序:

      • 【绝对置顶层】:凡是品种(G列)为 调味品 的行,必须强制集中排在当前店铺区块的最前面。
      • 【次优先层】:紧随其后排列品种(G列)不是“乙基” 的所有其他行(如香兰素、I+G、MCP、甲基等)。
      • 【行垫底层】:品种(G列)为 乙基 的行,必须全部排在当前店铺区块的最后面。
  2. 全行高亮色彩填充规则: 必须对整行(从 A 列到 P 列,包括没有任何文字的绝对空白单元格)进行无死角底色填充:

    • 天猫 店铺块所在整行:填充纯黄底色,十六进制码 #FFFF00
    • 京东 店铺块所在整行:填充绿底色,十六进制码 #92D050
    • 拼多多 店铺块所在整行:填充蓝底色,十六进制码 #00B0F0
    • 抖音 店铺块所在整行:填充橙底色,十六进制码 #ED7D31
    • 淘宝 店铺块所在整行:保持默认,不填充任何底色

---

🐍 附录:Agent 内部 Code Interpreter 自动化执行参考脚本

若 Agent 在执行过程中调用 Python 进行物理建表,已将切词逻辑完美修正(多字后缀在前,单字在后):

import re
import os
import pandas as pd
from openpyxl import Workbook
from openpyxl.styles import Alignment, PatternFill, Font

def clean\_shell(val):
    """全局自动脱壳清洗工序"""
    if pd.isna(val): return ""
    val\_str = str(val).strip()
    if val\_str.startswith('='):
        val\_str = val\_str.lstrip('=').strip('"')
    if val\_str.startswith('"') and val\_str.endswith('"'):
        val\_str = val\_str.strip('"')
    return val\_str.strip()

def process\_rebuild\_engine(main\_table\_path, name\_table\_path, output\_path):
    df\_main = pd.read\_csv(main\_table\_path) if main\_table\_path.endswith('.csv') else pd.read\_excel(main\_table\_path)
    
    # 建立京东人名 VLOOKUP 字典
    vlookup\_dict = {}
    if name\_table\_path and os.path.exists(name\_table\_path):
        df\_name = pd.read\_csv(name\_table\_path) if name\_table\_path.endswith('.csv') else pd.read\_excel(name\_table\_path)
        id\_col = \[c for c in df\_name.columns if '单号' in str(c) or '订单' in str(c)]\[0]
        name\_col = \[c for c in df\_name.columns if any(x in str(c) for x in \['人', '名', '姓名'])]\[0]
        for \_, n\_row in df\_name.iterrows():
            k = clean\_shell(n\_row.get(id\_col, ''))
            v = clean\_shell(n\_row.get(name\_col, ''))
            if k: vlookup\_dict\[k] = v

    region\_rules = {
        '东北': \['吉林', '黑龙', '辽宁'],
        '华北': \['北京', '天津', '安徽', '山东', '内蒙', '河北'],
        '西北': \['陕西', '甘肃', '宁夏', '河南', '青海', '山西'],
        '华中': \['浙江', '福建', '江西'],
        '西南': \['云南', '贵州', '四川', '重庆', '广西', '湖北'],
        '华东': \['江苏', '上海'],
        '华南': \['新疆', '西藏', '海南'],
        '广东': \['广东'], '湖南': \['湖南']
    }
    
    parsed\_rows = \[]
    for \_, row in df\_main.iterrows():
        shop\_raw = clean\_shell(row.get('店铺', ''))
        combo = clean\_shell(row.get('拆自组合装', ''))
        addr\_raw = clean\_shell(row.get('收货地区', ''))
        order\_id = clean\_shell(row.get('子单原始单号', ''))
        qty = clean\_shell(row.get('实发数量', ''))
        pay\_amt = clean\_shell(row.get('单品支付金额', ''))
        
        remark = ""
        for p in \['淘宝', '天猫', '京东', '拼多多', '抖音']:
            if p in shop\_raw: remark = p; break
        if not remark: continue 
        
        addr\_parts = addr\_raw.split()
        prov\_raw = addr\_parts\[0] if len(addr\_parts) > 0 else ""
        city\_raw = addr\_parts\[1] if len(addr\_parts) > 1 else ""
        
        prov = prov\_raw.replace("省", "").replace("自治区", "").replace("市", "")
        if "内蒙古" in prov: prov = "内蒙古"
        elif "广西" in prov: prov = "广西"
        elif "西藏" in prov: prov = "西藏"
        elif "新疆" in prov: prov = "新疆"
        elif "宁夏" in prov: prov = "宁夏"
        
        # 🚨 直辖市全切断防重复前缀拦截
        if prov in \["北京", "上海", "天津", "重庆"]:
            geo\_prefix = prov
        else:
            city = city\_raw
            # 🚨 完美修复:调整执行顺序,必须先判定长词“地区”,再判定单字“市县区盟”!
            if city.endswith('地区'): 
                city = city\[:-2] 
            elif city.endswith(('市', '县', '区', '盟')): 
                city = city\[:-1]
                
            city = re.sub(r'(哈尼族|土家族|苗族|彝族|藏族|回族|白族|傣族|景泼族|壮族|侗族|布依族|满族|蒙古族|哈萨克族|柯尔克孜族|羌族|各族|自治州|自治县)+', '', city)
            if city.endswith('州') and len(city) > 2: city = city\[:-1]
            geo\_prefix = f"{prov}{city}" if city else prov
            
        region = ""
        for reg, keywords in region\_rules.items():
            if any(k in prov for k in keywords): region = reg; break
        
        if remark == "京东":
            person\_name = vlookup\_dict.get(order\_id, "")
            customer = f"{geo\_prefix}{person\_name}"
        else:
            customer = f"{geo\_prefix}{order\_id}"
        
        # 品种逻辑判定
        if any(x in combo for x in \["盐焗粉", "浓缩鲜香粉", "烧腊香味素", "去腥增香调味油", "凉拌菜调味油"]): breed = "调味品"
        elif "I+G" in combo: breed = "I+G"
        elif "呋喃酮" in combo: breed = "呋喃酮"
        elif "甲基环戊烯醇酮" in combo or "MCP" in combo: breed = "MCP"
        elif "甲基" in combo: breed = "甲基"
        elif "香兰素" in combo: breed = "香兰素"
        else: breed = "乙基"
        
        # 规格逻辑判定
        if "30g\*3盐焗粉" in combo: spec = "12KG箱"
        elif any(x in combo for x in \["1kg凉拌菜调味油", "1kg去腥增香调味油"]): spec = "1kg/瓶"
        elif any(x in combo for x in \["500g凉拌菜调味油", "500g去腥增香调味油"]): spec = "0.5kg/瓶"
        elif "250克" in combo: spec = "5KG箱"
        elif any(x in combo for x in \["焦桶", "纯桶", "特醇桶", "焦糖桶"]): spec = "10大小"
        else:
            spec\_box = \["焦","纯","特醇","I+G","香兰素","呋喃酮","甲基","焦箱","纯箱","特醇箱","甲基环戊烯醇酮","香虎粉","焦糖香瓶"]
            spec = "箱" if any(x in combo for x in spec\_box) else "箱"
        
        try: unit\_price = float(pay\_amt) / float(qty) if float(qty) != 0 else ""
        except: unit\_price = ""
            
        company = "肇庆香料" if remark == "淘宝" else "华宝星湖"
        
        parsed\_rows.append({
            '日期': ' ', '省份': prov, '区域': region, '客户': customer, '餐饮配料': '餐饮配料', '直销': '直销',
            '品种': breed, '规格': spec, 'combo\_raw': combo, '数量': qty, '含税单价': unit\_price,
            '备注': remark, '订单号': order\_id, '所属公司': company
        })
        
    res\_df = pd.DataFrame(parsed\_rows)
    if res\_df.empty: return
    
    # 倒数第二步:批量剥离香型关键字
    removals = \["250克", "箱", "瓶", "桶", "500g", "1kg", "30g\*3"]
    def clean\_flavor(text):
        for word in removals: text = text.replace(word, "")
        return text
    res\_df\['香型'] = res\_df\['combo\_raw'].apply(clean\_flavor)
    res\_df = res\_df.drop(columns=\['combo\_raw'])
    
    # 店铺与多级置顶排序权重计算
    shop\_weight = {'淘宝': 1, '天猫': 2, '京东': 3, '拼多多': 4, '抖音': 5}
    res\_df\['shop\_w'] = res\_df\['备注'].map(shop\_weight)
    res\_df\['breed\_w'] = res\_df\['品种'].apply(lambda b: 0 if b == '调味品' else (1 if b != '乙基' else 2))
    res\_df = res\_df.sort\_values(by=\['shop\_w', 'breed\_w']).reset\_index(drop=True)
    res\_df = res\_df.drop(columns=\['shop\_w', 'breed\_w'])
    
    # 生成 Excel 并渲染
    wb = Workbook()
    ws = wb.active
    ws.title = "重构账目表"
    
    headers = \["日期", "省份", "区域", "客户", "餐饮配料", "直销", "品种", "规格", "香型", "数量", "含税单价", "含税金额", "不含税金额", "备注", "订单号", "所属公司"]
    ws.append(headers)
    
    fills = {
        '天猫': PatternFill(start\_color="FFFF00", end\_color="FFFF00", fill\_type="solid"),
        '京东': PatternFill(start\_color="92D050", end\_color="92D050", fill\_type="solid"),
        '拼多多': PatternFill(start\_color="00B0F0", end\_color="00B0F0", fill\_type="solid"),
        '抖音': PatternFill(start\_color="ED7D31", end\_color="ED7D31", fill\_type="solid")
    }
    center\_align = Alignment(horizontal="center", vertical="center")
    font\_12 = Font(size=12)
    font\_11 = Font(size=11)
    
    for col\_idx in range(1, 17):
        ws.cell(row=1, column=col\_idx).font = font\_12
        ws.cell(row=1, column=col\_idx).alignment = center\_align
        
    for i, r in res\_df.iterrows():
        row\_idx = i + 2
        row\_data = \[
            r\['日期'], r\['省份'], r\['区域'], r\['客户'], r\['餐饮配料'], r\['直销'],
            r\['品种'], r\['规格'], r\['香型'], r\['数量'], r\['含税单价'],
            f"=J{row\_idx}\*K{row\_idx}", f"=L{row\_idx}/1.13",      
            r\['备注'], r\['订单号'], r\['所属公司']
        ]
        ws.append(row\_data)
        
        row\_fill = fills.get(r\['备注'], None)
        # 🚨 对整行(包含空白列)强制进行颜色填充与字号分级
        for col\_idx in range(1, 17):
            cell = ws.cell(row=row\_idx, column=col\_idx)
            cell.alignment = center\_align
            if row\_fill: cell.fill = row\_fill
            cell.font = font\_11 if col\_idx in \[5, 6, 12, 13] else font\_12
            if col\_idx == 13: cell.number\_format = '0.00'
                
    wb.save(output\_path)