local addonName, ZLAUTO= ...

local ZL = ZLAUTO.mainFrame
local REALM_SEPARATOR_LIST = {}
local cGetItemInfo = C_Item and C_Item.GetItemInfo or GetItemInfo
local cGetItemIcon = C_Item and C_Item.GetItemIconByID or GetItemIcon
local GetItemCount = C_Item and C_Item.GetItemCount or GetItemCount
local GetItemInfoInstant = C_Item and C_Item.GetItemInfoInstant or GetItemInfoInstant
local GetItemSpecInfo = C_Item and C_Item.GetItemSpecInfo or GetItemSpecInfo
local GetSpecialization = C_SpecializationInfo and C_SpecializationInfo.GetSpecialization or GetSpecialization
local GetSpecializationInfo = C_SpecializationInfo and C_SpecializationInfo.GetSpecializationInfo or GetSpecializationInfo
local IsAddOnLoaded = C_AddOns and C_AddOns.IsAddOnLoaded or IsAddOnLoaded
local LoadAddOn = C_AddOns and C_AddOns.LoadAddOn or LoadAddOn
local GetLootMethod = C_PartyInfo and C_PartyInfo.GetLootMethod or GetLootMethod
local GetItemStats = C_Item and C_Item.GetItemStats or GetItemStats
local MyAddon = ZL.MyAddon
for s in REALM_SEPARATORS:gmatch(".") do tinsert(REALM_SEPARATOR_LIST, s) end
ZL.BUILD_DATA = floor(select(4, GetBuildInfo())/10000)
ZL.colorList = {
    waiting = {1, 1, 1, 1},
    auctioning = {0, 0, 1, 1},
    success = {0, 1, 0, 1},
    failed = {1, 0, 0, 1},
    lgnore = {0.5, 0.5, 0.5, 1},
    other = {0.2, 0.2, 0.2, 1}
}


--将RGB转换为|caarrggbb|r格式
function ZL.RGBAToHex(r, g, b, a)
    a = a or 1
    r = math.max(0, math.min(255, r))
    g = math.max(0, math.min(255, g))
    b = math.max(0, math.min(255, b))
    a = math.max(0, math.min(255, a))
    return string.format("|c%02X%02X%02X%02X", a, r, g, b)
end
--背景，测试用
function ZL.background(frame)
    frame.background = frame:CreateTexture(nil, "BACKGROUND")
    frame.background:SetAllPoints(frame) -- 让纹理覆盖整个Frame
    frame.background:SetColorTexture(math.random(), math.random(), math.random()) -- 设置为随机颜色
end

--设置消息前缀为[AutoAuction]
function ZL.Prefix(...)
    return string.join(" ", format("|cff4080FF%s|r", "[AutoAuction]"), tostringall(...))
end

--聊天窗口默认不显示, 滚动消息默认显示
function ZL.Print(msgStr, ChatFrame, notScrollFrame, r, g, b)
    r = r or 1
    g = g or 0.82
    b = b or 0
    if ChatFrame then
        DEFAULT_CHAT_FRAME:AddMessage(ZL.Prefix(msgStr), r, g, b)
    end
    if not notScrollFrame and ZL.ScrollingMessageFrame then
        ZL.ScrollingMessageFrame:AddMessage(msgStr, r, g, b)
    end
end

--定义空元表
function ZL.emptytable(...)
    local logTableRequests = false
    local tables = {}
    local meta = {
        __index = {
            Release=function(t,noRecursion)
                if not noRecursion then
                    for key,val in pairs(t) do
                        if (type(val) == "table") and (getmetatable(val) == "TempTable") then
                            val:Release()
                        end
                    end
                end
                table.wipe(t)
                if not tContains(tables,t) then
                    tinsert(tables,t)
                end
            end,
        },
        __metatable = "TempTable",
    }
    if logTableRequests then
        TempTables_RequestLog = {}
    end
    local t = tremove(tables) or setmetatable({},meta)
    for i=1,select('#',...) do
        t[i] = (select(i,...))
    end
    if logTableRequests then
        local tostrT = tostring(t)
        TempTables_RequestLog[tostrT] = TempTables_RequestLog[tostrT] or {}
        tinsert(TempTables_RequestLog[tostrT],debugstack())
    end
    return t
end
-- 团队官员，非团长
function ZL.IsRaidOfficer()
	return IsInRaid(1) and UnitIsRaidOfficer("player")
end
--小队队长或团队团长
function ZL.IsRaidLeader(playerName)
	playerName = playerName or "player"
    playerName = ZL.ParseClassColorName(playerName)
    playerName = ZL.pruneCrossRealm(playerName)
    return IsInRaid(1) and UnitIsGroupLeader(playerName)
end

--是否拥有拾取权限(ML权限)，默认为玩家自己
function ZL.PlayerIsML(playerName)
    playerName = playerName or UnitName("player")
    playerName = ZL.ParseClassColorName(playerName)
    playerName = ZL.pruneCrossRealm(playerName)
    if IsInRaid(1) then
        local lootMethod, _, raidMaster = GetLootMethod()
        if (lootMethod == "master" or lootMethod == 2) and (raidMaster == UnitInRaid(playerName)) then
            return true
        elseif (lootMethod == "group" or lootMethod == 3 or lootMethod == "personalloot" or lootMethod == 5) then
            if ZL.opt.appointMLName then
                local newAppointMLName = ZL.pruneCrossRealm(ZL.opt.appointMLName)
                if UnitInRaid(newAppointMLName) then
                    if newAppointMLName == playerName then
                        return true
                    else
                        return false
                    end
                else
                    if UnitIsGroupLeader(playerName) then
                        return true
                    else
                        return false
                    end
                end
            else
                if UnitIsGroupLeader(playerName) then
                    return true
                else
                    return false
                end
            end
        else
            return false
        end
    elseif IsInRaid(2) or IsInGroup() then
        return false
    else
        if playerName ~= UnitName("player") then
            return false
        else
            return true
        end
    end
end

--获取ML的名字
function ZL.GetMLname()
    local MLname
    if IsInRaid(1) then
        local lootMethod, _, masterlooterRaidID = GetLootMethod()
        if lootMethod == "master" or lootMethod == 2 then
            MLname = ZL.GetFullName(GetUnitName("raid" .. masterlooterRaidID, true))
        elseif (lootMethod == "group" or lootMethod == 3 or lootMethod == "personalloot" or lootMethod == 5) then
            MLname = (ZL.opt.appointMLName and UnitInRaid(ZL.pruneCrossRealm(ZL.opt.appointMLName))) and ZL.opt.appointMLName or ZL.GetRLname()
        end
        if MLname == "未知目标" then MLname = nil end
    end
    return MLname
end

--获取RL的名字
function ZL.GetRLname()
    for i = 1, MAX_RAID_MEMBERS do
        local name, rank = GetRaidRosterInfo(i)
        if rank == 2 then
            return ZL.GetFullName(name)
        end
    end
end
--战利品窗口槽是否为物品：0表示没有东西，1表示为物品，2表示为钱
function ZL.LootSlotIsItem(i)
	return (GetLootSlotType(i) == 1)
end

-- 如果GetUnitName不能解析名字为unitID，需我们自己的定义，手动解析
function ZL.localNameOnly(name)
	for _, s in ipairs(REALM_SEPARATOR_LIST) do
		local i = name:find(s, 1, true)
		if i then name = name:sub(1, i - 1) break end
	end
	return name
end


--处理服务器后缀名字，本服务器去掉服务器名
function ZL.pruneCrossRealm(name)
	name = ZL.ParseClassColorName(name)
    return GetUnitName(name, true) or ZL.localNameOnly(name)
end

--获取带服务器的名字
function ZL.GetFullName(name, realm)
    name = name or UnitName("player")
    name = ZL.ParseClassColorName(name)
    if name:find('-', nil, true) then
        return name
    end

    if not realm or realm == '' then
        realm = GetNormalizedRealmName()
    end
    if not realm or realm == '' then
        realm = GetRealmName():gsub(' +', '')
    end
    return name .. '-' .. realm
end
--获取不带服务器的名字
function ZL.GetNoRealmName(name, isColor)
    name = name or UnitName("player")
    local pos = name:find("%-")
    if pos then
        name = name:sub(1, pos-1)
        if name:match("|c%x%x%x%x%x%x%x%x.-") then
            name = name .. "|r"
        end
    end
    if isColor then
        name = ZL.GetClassColorName(name)
    else
        name = ZL.ParseClassColorName(name)
    end
    return name
end
--创建默认按钮
function ZL.CreateButton(ButtonName, parent, ButtonText, point, relativeto, relativePoint, offsetX, offsetY, Width, Height, fontSize, NormalTexture, BorderA)
	offsetX = offsetX or 0
	offsetY = offsetY or 0
	Width = Width or 70
	Height = Height or 20
	fontSize = fontSize or 14
    BorderA = BorderA or 0.5
	local btn = CreateFrame("Button", ButtonName, parent) -- , "UIPanelButtonTemplate"
    ZL.CreateBorder(btn, 0.24, 0.25, 0.3, BorderA, "OVERLAY", 1)
	btn:SetText(ButtonText or " ")
	btn:SetSize(Width, Height)
    btn:SetPoint(point, relativeto, relativePoint, offsetX, offsetY)
    do
        local texture = btn:CreateTexture(nil,"BACKGROUND")
		texture:SetColorTexture(0,0,0,1)
		texture:SetPoint("TOPLEFT")
		texture:SetPoint("BOTTOMRIGHT")
        btn.Background = texture
    end

    if NormalTexture then
        local texture = btn:CreateTexture(nil,"BACKGROUND")
        texture:SetColorTexture(1,1,1,1)
        texture:SetGradient("VERTICAL",CreateColor(0.05,0.06,0.09,1), CreateColor(0.20,0.21,0.25,1))
        texture:SetPoint("TOPLEFT")
        texture:SetPoint("BOTTOMRIGHT")
        btn:SetNormalTexture(texture)
    end
    do
        local texture = btn:CreateTexture()
        texture:SetColorTexture(0.9,0.9,0.9,.2)
        texture:SetPoint("TOPLEFT")
        texture:SetPoint("BOTTOMRIGHT")
        btn:SetHighlightTexture(texture)
    end
    -- do
    --     local texture = btn:CreateTexture()
    --     texture:SetColorTexture(.9,.8,.1,.3)
    --     texture:SetPoint("TOPLEFT")
    --     texture:SetPoint("BOTTOMRIGHT")
    --     btn:SetPushedTexture(texture)
    -- end
	btn:SetNormalFontObject("GameFontNormal")
	btn:SetHighlightFontObject("GameFontHighlight")
	btn:SetDisabledFontObject("GameFontDisable")
    local fontString = btn:GetFontString()
    if fontString then
	    fontString:SetFont(GameFontNormal:GetFont(), fontSize)
    end
	return btn
end

function ZL.CreateHeaderButton(parent, width, height, size)
    local btn = CreateFrame("Button", nil, parent)
    btn:SetSize(width or 40, height or 21)

    -- 背景层
    local backgroundLeft = btn:CreateTexture("backgroundLeft", "BACKGROUND")
    backgroundLeft:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
    backgroundLeft:SetSize(8, height)
    backgroundLeft:SetPoint("TOPLEFT")
    backgroundLeft:SetTexCoord(0.0625, 0.1875, 0.34375, 1)

    local backgroundRight = btn:CreateTexture("backgroundRight", "BACKGROUND")
    backgroundRight:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
    backgroundRight:SetSize(8, height)
    backgroundRight:SetPoint("TOPRIGHT")
    backgroundRight:SetTexCoord(0.8125, 0.9375, 0.34375, 1)
    -- backgroundRight:SetColorTexture(0.25, 0.25, 0.25, 1)
    
    local backgroundMid = btn:CreateTexture("backgroundMid", "BACKGROUND")
    backgroundMid:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
    backgroundMid:SetSize(0, height)
    backgroundMid:SetPoint("TOPLEFT", 8, 0)
    backgroundMid:SetPoint("TOPRIGHT", -8, 0)
    backgroundMid:SetTexCoord(0.1875, 0.8125, 0.34375, 1)
    -- backgroundMid:SetColorTexture(0.25, 0.25, 0.25, 1)

    do
        local texture = btn:CreateTexture()
        texture:SetColorTexture(0, 0, 1, 0.2)
        texture:SetPoint("TOPLEFT")
        texture:SetPoint("BOTTOMRIGHT")
        btn:SetHighlightTexture(texture)
    end
    -- 按钮文本
    -- local customFont = CreateFont("CustomFont")
    -- customFont:SetFont(GameFontNormal:GetFont(), size or 14, "")  -- 字体路径、大小、字体样式
    -- customFont:SetTextColor(1, 1, 1)
	-- btn:SetNormalFontObject(customFont) --GameFontNormal
    btn:SetNormalFontObject("GameFontNormal")
	btn:SetHighlightFontObject("GameFontHighlight")
	btn:SetDisabledFontObject("GameFontDisable")
    -- local fontString = btn:GetFontString()
	-- fontString:SetFont(GameFontNormal:GetFont(), size)

    return btn
end
--创建边框
function ZL.CreateBorder(frame, r, g, b, a, drawLayer, size)
    drawLayer = drawLayer or "OVERLAY"
    size = size or 1
    frame.BorderTop = frame.BorderTop or frame:CreateTexture(nil,drawLayer) --BACKGROUND  OVERLAY
    frame.BorderTop:SetColorTexture(r,g,b,a)
    -- frame.BorderTop:SetTexture([[Interface\Common\UI-TooltipDivider-Transparent]])
    frame.BorderTop:SetPoint("TOPLEFT",frame,"TOPLEFT",0,0)
    frame.BorderTop:SetPoint("BOTTOMRIGHT",frame,"TOPRIGHT",0,-size)
    -- frame.BorderTop = frame.BorderTop or frame:CreateLine()
    -- frame.BorderTop:SetColorTexture(r,g,b,a)
    -- frame.BorderTop:SetStartPoint("TOPLEFT", 0, 0)
    -- frame.BorderTop:SetEndPoint("TOPRIGHT", 0, 0)
    -- frame.BorderTop:SetThickness(size)

    frame.BorderBottom = frame.BorderBottom or frame:CreateTexture(nil,drawLayer)
    frame.BorderBottom:SetColorTexture(r,g,b,a)
    -- frame.BorderBottom:SetTexture([[Interface\Common\UI-TooltipDivider-Transparent]])
    frame.BorderBottom:SetPoint("BOTTOMLEFT",frame,"BOTTOMLEFT",0,0)
    frame.BorderBottom:SetPoint("TOPRIGHT",frame,"BOTTOMRIGHT",0,size)
    -- frame.BorderBottom = frame.BorderBottom or frame:CreateLine()
    -- frame.BorderBottom:SetColorTexture(r,g,b,a)
    -- frame.BorderBottom:SetStartPoint("BOTTOMLEFT", 0, 0)
    -- frame.BorderBottom:SetEndPoint("BOTTOMRIGHT", 0, 0)
    -- frame.BorderBottom:SetThickness(size)

    frame.BorderLeft = frame.BorderLeft or frame:CreateTexture(nil,drawLayer)
    frame.BorderLeft:SetColorTexture(r,g,b,a)
    frame.BorderLeft:SetPoint("TOPLEFT",frame,"TOPLEFT",0,-size)
    frame.BorderLeft:SetPoint("BOTTOMRIGHT",frame,"BOTTOMLEFT",size,size)
    -- frame.BorderLeft = frame.BorderLeft or frame:CreateLine()
    -- frame.BorderLeft:SetColorTexture(r,g,b,a)
    -- frame.BorderLeft:SetStartPoint("TOPLEFT", 0, 0)
    -- frame.BorderLeft:SetEndPoint("BOTTOMLEFT", 0, 0)
    -- frame.BorderLeft:SetThickness(size)



    frame.BorderRight = frame.BorderRight or frame:CreateTexture(nil,drawLayer)
    frame.BorderRight:SetColorTexture(r,g,b,a)
    frame.BorderRight:SetPoint("TOPLEFT",frame,"TOPRIGHT",-size,-size)
    frame.BorderRight:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,size)
    -- frame.BorderRight = frame.BorderRight or frame:CreateLine()
    -- frame.BorderRight:SetColorTexture(r,g,b,a)
    -- frame.BorderRight:SetStartPoint("TOPRIGHT", 0, 0)
    -- frame.BorderRight:SetEndPoint("BOTTOMRIGHT", 0, 0)
    -- frame.BorderRight:SetThickness(size)
end

--创建框架
function ZL.ZLCreateFrame(FrameName, parent, Width, Height, FrameStrata, ClampedToScreen, Movable, TitleText)
    local f = CreateFrame("Frame", FrameName, parent or ZL)
    ZL.CreateBorder(f, 1, 1, 1, 0.5, "OVERLAY", 1)
    f:SetSize(Width or 370, Height or 400)
    f:SetFrameStrata(FrameStrata or "DIALOG")
    f:SetClampedToScreen(ClampedToScreen and true or false)
    f:SetMovable(Movable and true or false)
    f:SetResizable(true)
    f:SetToplevel(true)
    f:SetResizeBounds(370, 219, GetScreenWidth()-30, GetScreenHeight()-50) -- 设置最小尺寸，以避免框架被缩小到看不见
    ZL.CreateResizeButton(f)

    f.Background = f:CreateTexture(nil,"BACKGROUND")
    f.Background:SetColorTexture(0, 0, 0, .8)
    f.Background:SetPoint("TOPLEFT")
    f.Background:SetPoint("BOTTOMRIGHT")

    f.TitleBottom = f:CreateTexture(nil,"ARTWORK")
    f.TitleBottom:SetColorTexture(1, 1, 1, 0.5)
    f.TitleBottom:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -26)
    f.TitleBottom:SetPoint("BOTTOMRIGHT", f, "TOPRIGHT", 0, -27)

    f.Title = f:CreateFontString(nil, "OVERLAY")
    f.Title:SetFont(GameFontNormal:GetFont(), 15, "")
    f.Title:SetTextColor(1, 0.82, 0)
    f.Title:SetWordWrap(false)
    f.Title:SetJustifyH("CENTER")
    f.Title:SetJustifyV("MIDDLE")
    f.Title:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -1)
    f.Title:SetPoint("TOPRIGHT", f, "TOPRIGHT", -20, 0)
    f.Title:SetHeight(26)
    f.Title:SetText(TitleText or "")

    f.closeButton = CreateFrame("Button", nil, f, "UIPanelCloseButton")
    f.closeButton:SetPoint("LEFT", f.Title, "RIGHT", -5, 0)
    f.closeButton:SetSize(20, 20)
    f.closeButton:SetScript("OnClick", function (self)
        f:Hide()
    end)
    if Movable then
        f:SetScript("OnMouseUp", function (self)
            self:StopMovingOrSizing()
        end)
        f:SetScript("OnMouseDown", function (self)
            self:StartMoving()
        end)
    end
    return f
end
--创建文本框
--parent, width, heigth, fontSize, justifyH, numeric, multiLine, r, g, b, a, name
function ZL.CreateEditBox(parent, width, heigth, fontSize, justifyH, numeric, multiLine, r, g, b, a, name)
    r = r or 0.24
    g = g or 0.25
    b = b or 0.3
    a = a or 1
    local editBox = CreateFrame("EditBox", name, parent, BackdropTemplateMixin and "BackdropTemplate")
    editBox:EnableMouse(true)
    ZL.CreateBorder(editBox, r, g, b, a, "OVERLAY", 1)

    editBox.Background = editBox:CreateTexture(nil,"BACKGROUND")
    editBox.Background:SetColorTexture(0,0,0,1)
    editBox.Background:SetPoint("TOPLEFT")
    editBox.Background:SetPoint("BOTTOMRIGHT")

    editBox:SetFontObject("ChatFontNormal")

    editBox:SetTextInsets(4, 4, 0, 0)
    editBox:SetSize(width or 60, heigth or 20)
    editBox:SetFont(GameFontNormal:GetFont(), fontSize or 14, "")
    editBox:SetMultiLine(multiLine)
    editBox:SetTextColor(0.95, 0.95, 0.95)
    editBox:SetAutoFocus(false)
    editBox:SetNumeric(numeric)
    editBox:SetJustifyH(justifyH or "CENTER")

    editBox:SetScript("OnEscapePressed",function (self)
        self:ClearFocus()
    end)
    editBox:SetScript("OnEnterPressed", function (self)
        self:ClearFocus()
    end)
    editBox:SetScript("OnEditFocusLost",function (self)
        self:HighlightText(0, 0)
    end)
    editBox:SetScript("OnEditFocusGained",function (self)
        self:HighlightText()
    end)

    return editBox
end

--创建拉升按钮
function ZL.CreateResizeButton(parent)
    -- 创建右下角的拉伸角标
    -- AuctionFrame.resizeButton = CreateFrame("Button", nil, AuctionFrame)
    local resizeButton = CreateFrame("Button", nil, parent)
    resizeButton:SetSize(16, 16)
    resizeButton:SetPoint("BOTTOMRIGHT")

    -- 设置拉伸角标的纹理，可以是默认的角标图案
    resizeButton.texture = resizeButton:CreateTexture(nil, "BACKGROUND")
    resizeButton.texture:SetAllPoints()
    resizeButton.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up") -- 默认拉伸图标
    -- 鼠标悬停和点击效果
    resizeButton:SetHighlightTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Highlight")
    resizeButton:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Down")
    -- 设置鼠标按下时开始调整大小
    resizeButton:SetScript("OnMouseDown", function(self, button)
        if button == "LeftButton" then
            parent:StartSizing("BOTTOMRIGHT")
        end
    end)
    -- 鼠标松开时停止调整大小
    resizeButton:SetScript("OnMouseUp", function(self, button)
        parent:StopMovingOrSizing()
    end)
    parent.resizeButton = resizeButton
end

--重写滑动条鼠标滚动事件
function ZL.ScrollFrame_OnMouseWheel(self, delta)
    local newValue = self:GetVerticalScroll() - (delta * 20)
    if newValue < 0 then
        newValue = 0
    elseif newValue > self:GetVerticalScrollRange() then
        newValue = self:GetVerticalScrollRange()
    end
    self:SetVerticalScroll(newValue)
end

--根据itemlink和itemindex获取数据库中是否已存在该拍卖物品
function ZL.FetchDataFromItemId(itemlink, itemindex)
    if ZL_CURRENT.auctionlist and #ZL_CURRENT.auctionlist > 0 then
        for index, data in ipairs(ZL_CURRENT.auctionlist) do
            if (data.itemlink == itemlink) and (data.itemindex == itemindex) then --注意匹配时数据类型是否一致
                return data, index
            end
        end
    end
    return nil, nil
end
--按钮点击间隔时间
function ZL.btnDelay(self)
    C_Timer.After(0.3, function() --ZL.opt.buttonReenableDelay
        self:Disable()
        C_Timer.After(1, function() --ZL.opt.buttonReenableDelay
            self:Enable()
        end)
    end)
end
--没被忽略情况下，拍卖状态的物品个数:拍卖中，等待拍卖，成功，流拍, 忽略
function ZL.auctionStateCount()
    local auctioningCount = 0
    local waitingCount = 0
    local successCount = 0
    local failedCount = 0
    local lgnoreCount = 0
    if ZL_CURRENT.auctionlist then
        for _, frame in ipairs(ZL_CURRENT.auctionlist) do
            if frame.lgnore then
                lgnoreCount = lgnoreCount + 1
            else
                if frame.state == "auctioning" then
                    auctioningCount = auctioningCount + 1
                elseif frame.state == "waiting" then
                    waitingCount = waitingCount + 1
                elseif frame.state == "success" then
                    successCount = successCount + 1
                elseif frame.state == "failed" then
                    failedCount = failedCount + 1
                end
            end
        end
    end
    return auctioningCount, waitingCount, successCount, failedCount, lgnoreCount
end
--通过itemId获取数组表的索引
function ZL.GetIndex(table, itemId)
    for index, data in ipairs(table) do
        if data.itemId == itemId then
            return index
        end
    end
    return nil
end

--获取起拍价和每次最低加价，优先顺序：独立的物品设置，按照物品等级设置，默认设置
function ZL.GetStartAndIncrementBid(itemId)
	local ZL_SETTING = ZL.opt.ZL_SETTING
    local index = ZL.GetIndex(ZL_SETTING["itemIdSetting"], itemId)
    if index then
        return ZL_SETTING["itemIdSetting"][index].startbid, ZL_SETTING["itemIdSetting"][index].increment
    end
    --然后查询按照物品等级，如果存在，则按照物品等级设置返回
    --先判断物品类型
    if (ZL_SETTING["itemLevelSetting"] and #ZL_SETTING["itemLevelSetting"] > 0) then
        local itemType = nil
        local itemLevel = ZL.setsItemLevelData[tostring(itemId)] --查询是否为兑换套装物品
        if itemLevel then
            itemType = "套装"
        else
            local function linshi(itemlink)
            end
            ZL.LoadItemDataByID(itemId, linshi, ZL.AuctionFrame2)
            local _, _, _, _itemLevel, _, _itemType, _itemSubType, _, _itemEquipLoc, _, _, _, _, _, _, _setID = cGetItemInfo(itemId)
            if _setID then
                itemType = "套装"
            else
                if _itemType == "护甲" then
                    --装备槽位为13,14(饰品)，16,17,18(武器类)
                    if _itemEquipLoc == "INVTYPE_TRINKET" or _itemEquipLoc == "INVTYPE_SHIELD" or _itemEquipLoc == "INVTYPE_HOLDABLE" or
                    _itemEquipLoc == "INVTYPE_WEAPON" or _itemEquipLoc == "INVTYPE_RANGED" or _itemEquipLoc == "INVTYPE_2HWEAPON" or
                    _itemEquipLoc == "INVTYPE_WEAPONMAINHAND" or _itemEquipLoc == "INVTYPE_WEAPONOFFHAND" or
                    _itemEquipLoc == "INVTYPE_THROWN" or _itemEquipLoc == "INVTYPE_RANGEDRIGHT" then
                        itemType = "武器饰品"
                    else
                        itemType = "散件"
                    end
                elseif _itemType == "武器" then
                    itemType = "武器饰品"
                else
                    itemType = _itemType
                end
            end
            itemLevel = _itemLevel
        end
        if itemType then
            for _, d in ipairs(ZL_SETTING["itemLevelSetting"]) do
                if (d.minLevel <= itemLevel) and (d.maxLevel >= itemLevel) then
                    if itemType == "散件" and d.sanJianStartBid > 0  then
                        return d.sanJianStartBid, d.increment
                    elseif itemType == "套装" and d.taoZhuangStartBid > 0  then
                        return d.taoZhuangStartBid, d.increment
                    elseif itemType == "武器饰品" and d.wuQiStartBid > 0  then
                        return d.wuQiStartBid, d.increment
                    end
                end
            end
        end
    end
    return ZL.opt.startBid, ZL.opt.increment --全局默认值
end

--按区间设置加价幅度
function ZL.GetDiffrentIncrementBid(startbidamount, bidIncrement)
    if ZL_CURRENT.globalConfig.intervalBidIncrement then
        if startbidamount < ZL_CURRENT.globalConfig.baseAmount1 then
            bidIncrement = ZL_CURRENT.globalConfig.bidIncrement
        elseif startbidamount < ZL_CURRENT.globalConfig.baseAmount2 then
            bidIncrement = ZL_CURRENT.globalConfig.bidIncrement1
        elseif startbidamount < ZL_CURRENT.globalConfig.baseAmount3 then
            bidIncrement = ZL_CURRENT.globalConfig.bidIncrement2
        else
            bidIncrement = ZL_CURRENT.globalConfig.bidIncrement3
        end
    end
    return bidIncrement
end
--获取新的基础价，加价，目标价
function ZL.GetNewBidAmount(v)
    local fdata = ZL_CURRENT.auctionlist[v]
    local itemCount = fdata.itemCount
    local bidderlist = fdata.bidderlist
    local tarbidamount = 0
    local bidIncrement = fdata.bidIncrement
    local baseamount = 0
    local successBidderCount = 0
    local successIndex
    local successList = {}
    local bidCount = 0
    ZL.tableSort(bidderlist)
    for _successIndex, bidData in ipairs(bidderlist) do
        if successBidderCount < itemCount then
            local count = bidData["bidCount"] or 1
            if (successBidderCount + count) >= itemCount then
                count = itemCount - successBidderCount
                ZL_CURRENT.auctionlist[v].bidderlist[_successIndex].bidCount = count
            end
            --(出价，最大可竞拍数量，累计入围数量)
            tinsert(successList, {bidData.bidamount, itemCount-successBidderCount, successBidderCount + count})
            successIndex = _successIndex
            successBidderCount = successBidderCount + count
        else
            break
        end
    end
    --如果总的出价数量小于物品总数量，则按照起拍价
    if successBidderCount < itemCount then
        baseamount = fdata.startbidamount
    else
        baseamount = bidderlist[successIndex].bidamount
    end
    bidIncrement = ZL.GetDiffrentIncrementBid(baseamount, bidIncrement)
    if successBidderCount >= itemCount then
        tarbidamount = baseamount + bidIncrement
        for _, data in ipairs(successList) do
            if data[1] == baseamount then
                bidCount =data[2]
                break
            end
        end
    else
        tarbidamount = fdata.startbidamount
        bidCount = itemCount - successBidderCount
    end
    if tarbidamount >= bidIncrement then
        tarbidamount = tarbidamount - tarbidamount % bidIncrement
    end
    return baseamount, bidIncrement, tarbidamount, bidCount, successList
end

--返回开始拍卖语音文字
function ZL.GetAuctionSoundText(itemInfo)
    if itemInfo == "[打包拍卖]" then return "打包物品" end
    local itemName, itemLink, _, itemLevel, _, itemType, itemSubType, _, itemEquipLoc, _, _, _, _, bindType, _, setID = cGetItemInfo(itemInfo)
    local itemId = tonumber(itemLink:match("|Hitem:(%d+):"))
    local profession --职业
    local soundText = ""
    --获取职业限制信息
    if (not ZL.itemToolTip) then
        ZL.itemToolTip = CreateFrame("GameTooltip", "ZLitemToolTip", nil, "GameTooltipTemplate")
    end
    ZL.itemToolTip:SetOwner(UIParent, "ANCHOR_NONE")
    ZL.itemToolTip:ClearLines()
    ZL.itemToolTip:SetHyperlink(itemLink)
    for i = 1, ZL.itemToolTip:NumLines() do
        -- 遍历每一行并打印内容
        local leftLine = _G["ZLitemToolTipTextLeft"..i]
        if leftLine and leftLine:GetText() then
            local text = leftLine:GetText()
            profession = string.match(text, "^职业：(.+)")
            if profession then
                break
            end
        end
        -- local rightLine = _G["ZLitemToolTipTextRight"..i]
        -- if rightLine and rightLine:GetText() then
        --     local text = rightLine:GetText()
        --     local profession1 = string.match(text, itemSubType)
        --     if profession1 then
        --         local r, g, b = rightLine:GetTextColor()
        --         print(text, r, g, b)
        --         if not (r == 1 and g == 1 and b == 1) then
        --             print(text, "无法装备")
        --         else
        --             print("可以装备")
        --         end
        --     end
        -- end
    end
    local _itemLevel = ZL.setsItemLevelData[tostring(itemId)] --查询是否为兑换套装物品
    if _itemLevel then
        soundText = soundText .. "套装：" .. itemName .. "，装等：" .. ZL.convertToChineseNumber(tostring(_itemLevel))
        if profession then
            soundText = soundText .. "，适合职业：" .. profession
        end
    else
        local socketCounts = 0 --插槽数量
        local statList = {}
        local stats = GetItemStats(itemLink)
        for key, value in pairs(stats) do
            if ZL.itemStats[key] then
                table.insert(statList, ZL.itemStats[key])
            elseif ZL.socketStats[key] then --插槽
                socketCounts = socketCounts + value
            end
        end
        if bindType == 2 then
            soundText = soundText .. "装绑"
        end
        if setID then
            soundText = soundText .. "套装"
        end

        if itemType == "护甲" then
            if itemSubType == "盾牌" or itemSubType == "圣契" or itemSubType == "神像" or itemSubType == "图腾" or itemSubType == "魔印" then
                soundText = soundText .. itemSubType .. "：" .. itemName .. "，装等：" .. ZL.convertToChineseNumber(tostring(itemLevel))
            elseif itemSubType == "布甲" or itemSubType == "皮甲" or itemSubType == "锁甲" or itemSubType == "板甲" then
                if itemEquipLoc == "INVTYPE_CLOAK" then --披风
                    soundText = soundText .. ZL.itemEquipLoc[itemEquipLoc] .. "：" .. itemName .. "，装等：" .. ZL.convertToChineseNumber(tostring(itemLevel))
                else
                    soundText = soundText .. itemSubType .. ZL.itemEquipLoc[itemEquipLoc] .. "：" .. itemName .. "，装等：" .. ZL.convertToChineseNumber(tostring(itemLevel))
                end
            else
                soundText = soundText .. ZL.itemEquipLoc[itemEquipLoc] .. "：" .. itemName .. "，装等：" .. ZL.convertToChineseNumber(tostring(itemLevel))
            end
        elseif itemType == "武器" then
            if itemSubType == "双手斧" or itemSubType == "双手剑" or itemSubType == "双手锤" or itemSubType == "投掷武器" or itemSubType == "弓" or itemSubType == "枪"
            or itemSubType == "弩" or itemSubType == "长柄武器" or itemSubType == "法杖" or itemSubType == "魔杖" or itemSubType == "鱼竿" then
                soundText = soundText .. itemSubType .. "：" .. itemName .. "，装等：" .. ZL.convertToChineseNumber(tostring(itemLevel))
            elseif itemSubType == "单手斧" or itemSubType == "单手剑" or itemSubType == "单手锤" or itemSubType == "拳套" or itemSubType == "匕首" then
                itemSubType = itemSubType:gsub("单手", "")
                soundText = soundText .. ZL.itemEquipLoc[itemEquipLoc] .. itemSubType .. "：" .. itemName .. "，装等：" .. ZL.convertToChineseNumber(tostring(itemLevel))
            else
                soundText = soundText .. "：" .. itemName
            end
        elseif itemType == "容器" or itemType == "箭袋" then
            soundText = soundText .. itemSubType .. "：" .. itemName
        elseif itemType == "配方" then
            if itemSubType == "附魔" then
                soundText = soundText .. itemName
            else
                soundText = soundText .. itemSubType .. itemName
            end
        else
            soundText = soundText .. "：" .. itemName
        end

        if profession then
            soundText = soundText .. "，适合职业：" .. profession
        end
        if socketCounts > 0 then
            soundText = soundText .. "，插槽：" .. socketCounts .. "个"
        end
        if #statList > 0 then
            soundText = soundText .. "，属性：" .. table.concat(statList)
        end
    end
    return soundText
end

--物品是否可以使用
function ZL.ItemCanUse(itemInfo)
    if itemInfo == "[打包拍卖]" then return true end
    local _, itemLink, _, _, _, _, itemSubType = cGetItemInfo(itemInfo)
    local profession
    local professionCanuse = true --职业是否满足要求
    local itemSubTypeCanuse = true --物品分类是否可以使用
    local className = UnitClass("player")
    --获取职业限制信息
    if (not ZL.itemToolTip) then
        ZL.itemToolTip = CreateFrame("GameTooltip", "ZLitemToolTip", nil, "GameTooltipTemplate")
    end
    ZL.itemToolTip:SetOwner(UIParent, "ANCHOR_NONE")
    ZL.itemToolTip:ClearLines()
    ZL.itemToolTip:SetHyperlink(itemLink)
    for i = 1, ZL.itemToolTip:NumLines() do
        -- 遍历每一行并打印内容
        local leftLine = _G["ZLitemToolTipTextLeft"..i]
        if leftLine and leftLine:GetText() then
            local text = leftLine:GetText()
            profession = string.match(text, "职业：(.+)")
            if profession then
                -- print("职业：", profession)
                if (not string.match(profession, className)) then
                    professionCanuse = false
                    -- print("职业：不满足要求")
                end
            end
        end
        local rightLine = _G["ZLitemToolTipTextRight"..i]
        if rightLine and rightLine:GetText() then
            local text = rightLine:GetText()
            local profession1 = string.match(text, itemSubType)
            if profession1 then
                local r, g, b = rightLine:GetTextColor()
                -- print(text, r, g, b)
                if not (r == 1 and g == 1 and b == 1) then
                    -- print(text, "无法装备")
                    itemSubTypeCanuse = false
                else
                    -- print("可以装备")
                    itemSubTypeCanuse = true
                end
            end
        end
    end
    return professionCanuse and itemSubTypeCanuse
end

--通过当前专精判断物品是否可以使用
--true：当前专精可用, false:其它专精可用，nil：不可使用
function ZL.ItemCanUseBySpec(itemId, bindType, expansionID)
    if bindType == 1 then
        if not expansionID then
            expansionID = select(15, cGetItemInfo(itemId))
        end
        if expansionID then
            if expansionID == GetExpansionLevel() then
                local ItemSpecInfo = ZL.instanceInfo.ItemSpecInfo
                if not ItemSpecInfo[itemId] then return nil end
                local curSpecId = GetSpecializationInfo(GetSpecialization())
                if ItemSpecInfo[itemId][curSpecId] then
                    return true
                elseif next(ItemSpecInfo[itemId]) then
                    return false
                else
                    return nil
                end
            else
                return true
            end
        else
            return true
        end
    end
    return true
end
-- 判断所有专精是否有合适的专精能使用物品
--不能使用：|cffff0000 红色
--当前专精能使用:|cff00ff00 绿色
--其它专精能使用：|cff0000ff 蓝色
function ZL.ItemCanUseByAllSpec(itemId, bindType, expansionID)
    if bindType == 2 then
        return "|cffffff00"
    end
    if bindType == 1 then
        if not expansionID then
            expansionID = select(15, cGetItemInfo(itemId))
        end
        if expansionID then
            if expansionID == GetExpansionLevel() then
                if not ZL.instanceInfo then return "|cffffffff" end
                local ItemSpecInfo = ZL.instanceInfo.ItemSpecInfo
                if not ItemSpecInfo[itemId] then return "|cffff0000" end
                local curSpecId = GetSpecializationInfo(GetSpecialization())
                if ItemSpecInfo[itemId][curSpecId] then
                    return "|cff00ff00"
                elseif next(ItemSpecInfo[itemId]) then
                    return "|cff0000ff"
                else
                    return "|cffff0000"
                end
            else
                return "|cffffffff"
            end
        else
            return "|cffffffff"
        end
    end
    return "|cff00ff00"
end

--设置物品子拍卖窗口是显示还是隐藏
function ZL.ItemAuctionFrameIsShown(data)
    --打包拍卖物品都不显示
    local selectCharKey = ZL.GetClassColorName() .. " - " .. GetRealmName()
    local tabId = ZL.opt.ZLAuctionFrameTabId
    if (not data.isPackage) then
        if tabId == 0 then --全部
            return true
        elseif tabId == 1 then --拍卖中
            if (not data.lgnore) and (data.state == "auctioning") then
                if ZL.opt.hideWaitingAuctionCantUseItem then
                    if ZL.ItemCanUseBySpec(data.itemId, data.bindType) then
                        return true
                    else
                        return false
                    end
                else
                    return true
                end
            else
                return false
            end
        elseif tabId == 2 then --成功
            if (not data.lgnore) and (data.state == "success") then
                return true
            else
                return false
            end
        elseif tabId == 3 then --流拍
            if (not data.lgnore) and (data.state == "failed") then
                return true
            else
                return false
            end
        elseif tabId == 4 then --忽略
            if data.lgnore then
                return true
            else
                return false
            end
        elseif tabId == 5 then --待拍卖
            if (not data.lgnore) and (data.state == "waiting") then
                return true
            else
                return false
            end
        elseif tabId == 6 then --关注物品
            local itemId = data.itemId
            if ZL.opt.concernList and ZL.opt.concernList[selectCharKey]
            and ZL.opt.concernList[selectCharKey]["itemList"][itemId] then
                return true
            else
                return false
            end
        elseif tabId == 7 then --待交易
            if ZL.PlayerIsML() then
                for _, incomeData in ipairs(ZL_CURRENT.IncomeList) do
                    if data.tradeId and incomeData.tradeId == data.tradeId then
                        for _, data2 in pairs(incomeData.itemList) do
                            if not data2.isTraded then
                                return true
                            end
                        end
                    end
                end
                return false
            else
                return false
            end
        end
    else
        return false
    end
end

--获取正在拍卖的物品个数，如果有多个，则返回个数和最后1个拍卖物品的index，暂停拍卖的也不属于拍卖中
function ZL.GetAuctioningCount()
    local num = 0
    local index = nil
    if ZL_CURRENT.auctionlist and #ZL_CURRENT.auctionlist then
        for i, data in ipairs(ZL_CURRENT.auctionlist) do
            if data.state == "auctioning" and (not data.isPaused) then
                num = num + 1
                index = i
            end
        end
    end
    return num, index
end
-- 定义一个函数来判断一串数字是否由相同的数字组成
function ZL.isAllSameDigits(numberString)
    -- 获取字符串的第一个字符
    local firstChar = numberString:sub(1, 1)
    -- 使用模式匹配来检查字符串是否只包含这个字符
    local pattern = "^" .. firstChar .. "+$"
    return numberString:match(pattern) ~= nil
end

--将出价者列表按照出价金额从大到小排序，相同出价的按照出价先后排序
function ZL.tableSort(tab)
    if #tab > 1 then
        table.sort(tab, function (a, b)
            if a.bidamount > b.bidamount then
                return true
            elseif a.bidamount == b.bidamount then
                if a.time and b.time and a.time < b.time then
                    return true
                end
            end
            return false
        end)
    end
end
--当前拍卖清单排序
function ZL.AuctionListSort()
   if ZL_CURRENT.auctionlist and  #ZL_CURRENT.auctionlist > 1 then
        table.sort(ZL_CURRENT.auctionlist, function (a, b)
            if ZL.opt.timeSort then
                if ZL.opt.timeSort == "up" then
                    if (a.createTime or 0) < (b.createTime or 0) then
                        return true
                    elseif (a.createTime or 0) == (b.createTime or 0) then
                        --如果创建时间相同按装等降序排序
                        if (a.itemLevel or 0) > (b.itemLevel or 0) then
                            return true
                        elseif (a.itemLevel or 0) == (b.itemLevel or 0) then
                            --如果装等一样，按照物品ID升序排序
                            if (a.itemId or 0) < (b.itemId or 0) then
                                return true
                            end
                        end
                    end
                else
                    if (a.createTime or 0) > (b.createTime or 0) then
                        return true
                    elseif (a.createTime or 0) == (b.createTime or 0) then
                        --如果创建时间相同按装等降序排序
                        if (a.itemLevel or 0) > (b.itemLevel or 0) then
                            return true
                        elseif (a.itemLevel or 0) == (b.itemLevel or 0) then
                            --如果装等一样，按照物品ID升序排序
                            if (a.itemId or 0) < (b.itemId or 0) then
                                return true
                            end
                        end
                    end
                end
            else
                if ZL.opt.levelSort == "up" then
                    if (a.itemLevel or 0) < (b.itemLevel or 0) then
                        return true
                    elseif (a.itemLevel or 0) == (b.itemLevel or 0) then
                        --如果装等相同，按照创建时间升序排列
                        if (a.createTime or 0) < (b.createTime or 0) then
                            return true
                        elseif (a.createTime or 0) == (b.createTime or 0) then
                            --如果创建时间一样，按照物品ID升序排序
                            if (a.itemId or 0) < (b.itemId or 0) then
                                return true
                            end
                        end
                    end
                else
                    if (a.itemLevel or 0) > (b.itemLevel or 0) then
                        return true
                    elseif (a.itemLevel or 0) == (b.itemLevel or 0) then
                        --如果装等相同，按照创建时间升序排列
                        if (a.createTime or 0) < (b.createTime or 0) then
                            return true
                        elseif (a.createTime or 0) == (b.createTime or 0) then
                            --如果创建时间一样，按照物品ID升序排序
                            if (a.itemId or 0) < (b.itemId or 0) then
                                return true
                            end
                        end
                    end
                end
            end
            return false
        end)
   end
   ZL.AuctionFrame2:Update()
end
--是否过滤物品
function ZL.isFilterItem(itemId)
    local filterItemId = ZL.opt.ZL_SETTING["filterItemId"]
    for _, data in ipairs(filterItemId) do
        if data.itemId == itemId then
            return data.itemlink, data.auction, data.loot
        end
    end
    return nil, nil, nil
end
--是否是包装备的物品,需改成按itemLink来判断
function ZL.isbuyItems(numLoot, itemId)
    if ZL_CURRENT.buyerItemList and #ZL_CURRENT.buyerItemList > 0 then
        for _, data in ipairs(ZL_CURRENT.buyerItemList) do
            local isBreak
            if data.itemId == itemId and data.hasLootCounts < data.itemCounts then
                local buyerName = ZL.pruneCrossRealm(data.buyerName)
                local candidateIndex = 1
                local candidateName = GetMasterLootCandidate(numLoot, candidateIndex)
                while candidateName do
                    if candidateName == buyerName then
                        return true
                    end
                    candidateIndex = candidateIndex + 1
                    candidateName = GetMasterLootCandidate(numLoot, candidateIndex)
                end
            end
            if isBreak then break end
        end
    end
    return nil
end
--字符串固定长度，如不够，自动在前面填充
function ZL.pad_left(str, length)
    return string.format("%" .. length .. "s", str)
  end

--自动出价
function ZL.autoBid(index, maxAutoBid, bidCount)
    local curAuctionList = ZL_CURRENT.auctionlist[index]
    if maxAutoBid and (not curAuctionList.isPaused) then
        local bidderlist = ZL_CURRENT.auctionlist[index].bidderlist
        local totalBidCount = 0
        local isSelf = false
        for _, bidData in ipairs(bidderlist) do
            if totalBidCount < curAuctionList.itemCount then
                local count = bidData["bidCount"] or 1
                local newTotalBidCount = totalBidCount + count
                if newTotalBidCount > curAuctionList.itemCount then
                    count = curAuctionList.itemCount - totalBidCount
                end
                totalBidCount = newTotalBidCount
                if ZL.ParseClassColorName(bidData["bidder"]) == ZL.GetFullName() then
                    if bidData.bidCount >= bidCount then
                        isSelf = true
                    end
                    break
                end
            else
                break
            end
        end
        if (not isSelf) then
            local _, bidIncrement, newBid, _bidCount, successList = ZL.GetNewBidAmount(index)
            local msgStr = ""
            if bidCount > _bidCount and #successList > 0 then
                for i = #successList, 1, -1 do
                    if successList[i][2] >= bidCount then
                        newBid = successList[i][1] + bidIncrement
                        break
                    end
                end
            end
            if newBid <= maxAutoBid then
                if bidCount == 1 then
                    msgStr = tostring(newBid)
                else
                    msgStr = tostring(newBid) .. "x" .. bidCount
                end
                if ZL_CURRENT.globalConfig.auctionMode == "团队" then
                    if not ZL_CURRENT.globalConfig.allowMultipleAuctions then
                        SendChatMessage(msgStr, "RAID")
                    else
                        SendChatMessage(curAuctionList.itemlink .. msgStr, "RAID")
                    end
                else
                    MyAddon:TransmitAddonInfo2("AUTOAUC BID", curAuctionList.itemlink .. msgStr)
                end
            else
                local f = ZL.AuctionFrame2.entries[index]
                f.bidFrame.bidBtn:Click()
            end
        end
    end
end

function ZL.globalConfigData()
    return {
        auctionTimerRefresh = ZL.opt.auctionTimerRefresh,
        auctionTimer = ZL.opt.auctionTimer,
        allowMultipleAuctions = ZL.opt.allowMultipleAuctions, --多拍模式：需要单独同步，属于全团共享变量
        bidIncrement = ZL.opt.increment, --默认加价幅度
        intervalBidIncrement = ZL.opt.intervalBidIncrement, --是否区间加价幅度：需要单独同步，属于全团共享变量
        baseAmount1 = ZL.opt.baseAmount1, --区间目标价1：需要单独同步，属于全团共享变量
        baseAmount2 = ZL.opt.baseAmount2, --区间目标价2：需要单独同步，属于全团共享变量
        baseAmount3 = ZL.opt.baseAmount3, --区间目标价3：需要单独同步，属于全团共享变量
        bidIncrement1 = ZL.opt.bidIncrement1, --区间加价幅度1：需要单独同步，属于全团共享变量
        bidIncrement2 = ZL.opt.bidIncrement2, --区间加价幅度2：需要单独同步，属于全团共享变量
        bidIncrement3 = ZL.opt.bidIncrement3, --区间加价幅度3：需要单独同步，属于全团共享变量
        wagesGroupMembers = ZL.opt.wagesGroupMembers, --计算工资成员
        RLBuTieType = ZL.opt.RLBuTieType,
        raidLeaderTiCheng = ZL.opt.raidLeaderTiCheng,
        raidLeaderbutie = ZL.opt.raidLeaderbutie,
        Tbutie = ZL.opt.Tbutie,
        Nbutie = ZL.opt.Nbutie,
        DPSbutie = ZL.opt.DPSbutie,
        FOODbutie = ZL.opt.FOODbutie,
        xiuXingbutie = ZL.opt.xiuXingbutie,
        ANMUbutie = ZL.opt.ANMUbutie,
        YYSound = ZL.opt.YYSound,
        auctionMode = ZL.opt.auctionMode,
        auctionGUID = (ZL_CURRENT.globalConfig and ZL_CURRENT.globalConfig.auctionGUID) and ZL_CURRENT.globalConfig.auctionGUID or ZL_CURRENT.auctionGUID
    }
end
--同步配置文件全局参数
function ZL.TransmitAddonInfo_Pro()
    if IsInRaid(1) and ZL.PlayerIsML() then
        MyAddon:TransmitAddonInfo("AUTOAUC PRO", ZL.globalConfigData())
    end
end
--提示消息1
function ZL.GameTooltipShow(self, point, relativePoint, offsetX, offsetY)
    offsetX = offsetX or 0
    offsetY = offsetY or 0
    GameTooltip:ClearAllPoints()
    GameTooltip:ClearLines()
    GameTooltip:SetOwner(self, "ANCHOR_NONE")
    GameTooltip:SetPoint(point, self, relativePoint, offsetX, offsetY)
end
--提示消息2
function ZL.GameTooltipShowAnchor(self, anchor, x, y)
    x = x or 0
    y = y or 0
    anchor = anchor or "ANCHOR_BOTTOMRIGHT"
    GameTooltip:ClearAllPoints()
    GameTooltip:ClearLines()
    GameTooltip:SetOwner(self, anchor, x, y)
end
--将秒转换成时间格式
function ZL.ConvertSecondsToTime(seconds)
    local hours = math.floor(seconds / 3600)
    local minutes = math.floor((seconds % 3600) / 60)
    local remainingSeconds = seconds % 60

    if hours > 0 then
        return string.format("%02d:%02d:%02d", hours, minutes, remainingSeconds)
    elseif hours == 0 and minutes > 0 then
        return string.format("%02d:%02d", minutes, remainingSeconds)
    else
        return string.format("%d", remainingSeconds)
    end
end
--更新时间
function ZL.ConvertSecondsToUpdateUnits(stampTime)
    if stampTime then
        local timeinfo = ConvertSecondsToUnits(time()-stampTime)
        if timeinfo.days > 0 then
            return timeinfo.days .. "天前"
        elseif timeinfo.hours > 0 then
            return timeinfo.hours .. "小时前"
        elseif timeinfo.minutes > 0 then
            return timeinfo.minutes .. "分钟前"
        else
            return "1分钟内"
        end
    else
        return ""
    end
end
--获取装备交易剩余时间
function ZL.GetRemainingTradeTime(IsShow)
    if not ZL.PlayerIsML() then return end
    local RemainingTradeItems = {}
    local itemLocation
    local itemGuid, itemLink
    for bag = 0, NUM_BAG_SLOTS do
        for slot = 1, C_Container.GetContainerNumSlots(bag) do
            if not itemLocation then
                itemLocation = ItemLocation:CreateFromBagAndSlot(bag, slot)
            else
                itemLocation:SetBagAndSlot(bag, slot)
            end
            if C_Item.DoesItemExist(itemLocation) then
                itemLink = C_Container.GetContainerItemLink(bag, slot)
                itemGuid = C_Item.GetItemGUID(itemLocation)
                if ZL_CURRENT.itemGUIDUsed and ZL_CURRENT.itemGUIDUsed[itemGuid] and ((not ZL_CURRENT.SelfAuction) or (not ZL_CURRENT.SelfAuction[itemGuid])) then
                    if (not ZL.ToolTip) then
                        ZL.ToolTip = CreateFrame("GameTooltip", "TradeTimeRemainingTooltip", nil, "GameTooltipTemplate")
                    end
                    ZL.ToolTip:SetOwner(UIParent, "ANCHOR_NONE")
                    ZL.ToolTip:ClearLines()
                    ZL.ToolTip:SetBagItem(bag, slot)
                    for i = 1, ZL.ToolTip:NumLines() do
                        local text = _G["TradeTimeRemainingTooltipTextLeft"..i]:GetText()
                        if text then
                            local timeRemaining = text:match(BIND_TRADE_TIME_REMAINING:gsub("%%s", "(.+)"))
                            if timeRemaining then
                                local hour = tonumber(timeRemaining:match("(%d+)" .. "小时")) or 0
                                local min = tonumber(timeRemaining:match("(%d+)" .. "分钟")) or 0
                                table.insert(RemainingTradeItems, {
                                    itemLink=itemLink, timeRemaining=timeRemaining, hour=hour, min=min
                                })
                                break
                            end
                        end
                    end
                end
            end
        end
    end
    if itemLocation then
        itemLocation:Clear()
    end
    itemGuid = nil
    itemLink = nil
    local text = ""
    if #RemainingTradeItems > 0 then
        table.sort(RemainingTradeItems, function (a, b)
            return (a.hour*60 + a.min) < (b.hour*60 + b.min)
        end)
        text = "|cffffd100交易剩余时间清单(前5)：|r\n"
    else
        text = "|cffffd100没有交易剩余时间的装备！|r\n"
    end
    
    local _IsVoiceReminder = false
    for _, data in ipairs(RemainingTradeItems) do
        local remainingTime = (data.hour*60 + data.min)
        if remainingTime <= ZL.opt.TradeRemainingTimer then _IsVoiceReminder = true end
        if remainingTime <= 30 then
            text = text .. data.itemLink .. ":|cffff0000" .. data.timeRemaining .. "|r\n"
        else
            text = text .. data.itemLink .. ":" .. data.timeRemaining .. "\n"
        end
    end
    ZL.ZLRemainingTradeTimeFrame.RemainingTradeTimeText:SetText(text)
    if ZL.opt.IsTradeRemainingVoiceReminder and _IsVoiceReminder and IsInInstance() and (select(2, IsInInstance()) == "raid") and
        ((not ZL.TradeRemainingReminderTime) or ((GetTime() - ZL.TradeRemainingReminderTime) >= (ZL.opt.TradeRemainingReminderPinlv * 60)))
        then
        ZL.TradeRemainingReminderTime = GetTime()
        C_VoiceChat.StopSpeakingText()
        PlaySoundFile("Interface\\AddOns\\" .. addonName .. "\\sound\\" .. ZL.SoundType .. "\\youzhuangbeikuaiyaoguoqileo.mp3", "Master")
    end
    if IsShow then
        return RemainingTradeItems
    else
        RemainingTradeItems = nil
    end
end

--获取职业颜色名字
function ZL.GetClassColorName(name, classFilename)
    name = name or UnitName("player")
    if name:match("|c%x%x%x%x%x%x%x%x.-%|r") ~= nil then return name end --如有已经是带职业颜色名字则直接返回
    local oldName = name
    name = ZL.pruneCrossRealm(name)
    classFilename = classFilename or UnitClassBase(name)
    if classFilename then
        local color = select(4, GetClassColor(classFilename))
        if color then
            return "|c" .. color .. oldName .. "|r"
        else
            return oldName
        end
    else
        return oldName
    end
end

--解析带职业颜色的名字
function ZL.ParseClassColorName(name)
    name = name or UnitName("player")
    name = tostring(name)
    local cleanText = name and (name:gsub("|c........", ""):gsub("|r", "")) --把颜色代码剔除掉
    return cleanText
end

--获取团队成员名
function ZL.GetCurrentRoster(IsSaveUnitGuid)
    local roster = {{},{},{},{},{},{},{},{}} --初始化8个小队
    for i = 1, MAX_RAID_MEMBERS do
        local name, _, subgroup, _, _, classFilename = GetRaidRosterInfo(i)
        local oldName = name
        if name then
            name = ZL.GetFullName(name)
            if classFilename then
                local color = select(4, GetClassColor(classFilename))
                name = "|c" .. color .. name .. "|r"
            end
            table.insert(roster[subgroup], name)
            if IsSaveUnitGuid then
                if not ZL_CURRENT.UnitGUID then ZL_CURRENT.UnitGUID = {} end
                ZL_CURRENT.UnitGUID[name] = UnitGUID(oldName)
            end
        end
    end
    return roster
end

--识别出价
function ZL.padZeros(num, tarbidamount, bidIncrement, baseamount)
    local numStr = tostring(num)
    local currentLength = #numStr-- 获取字符串长度
    local baselength = #tostring(baseamount)
    -- 如果当前长度已经大于或等于基础出价的长度，则直接返回原数字字符串
    -- 不能与目标价长度做对比，如：baseamount=9500，tarbidamount=10000，如有人出价9，则为识别为90000
    if currentLength >= baselength then
        return num
    end
    -- 计算需要添加的零的数量
    local zerosToAdd = baselength - currentLength
    -- 创建一个包含需要数量零的字符串
    local zeros = string.rep("0", zerosToAdd)
    -- 将零添加到数字字符串的后面
    local paddedNumStr = numStr .. zeros
    --添0后大于或等于基础出价时，直接返回
    if tonumber(paddedNumStr) >= baseamount then
        return tonumber(paddedNumStr)
    end
    --计算原始出价从右往左数有几个连续的0，如果大于0个，则继续在第一次添加0后的数字加一个0
    local zeroCount = 0
    for i = currentLength, 1, -1 do  -- 从右往左遍历字符串
        if numStr:sub(i, i) == "0" then
            zeroCount = zeroCount + 1
        else
            break  -- 一旦遇到非零字符，就停止
        end
    end
    if zeroCount == 1 then
        paddedNumStr = paddedNumStr .. "0"
    elseif zeroCount == 0 then
        local firstChar = string.sub(numStr, 1, 1)
        if firstChar == "1" then
            if ((tarbidamount == baseamount) and (baseamount <= 10000 or (baseamount > 50000 and baseamount < 100000))) or
            ((tarbidamount > baseamount) and ((baseamount > 500 and baseamount < 1000) or (baseamount > 5000 and baseamount < 10000) or (baseamount > 50000 and baseamount < 100000))) then
                paddedNumStr = paddedNumStr .. "0"
            end
        elseif firstChar == "2" then
            if ((tarbidamount == baseamount) and ((baseamount <= 1000) or (baseamount > 5000 and baseamount < 10000))) or
            ((tarbidamount > baseamount) and ((baseamount > 500 and baseamount < 1000) or (baseamount > 5000 and baseamount < 10000))) then
                paddedNumStr = paddedNumStr .. "0"
            end
        end
    end
    return tonumber(paddedNumStr)
end
-- 自定义位与操作
function ZL.bit_and(a, b)
    local result = 0
    local bit = 1
    while a > 0 or b > 0 do
        if (a % 2 == 1) and (b % 2 == 1) then
            result = result + bit
        end
        a = math.floor(a / 2)
        b = math.floor(b / 2)
        bit = bit * 2
    end
    return result
end
-- 自定义位左移操作
function ZL.bit_lshift(num, shift)
    return num * (2 ^ shift)
end
-- 自定义位或操作
function ZL.bit_or(a, b)
    return a + b - ZL.bit_and(a, b)
end
function ZL.utf8_to_num(raw_string)
    local result = {}
    local pos = 1
    while pos <= #raw_string do
        local count_1_of_byte = ZL.get_continuous_1_count_of_byte(string.byte(raw_string, pos))
        local num = 0
        if count_1_of_byte < 1 then 
            num = string.byte(raw_string, pos)
            count_1_of_byte = 1
        else
            local boundary = 8
            local i = count_1_of_byte + 1
            while i < boundary * count_1_of_byte do
                if 0 == i % boundary then
                    i = i + 2
                end
                if ZL.bit_and(ZL.bit_lshift(1, boundary - i % boundary - 1), string.byte(raw_string, pos + math.floor(i / boundary))) ~= 0 then
                    num = ZL.bit_or(ZL.bit_lshift(num, 1), 1)
                else
                    num = ZL.bit_lshift(num, 1)
                end
                i = i + 1
            end
        end
        pos = pos + count_1_of_byte
        table.insert(result, num)
    end

    return result
end
--获取一个字节中，从最高位开始连续的1的个数
function ZL.get_continuous_1_count_of_byte(num)
    if nil == num then
        return -1
    end
    local count = 0
    while ZL.bit_and(num, 0x80) ~= 0 do
        count = count + 1
        num = ZL.bit_lshift(num, 1)
    end
    return count
end
--将全角转换成半角
function ZL.fullwidthToHalfwidth(raw_string)
    local new_string = {}
    local pos = 1
    while pos <= #raw_string do
        local count_1_of_byte = ZL.get_continuous_1_count_of_byte(string.byte(raw_string, pos))
        if 3 == count_1_of_byte then
            local char = string.sub(raw_string, pos, pos + 2)
            local num_of_char = ZL.utf8_to_num(char)[1]
            if num_of_char == 12288 then --全角空格
                num_of_char = 32
                table.insert(new_string, string.char(num_of_char))
            elseif num_of_char >= 65296 and num_of_char <= 65305 then --全角数字进行转换为半角
                num_of_char = num_of_char - 65248
                table.insert(new_string, string.char(num_of_char))
            else --汉字默认为全角
                table.insert(new_string, char)
            end
            pos = pos + count_1_of_byte
        else
            table.insert(new_string, string.sub(raw_string, pos, pos))
            pos = pos + 1
        end
    end
    return table.concat(new_string)
end
--处理竞价消息
function ZL.msg_gsub(msg)
    local cmsg = msg:gsub("%[T%]", "")
    local colorPart, txtPart = cmsg:match("^(|c.-|r)(.*)$")
    if not colorPart then
        colorPart = ""
        txtPart = cmsg:match("^(.*)$")
    end
    cmsg = txtPart or ""
    cmsg = cmsg:gsub("[!！Pp%s]", "")
    cmsg = cmsg:gsub("。", ".")
    cmsg = cmsg:gsub("万", "w")
    cmsg = cmsg:gsub("千", "k")
    cmsg = cmsg:gsub("一", "1")
    cmsg = cmsg:gsub("二", "2")
    cmsg = cmsg:gsub("三", "3")
    cmsg = cmsg:gsub("四", "4")
    cmsg = cmsg:gsub("五", "5")
    cmsg = cmsg:gsub("六", "6")
    cmsg = cmsg:gsub("七", "7")
    cmsg = cmsg:gsub("八", "8")
    cmsg = cmsg:gsub("九", "9")
    cmsg = cmsg:gsub("两", "2")
    cmsg = cmsg:gsub("伍", "5")
    cmsg = colorPart .. cmsg
    return cmsg
end

--获取玩家购买清单
function ZL.GetPlayerBuyList(bill)
    local buyList = {}
    bill = bill or ZL_CURRENT
    if bill then
        local IncomeList = bill.IncomeList
        if IncomeList and #IncomeList > 0 then
            for _, data in ipairs(IncomeList) do
                if data.player ~= "" then
                    local name = data.player
                    buyList[name] = buyList[name] or {["items"] = {},["totalAmount"] = 0}
                    buyList[name].totalAmount = buyList[name].totalAmount + data.amount
                    if data.itemList and next(data.itemList, nil) then
                        for _itemlink, _data in pairs(data.itemList) do
                            table.insert(buyList[name]["items"], {
                                notes=_itemlink, isTraded=_data.isTraded, itemCount=_data.itemCount,
                                stackCount=_data.stackCount, itemGUID=_data.itemGUID,
                            })
                        end
                    end
                end
            end
        end
    end
    return buyList
end
--创建拍卖信息
function ZL.CreateAuctionInfo()
    local MLname = ZL.GetMLname()
    local name, _, difficultyID, difficultyName, maxPlayers, _, _, instanceID = GetInstanceInfo()
    difficultyName = difficultyName:gsub("人", ""):gsub("（", ""):gsub("）", "")
    ZL_CURRENT.name = difficultyName ~= "" and name .. "(" .. difficultyName .. ")" or name
    ZL_CURRENT.instanceID = instanceID
    ZL_CURRENT.maxPlayers = maxPlayers
    ZL_CURRENT.auctiondate =  date("%Y-%m-%d %H:%M:%S", GetServerTime())
    ZL_CURRENT.RealmName = GetRealmName()
    ZL_CURRENT.totalincome = 0
    ZL_CURRENT.IncomeList = {}
    ZL_CURRENT.auctionGUID = UnitGUID("player") .. ":" .. GetServerTime()
    if difficultyID ~= 0 then
        for i = 1, GetNumSavedInstances() do
            local _, lockoutId, _, _difficultyID, locked, _, _, _, _, _, _, _, _, _instanceID = GetSavedInstanceInfo(i)
            if locked and (instanceID == _instanceID) and (difficultyID == _difficultyID) then
                ZL_CURRENT.lockoutId = lockoutId
                break
            end
        end
    end
    if MLname then
        ZL_CURRENT.UnitGuid = UnitGUID(MLname)
        ZL_CURRENT.FactionGroup = select(2, UnitFactionGroup(MLname))
        ZL_CURRENT.MLname = MLname
    end
end

--获取掉落物品候选人
function ZL.GetMasterLootCandidates(slot)
    local candidates = {}
    for index = 1, MAX_RAID_MEMBERS do
        local candidate = GetMasterLootCandidate(slot, index)
        if candidate then
            candidates[ZL.GetClassColorName(ZL.GetFullName(candidate))] = true
        end
    end
    return candidates
end

--判断玩家是否拥有装备交易权限(装备候选人)
function ZL.IsCandidate(v, name)
    local bindType = ZL_CURRENT.auctionlist[v].bindType
    if bindType ~= 1 then return true end --只要不是拾取绑定的，都可以参与拍卖
    for _, value in pairs(ZL_CURRENT.auctionlist[v]["spawnUID"]) do
        if not value["candidates"] then
            return true
        else
            if not next(value["candidates"], nil) then
                return true
            else
                name = name or ZL.GetClassColorName(ZL.GetFullName())
                if value["candidates"][name] == true then
                    return true
                end
            end
        end
    end
    return false
end
--加载物品信息获取itemlink
function ZL.LoadItemDataByID(itemId, func, relativeFrame)
    local itemExists = C_Item.DoesItemExistByID(itemId)
    if itemExists then
        local itemlink = select(2, cGetItemInfo(itemId))
        if (not itemlink) then
            ZL:RegisterEvent("ITEM_DATA_LOAD_RESULT")
            C_Item.RequestLoadItemDataByID(itemId)
            ZL:SetScript("OnEvent", function(self, event, ...)
                if event == "ITEM_DATA_LOAD_RESULT" then
                    local loadedItemId, success = ...
                    if loadedItemId == itemId then
                        if success then
                            itemlink = select(2, cGetItemInfo(itemId))
                            if func then
                                func(itemlink)
                            end
                        else
                            local msgStr = "物品ID：" .. itemId .. "信息加载失败，请重试！"
                            ZL.Print(msgStr, true)
                            if relativeFrame then
                                ZL.GameTooltipShow(relativeFrame, "BOTTOM", "TOP")
                                GameTooltip:AddLine(msgStr)
                                GameTooltip:Show()
                                C_Timer.After(5, function ()
                                    GameTooltip:Hide()
                                end)
                            end
                        end
                        -- 取消事件注册
                        self:UnregisterEvent("ITEM_DATA_LOAD_RESULT")
                    end
                end
            end)
        else
            func(itemlink)
        end
    else
        local msgStr = "物品ID：" .. itemId .. "不存在，请核实填写是否正确！"
        ZL.Print(msgStr, true)
        if relativeFrame then
            ZL.GameTooltipShow(relativeFrame, "BOTTOM", "TOP")
            GameTooltip:AddLine(msgStr)
            GameTooltip:Show()
            C_Timer.After(3, function ()
                GameTooltip:Hide()
            end)
        end
    end
end

--手动创建拍卖物品
function ZL.ManualCreateAuctionItem(itemLink, itemCount, itemGUID, notSync)
    if not ZL_CURRENT.name then ZL.CreateAuctionInfo() end
    itemCount = itemCount or 1
    if (not ZL_CURRENT.globalConfig) then
        ZL_CURRENT.globalConfig = ZL.globalConfigData()
    end
    local _, _, _, itemLevel, _, _, itemSubType, stackCount, _, _, _, _, _, bindType, expansionID = cGetItemInfo(itemLink)
    local itemindex = 1
    local itemId = tonumber(itemLink:match("|Hitem:(%d+):"))
    if ZL_CURRENT.auctionlist and (#ZL_CURRENT.auctionlist > 0) then
        for _, fdata in ipairs(ZL_CURRENT.auctionlist) do
            if (fdata.itemlink == itemLink) then
                itemindex = itemindex + 1
            end
        end
    end
    local startbidamount, bidIncrement = ZL.GetStartAndIncrementBid(itemId)
    bidIncrement = ZL.GetDiffrentIncrementBid(startbidamount, bidIncrement)
    local spawnUIDkey
    local spawnUID = {}
    if stackCount == 1 then
        for i = 1, itemCount do
            spawnUIDkey = itemId ..GetServerTime() .. string.format("%02d", i)
            if itemGUID and i == 1 then
                spawnUID[spawnUIDkey] = {bossName="其他", itemGUID={[itemGUID]={}}}
            else
                spawnUID[spawnUIDkey] = {bossName="其他", itemGUID={}}
            end
        end
    else
        spawnUIDkey = itemId ..GetServerTime() .. "01"
        if itemGUID then
            spawnUID[spawnUIDkey] = {bossName="其他", itemGUID={[itemGUID]={}}}
        else
            spawnUID[spawnUIDkey] = {bossName="其他", itemGUID={}}
        end
    end
    local fdata = {
        ["type"] = "手动创建",
        ["itemId"] = itemId,
        ["itemlink"] = itemLink,
        ["itemindex"] = itemindex,
        ["itemCount"] = itemCount,
        ["itemLevel"] = itemLevel,
        ["itemSubType"] = itemSubType,
        ["bindType"] = bindType,
        expansionID = expansionID,
        ["startbidamount"] = startbidamount,
        ["bidIncrement"] = bidIncrement,
        ["state"] = "waiting",
        ["endTime"] = 0,
        ["isPaused"] = false,
        ["stackCount"] = stackCount,
        ["spawnUID"] = spawnUID,
        ["bidderlist"] = {},
        ["sourceGUID"] = {},
        ["lgnore"] = false,
        ["createTime"] = date("%Y-%m-%d %H:%M:%S", GetServerTime()),
    }
    --ML自己创建，不参与插件同步创建
    ZL_CURRENT.auctionlist = ZL_CURRENT.auctionlist or {}
    table.insert(ZL_CURRENT.auctionlist, fdata)
    ZL.GetLootItemGUID()
    if not notSync then
        local index2 = #ZL_CURRENT.auctionlist
        --开始同步给其他人
        local fdata2 = {
            ["type"] = "手动创建",
            ["data2"] = ZL_CURRENT.auctionlist[index2],
            ["globalConfigData"] = ZL.globalConfigData(),
        }
        MyAddon:TransmitAddonInfo("AUTOAUC SYNC9", fdata2)
    end
    ZL.AuctionListSort()
end
--信息发送频道
function ZL.MsgChannel()
    if IsInRaid(1) then
        if ZL.opt.announceRaidWarning and (UnitIsGroupLeader("player") or UnitIsRaidOfficer("player")) then
            return "RAID_WARNING"
        else
            return "RAID"
        end
    elseif IsInGroup(1) then
        return "PARTY"
    elseif IsInRaid(2) or IsInGroup(2) then
        return "INSTANCE_CHAT"
    else
        return "SAY"
    end

end

--获取计算工资团队成员名单
function ZL.GetWagesGroupMembers(bill)
    local WagesGroupMembers
    local msg
    local ML, RL
    bill = bill or ZL_CURRENT
    local wagesGroupMembersIndex = (bill["globalConfig"] and bill["globalConfig"]["wagesGroupMembers"]) and bill["globalConfig"]["wagesGroupMembers"] or 0
    if wagesGroupMembersIndex then
        if wagesGroupMembersIndex == 0 then
            if IsInRaid(1) then
                WagesGroupMembers = ZL.GetCurrentRoster()
                msg = "|cffff0000当前成员|r"
                ML = ZL.GetClassColorName(ZL.GetMLname())
                RL = ZL.GetClassColorName(ZL.GetRLname())
            else
                if bill["GroupMembersList"] and #bill["GroupMembersList"] > 0 then
                    WagesGroupMembers = bill["GroupMembersList"][1]["list"]
                    msg = "|cffff0000历史1成员|r"
                    ML = bill["GroupMembersList"][1]["ML"]
                    RL = bill["GroupMembersList"][1]["RL"]
                end
            end
        else
            if bill["GroupMembersList"] and bill["GroupMembersList"][wagesGroupMembersIndex] then
                WagesGroupMembers = bill["GroupMembersList"][wagesGroupMembersIndex]["list"]
                msg = "|cffff0000历史" .. wagesGroupMembersIndex .. "成员|r"
                ML = bill["GroupMembersList"][wagesGroupMembersIndex]["ML"]
                RL = bill["GroupMembersList"][wagesGroupMembersIndex]["RL"]
            elseif IsInRaid(1) then
                WagesGroupMembers = ZL.GetCurrentRoster()
                msg = "|cffff0000当前成员|r"
                ZL.opt.wagesGroupMembers = 0
                ZL.TransmitAddonInfo_Pro()
                ML = ZL.GetClassColorName(ZL.GetMLname())
                RL = ZL.GetClassColorName(ZL.GetRLname())
            end
        end
    end
    return WagesGroupMembers, msg, ML, RL
end

--获取平均工资
function ZL.GetAveWages(bill)
    bill = bill or ZL_CURRENT
    local WagesGroupMembers, _, _, RL = ZL.GetWagesGroupMembers(bill)
    if (not WagesGroupMembers) then bill["aveWages"] = nil return end
    bill.butie = {}
    local profileName = ZL.opt.subsidyProfileList["profileKeys"][ZL.opt.subsidyProfileSelect]
    local subsidyParentData = ZL.opt.subsidyProfileList["profile"][profileName]["parent"]
    local subsidyData = ZL.opt.subsidyProfileList["profile"][profileName]["child"]

    local numGroupMembers = 0 --团队成员数-消费老板数
    local totalBiLi = 0
    local biLi = 0
    local subsidyMoney = subsidyData["RL"]
    local RLBuTieType,raidLeaderTiCheng2
    if ZL.opt.wagesSubsidyType ~= 1 and subsidyParentData["RL补贴"] then
        if subsidyMoney == "团双" then
            RLBuTieType = 3
        elseif type(subsidyMoney) == "string" and subsidyMoney:match("(%d+%%)") then
            RLBuTieType = 4
            raidLeaderTiCheng2 = tonumber(subsidyMoney:match("(%d+)%%"))
        else
            RLBuTieType = 2 --固定补贴
        end
    else
        RLBuTieType = 1 --无补贴
    end
    local BiLiList = {}
    for _, data in ipairs(WagesGroupMembers) do
        if #data > 0 then
            for _, name in ipairs(data) do
                if (not bill.WagesBiLi) or (not bill.WagesBiLi[name]) or (not bill.WagesBiLi[name]["biLi"]) then -- or bill.WagesBiLi[name]["biLi"] >= 100
                    biLi = 100
                elseif bill.WagesBiLi[name]["biLi"] <= 0 then
                    biLi = 0
                else
                    biLi = bill.WagesBiLi[name]["biLi"]
                end
                if name == RL and RLBuTieType == 3 then  --RL双倍工资，需要计算2次
                    biLi = biLi * 2
                end
                if biLi > 0 then
                    numGroupMembers = numGroupMembers + 1
                    totalBiLi = totalBiLi + biLi
                end
                BiLiList[biLi] =BiLiList[biLi] or {}
                tinsert(BiLiList[biLi], name)
            end
        end
    end
    totalBiLi = totalBiLi / 100
    if numGroupMembers <= 0 then bill["aveWages"] = nil return end
    if RLBuTieType == 3 then --如果团双则计算工资人数+1
        numGroupMembers = numGroupMembers + 1
    end
    local totalamount = 0 --净收入
    local totalincome = 0 --总收入
    local totalpayout = 0 --总支出为负值
    local averageamount = 0 --平均工资
    local raidLeaderTiCheng = (RLBuTieType == 4 and raidLeaderTiCheng2 and raidLeaderTiCheng2 > 0) and (raidLeaderTiCheng2/100) or 0 --RL提成点
    local RLBuTie = 0
    if bill.IncomeList and (#bill.IncomeList > 0) then
        for _, data in ipairs(bill.IncomeList) do
            if data.amount > 0 then
                totalincome = totalincome + data.amount
            else
                totalpayout = totalpayout + data.amount
            end
        end
    end
    ZL.getSubsidyParent(totalincome, raidLeaderTiCheng)
    if ZL.opt.wagesSubsidyType == 2 or ZL.opt.wagesSubsidyType == 3 then
        if RLBuTieType == 2  then --RL固定补贴
            if subsidyMoney and type(subsidyMoney) == "number" and subsidyMoney >= 0 then
                RLBuTie = subsidyMoney
            else
                RLBuTie = 0
            end
            totalpayout = totalpayout - RLBuTie
            table.insert(bill.butie, {player="", notes="RL补贴", amount=-RLBuTie, isTraded=true})
        elseif RLBuTieType == 4 and raidLeaderTiCheng2 and raidLeaderTiCheng2 >= 0 then
            --RL提成，按总收入*提成点
            RLBuTie = floor(totalincome*raidLeaderTiCheng)
            totalpayout = totalpayout - RLBuTie
            table.insert(bill.butie, {player="", notes="RL补贴(" .. raidLeaderTiCheng*100 .. "%)", amount=-RLBuTie, isTraded=true})
        end
        if ZL.opt.wagesSubsidyType == 2 then
            --按照父补贴类型计算
            for subsidyParentName, subsidyParentMoney in pairs(subsidyParentData) do
                if subsidyParentName ~= "RL补贴" then
                    totalpayout = totalpayout - subsidyParentMoney
                    table.insert(bill.butie, {player="", notes=subsidyParentName, amount=-subsidyParentMoney, isTraded=true})
                end
            end
        elseif ZL.opt.wagesSubsidyType == 3 then
            --按照子补贴类型计算
            for subsidyParentName, subsidyParentMoney in pairs(bill.subsidyParent) do
                if subsidyParentName ~= "RL补贴" then
                    totalpayout = totalpayout - subsidyParentMoney
                    table.insert(bill.butie, {player="", notes=subsidyParentName, amount=-subsidyParentMoney, isTraded=true})
                end
            end
        end
    end
    totalamount = totalincome + totalpayout
    if bill == ZL_CURRENT and ZL.AuctionRecordFrame.playerBalanceFrame.wagesNumber:GetNumber() > 0 then
        numGroupMembers = ZL.AuctionRecordFrame.playerBalanceFrame.wagesNumber:GetNumber()
        averageamount = floor(totalamount/numGroupMembers)
    else
        averageamount = floor(totalamount/totalBiLi)
    end
    bill["aveWages"] = averageamount
    if RLBuTieType == 3 then
        -- table.insert(bill.butie, 1, {player="", notes="RL补贴(团双)", amount=-averageamount, isTraded=true})
        -- RLBuTie = averageamount
        bill.subsidyParent["RL补贴"] = bill["aveWages"] or 0
    end
    return numGroupMembers, RLBuTie, totalincome, totalpayout, totalamount, averageamount, BiLiList
end

--发送物品链接到聊天窗口
function ZL.ChatEditInsertLink(itemlink)
    local focusEditBox = GetCurrentKeyBoardFocus()
    if focusEditBox then
        focusEditBox:Insert(itemlink)
    elseif _G["ChatFrameEditBox"] and _G["ChatFrameEditBox"]:IsVisible() then
        _G["ChatFrameEditBox"]:Insert(itemlink)
    else
        -- ChatEdit_ActivateChat(ChatEdit_ChooseBoxForSend())
        -- ChatEdit_InsertLink(itemlink)
    end
end
--判断物品是否可以拍卖
function ZL.IsCanAuction(data, senderColorName)
    local info
    if data.spawnUID then
        for _, value in pairs(data.spawnUID) do
            if (not value["candidates"]) or (not next(value["candidates"], nil)) or (not senderColorName) or value["candidates"][senderColorName] then
                if value["itemGUID"] and next(value["itemGUID"], nil) then
                    for itemGuid in pairs(value["itemGUID"]) do
                        local bagID, slotIndex = ZL.FindItemInBag(itemGuid)
                        if bagID and slotIndex then
                            info = C_Container.GetContainerItemInfo(bagID, slotIndex)
                            if info.isBound then
                                --如果是拾取绑定物品，检测是否还有剩余交易时间
                                if (not ZL.ToolTip) then
                                    ZL.ToolTip = CreateFrame("GameTooltip", "TradeTimeRemainingTooltip", nil, "GameTooltipTemplate")
                                end
                                ZL.ToolTip:SetOwner(UIParent, "ANCHOR_NONE")
                                ZL.ToolTip:ClearLines()
                                ZL.ToolTip:SetBagItem(bagID, slotIndex)
                                for i = 1, ZL.ToolTip:NumLines() do
                                    local text = _G["TradeTimeRemainingTooltipTextLeft"..i]:GetText()
                                    if text then
                                        local timeRemaining = text:match(BIND_TRADE_TIME_REMAINING:gsub("%%s", "(.+)"))
                                        if timeRemaining then
                                            return true
                                        end
                                    end
                                end
                            else
                                return true
                            end
                        end
                    end
                else
                    return true
                end
            end
        end
    end
    return false
end
--获取背包格子信息
function ZL.GetBagsInfo()
    local bags = {}
    local currentInfo
    for bagID = 0, NUM_BAG_SLOTS do
        if not bags[bagID] then bags[bagID] = {} end
        for slotIndex = 1, C_Container.GetContainerNumSlots(bagID) do
            -- 获取当前格子的物品信息
            currentInfo = C_Container.GetContainerItemInfo(bagID, slotIndex)
            if currentInfo then
                bags[bagID][slotIndex] = currentInfo
            end
        end
    end
    currentInfo = nil
    return bags
end

--获取背包物品GUID并保存
function ZL.GetBagsItemGUDI()
    local guidList = {}
    local itemLocation, itemGuid
    for bagID = 0, NUM_BAG_SLOTS do
        for slotIndex = 1, C_Container.GetContainerNumSlots(bagID) do
            if not itemLocation then
                itemLocation = ItemLocation:CreateFromBagAndSlot(bagID, slotIndex)
            else
                itemLocation:SetBagAndSlot(bagID, slotIndex)
            end
            if C_Item.DoesItemExist(itemLocation) then
                itemGuid = C_Item.GetItemGUID(itemLocation)
                table.insert(guidList, itemGuid)
            end
        end
    end
    if itemLocation then
        itemLocation:Clear()
    end
    itemGuid = nil
    return guidList
end
--获取新拾取物品的GUID并匹配到拍卖物品中
local function findItemGUID(itemlink, index, needCount)
    local itemHasCount = 0
    local itemLocation, itemGuid
    for bagID = 0, NUM_BAG_SLOTS do
        for slotIndex = 1, C_Container.GetContainerNumSlots(bagID) do
            -- 获取当前格子的物品信息
            local currentInfo = C_Container.GetContainerItemInfo(bagID, slotIndex)
            if currentInfo and currentInfo.hyperlink == itemlink then
                if not itemLocation then
                    itemLocation = ItemLocation:CreateFromBagAndSlot(bagID, slotIndex)
                else
                    itemLocation:SetBagAndSlot(bagID, slotIndex)
                end
                itemGuid = C_Item.GetItemGUID(itemLocation)
                local itemID = currentInfo.itemID
                --这个物品的GUID没有被使用过
                if (not ZL_CURRENT["itemGUIDUsed"]) or (not ZL_CURRENT["itemGUIDUsed"][itemGuid]) then
                    local isTrue = false
                    if currentInfo.isBound then
                        --如果是拾取绑定物品，检测是否还有剩余交易时间
                        if (not ZL.ToolTip) then
                            ZL.ToolTip = CreateFrame("GameTooltip", "TradeTimeRemainingTooltip", nil, "GameTooltipTemplate")
                        end
                        ZL.ToolTip:SetOwner(UIParent, "ANCHOR_NONE")
                        ZL.ToolTip:ClearLines()
                        ZL.ToolTip:SetBagItem(bagID, slotIndex)
                        for i = 1, ZL.ToolTip:NumLines() do
                            local text = _G["TradeTimeRemainingTooltipTextLeft"..i]:GetText()
                            if text then
                                local timeRemaining = text:match(BIND_TRADE_TIME_REMAINING:gsub("%%s", "(.+)"))
                                if timeRemaining then
                                    isTrue = true
                                    break
                                end
                            end
                        end
                    else
                        isTrue = true
                    end
                    if isTrue then
                        local npcID
                        local data =ZL_CURRENT["auctionlist"][index]
                        if data["stackCount"] == 1 then
                            --新增测试内容↓↓↓↓↓↓
                            for _, spawnData in pairs(data.spawnUID) do
                                if spawnData["itemGUID"] and (not next(spawnData["itemGUID"], nil)) then
                                    if itemID == 47242 then
                                        npcID = "其他"
                                    else
                                        npcID = spawnData["bossName"]
                                    end
                                    spawnData["itemGUID"][itemGuid] = {}
                                    break
                                end
                            end
                            --新增测试内容↑↑↑↑↑↑
                        else
                            npcID = "其他"
                            --新增测试内容↓↓↓↓↓↓
                            if data.spawnUID then
                                for _, spawnData in pairs(data.spawnUID) do
                                    spawnData["itemGUID"][itemGuid] = {}
                                end
                            end
                            --新增测试内容↑↑↑↑↑↑
                        end
                        --将使用过的itemGUID添加到itemGUIDUsed表中
                        if not ZL_CURRENT["itemGUIDUsed"] then ZL_CURRENT["itemGUIDUsed"] = {} end
                        ZL_CURRENT["itemGUIDUsed"][itemGuid] = npcID
                        --如果是打包拍卖，则同步到打包拍卖里面
                        if data.isPackage then
                            local _, __index = ZL.FetchDataFromItemId("[打包拍卖]", 1)
                            if __index then
                                table.insert(ZL_CURRENT.auctionlist[__index]["itemList"][itemlink]["itemGUID"], itemGuid)
                                -- ZL.syncAuction(__index)
                            end
                        end
                        itemHasCount = itemHasCount + currentInfo.stackCount
                        if itemHasCount >= needCount then
                            return
                        end
                    end
                end
            end
            if type(currentInfo) == "table" then wipe(currentInfo) end
        end
    end
    if itemLocation then
        itemLocation:Clear()
    end
    itemGuid = nil
end
--获取物品ItemGUID
function ZL.GetLootItemGUID()
    if not ZL.PlayerIsML() then return end
    local info, itemHasCount
    local itemBagCount = 0
    local itemNeedCount = 0
    -- local auctionlist = ZL_CURRENT["auctionlist"]
    if ZL_CURRENT["auctionlist"] and #ZL_CURRENT["auctionlist"] > 0 then
        ZL.AuctionFrame2.StateFrame.levelSortBtn:Disable()
        ZL.AuctionFrame2.StateFrame.timeSortBtn:Disable()
        for index, data in ipairs(ZL_CURRENT["auctionlist"]) do
            itemBagCount = GetItemCount(data.itemlink) --获取背包物品数量
            itemHasCount = 0
            if data["spawnUID"] then
                for _, value in pairs(data["spawnUID"]) do
                    if value["itemGUID"] then
                        for itemGUID, _ in pairs(value["itemGUID"]) do
                            local bagID, slotIndex = ZL.FindItemInBag(itemGUID)
                            if bagID and slotIndex then
                                info = C_Container.GetContainerItemInfo(bagID, slotIndex)
                                itemHasCount = itemHasCount + info.stackCount
                            end
                        end
                    end
                end
            end
            itemNeedCount = data.itemCount - itemHasCount
            if itemBagCount > 0 and itemNeedCount > 0 then
                findItemGUID(data.itemlink, index, itemNeedCount)
            end
        end
        ZL.AuctionFrame2.StateFrame.levelSortBtn:Enable()
        ZL.AuctionFrame2.StateFrame.timeSortBtn:Enable()
    end
    info = nil
end

--在IncomeList中查询tradeId的索引号，可能有多个
function ZL.FindTradeIdIncomeList(tradeId)
    local index = {}
    if ZL_CURRENT["IncomeList"] and #ZL_CURRENT["IncomeList"] > 0 then
        for _index, data in ipairs(ZL_CURRENT["IncomeList"]) do
            if data["tradeId"] == tradeId then
                table.insert(index, _index)
            end
        end
    end
    return index
end

--将物品放到指定背包
function ZL.PutAuctionItemInBag(itemGUID, targetBag, direction)
    targetBag = tonumber(targetBag) or 0
    local itemLocation, itemGuid, currentInfo, targetSlotIndex, _currentInfo, ___currentInfo
    if targetBag and C_Container.GetContainerNumFreeSlots(targetBag) > 0 then
        for bagID = 0, NUM_BAG_SLOTS do
            if bagID ~= targetBag then
                for slotIndex = 1, C_Container.GetContainerNumSlots(bagID) do
                    currentInfo = C_Container.GetContainerItemInfo(bagID, slotIndex)
                    if currentInfo and currentInfo.isBound then --拾取绑定的物品才移动位置
                        if not itemLocation then
                            itemLocation = ItemLocation:CreateFromBagAndSlot(bagID, slotIndex)
                        else
                            itemLocation:SetBagAndSlot(bagID, slotIndex)
                        end
                        itemGuid = C_Item.GetItemGUID(itemLocation)
                        if itemGuid == itemGUID then
                            for _targetSlotIndex = (direction and C_Container.GetContainerNumSlots(targetBag) or 1), (direction and 1 or C_Container.GetContainerNumSlots(targetBag)), (direction and -1 or 1) do
                                _currentInfo = C_Container.GetContainerItemID(targetBag, _targetSlotIndex)
                                if not _currentInfo then
                                    if ZL.opt.emptyOneSpace then
                                        --不同包之间空一格格子
                                        if _targetSlotIndex == C_Container.GetContainerNumSlots(targetBag) and targetBag < NUM_BAG_SLOTS then
                                            ___currentInfo = C_Container.GetContainerItemID(targetBag+1, 1)
                                            if not ___currentInfo then
                                                targetSlotIndex = _targetSlotIndex
                                                break
                                            end
                                        elseif _targetSlotIndex == 1 and targetBag > 0 then
                                            ___currentInfo = C_Container.GetContainerItemID(targetBag-1, C_Container.GetContainerNumSlots(targetBag-1))
                                            if not ___currentInfo then
                                                targetSlotIndex = _targetSlotIndex
                                                break
                                            end
                                        else
                                            targetSlotIndex = _targetSlotIndex
                                            break
                                        end
                                    else
                                        targetSlotIndex = _targetSlotIndex
                                        break
                                    end
                                end
                            end
                            if targetSlotIndex then
                                ClearCursor()
                                C_Container.PickupContainerItem(bagID, slotIndex)
                                C_Container.PickupContainerItem(targetBag, targetSlotIndex)
                                return
                            end
                        end
                    end
                end
            end
        end
    end
    if itemLocation then
        itemLocation:Clear()
    end
    itemGuid = nil
end

--通过itemGUID查询物品在背包中的位置
function ZL.FindItemInBag(itemGUID)
    if not itemGUID then return nil, nil end
    local itemLocation, itemGuid
    for bagID = 0, NUM_BAG_SLOTS do
        for slotIndex = 1, C_Container.GetContainerNumSlots(bagID) do
            if not itemLocation then
                itemLocation = ItemLocation:CreateFromBagAndSlot(bagID, slotIndex)
            else
                itemLocation:SetBagAndSlot(bagID, slotIndex)
            end
            if C_Item.DoesItemExist(itemLocation) then
                itemGuid = C_Item.GetItemGUID(itemLocation)
                if itemGuid == itemGUID then
                    return bagID, slotIndex
                end
            end
        end
    end
    if itemLocation then
        itemLocation:Clear()
    end
    itemLocation = nil
    itemGuid = nil
    return nil, nil
end
--将指定成员调整到队伍后面
function ZL.ChangePlayerGroup(memeberList)
    local index = 1
    local function changeGroup()
        if index <= #memeberList then
            local sender = memeberList[index]
            local senderIndex = nil
            local subgroup = nil
            --获取在团队中的位置和小队号
            for i = 1, MAX_RAID_MEMBERS do
                local name, _, _subgroup = GetRaidRosterInfo(i)
                if name and name == sender then
                    senderIndex = i
                    subgroup = _subgroup
                    break
                end
            end
            if senderIndex then
                local currentRoster = ZL.GetCurrentRoster()
                --从最后一队开始循环遍历
                for i = 8, subgroup+1, -1 do
                    if subgroup == i then --如果是和要调换队伍的人队伍一样，则不调换
                        break
                    else
                        if #currentRoster[i] < 5 then --如果目标队伍人数小于5人，则直接放到该小队
                            SetRaidSubgroup(senderIndex, i)
                            break
                        else --如果目标队伍人数为5人，则判断队伍中的玩家是否为消费老板或者需要邮寄的人或者是ML，都不是则跟他调换队伍
                            for j = 1, #currentRoster[i] do
                                local name = currentRoster[i][j]
                                local biLi = (ZL_CURRENT.WagesBiLi and ZL_CURRENT.WagesBiLi[name] and ZL_CURRENT.WagesBiLi[name].biLi) and (ZL_CURRENT.WagesBiLi[name].biLi/100) or 1
                                if ZL.PlayerIsML(name) and (biLi > 0) and ((not ZL_CURRENT["mailPlayers"]) or (not ZL_CURRENT["mailPlayers"][name])) then
                                    --如果不是消费老板，也不是需要邮寄的人，也不是ML，则遍历整个团队，查找这个在团队中的位置，然后相互调换
                                    for k = 1, MAX_RAID_MEMBERS do
                                        local _name = GetRaidRosterInfo(k)
                                        if _name and _name == name then
                                            SwapRaidSubgroup(senderIndex, k)
                                            break
                                        end
                                    end
                                end
                            end
                        end
                    end
                end
                index = index + 1
                C_Timer.After(0.3, changeGroup)
            else
                index = index + 1
                C_Timer.After(0.001, changeGroup)
            end
        end
    end
    changeGroup()
end

--获取不同背包插件的itemGuid对应的背包按钮名字
function ZL.GetBagButtonName(hide)
    local itemGuidBtnList = {}
    local itemLocation, itemGuid, bagButton, bagID, slotIndex
    local function linshi()
        if not itemLocation then
            itemLocation = ItemLocation:CreateFromBagAndSlot(bagID, slotIndex)
        else
            itemLocation:SetBagAndSlot(bagID, slotIndex)
        end
        if C_Item.DoesItemExist(itemLocation) then
            itemGuid = C_Item.GetItemGUID(itemLocation)
            itemGuidBtnList[itemGuid] = bagButton
        end
        if bagButton.BorderTop and hide then
            bagButton.BorderTop:Hide()
            bagButton.BorderLeft:Hide()
            bagButton.BorderBottom:Hide()
            bagButton.BorderRight:Hide()
        end
    end
    if _G["BagnonContainerItem1"] then
        --Bagnon背包插件,网易有爱BagBrother
        local i = 1
        while _G["BagnonContainerItem" .. i] do
            bagButton = _G["BagnonContainerItem" .. i]
            bagID = bagButton:GetParent():GetID()
            slotIndex = bagButton:GetID()
            linshi()
            i = i + 1
        end
    elseif _G["CombuctorFrame1"] then
        --Combuctor背包插件
        local i = 1
        while _G["CombuctorItem" .. i] do
            bagButton = _G["CombuctorItem" .. i]
            bagID = bagButton:GetParent():GetID()
            slotIndex = bagButton:GetID()
            linshi()
            i = i + 1
        end
    elseif _G["NDui_BackpackSlot1"] then
        --NDui插件
        local i = 1
        while _G["NDui_BackpackSlot" .. i] do
            bagButton = _G["NDui_BackpackSlot" .. i]
            bagID = bagButton.bagId
            slotIndex = bagButton.slotId
            linshi()
            i = i + 1
        end
    elseif _G["ElvUI_ContainerFrame"] then
        --ElvUI插件
        for _bagID = 0, NUM_BAG_SLOTS do
            for _slotIndex = 1, C_Container.GetContainerNumSlots(_bagID + 1) do
                bagButton = _G["ElvUI_ContainerFrameBag" .. _bagID .. "Slot" .. _slotIndex]
                bagID = bagButton.BagID
                slotIndex = bagButton.SlotID
                linshi()
            end
        end
    elseif _G["CombuctorInventoryFrame1"] then
        --网易有爱CombuctDep
        local totalSlots = 0
        local id, bag, slot
        for _bagID = 0, NUM_BAG_SLOTS do
            totalSlots = totalSlots + C_Container.GetContainerNumSlots(_bagID)
        end
        totalSlots = totalSlots + 32 --加上钥匙链
        for i = 1, totalSlots do
            id = i + 1
            bag = ceil(id / 36)
            slot = (id-1) % 36 + 1
            bagButton = _G[format('ContainerFrame%dItem%d', bag, slot)]
            if bagButton then
                bagID = bagButton:GetParent():GetID()
                slotIndex = bagButton:GetID()
                linshi()
            end
        end
        id, bag, slot = nil, nil, nil
    elseif _G["AdiBagsContainer1"] then
        --AdiBags

    elseif _G["ARKINV_Frame1"] then
        --ArkInventory
        for _bagID = 0, NUM_BAG_SLOTS do
            for _slotIndex = 1, C_Container.GetContainerNumSlots(_bagID) do
                bagButton = _G["ARKINV_Frame1ScrollContainerBag" .. (_bagID+1) .. "Item" .. _slotIndex]
                if bagButton then
                    bagID = bagButton:GetParent():GetID()
                    slotIndex = bagButton:GetID()
                    linshi()
                end
            end
        end
    else
        --暴雪原始背包
        for _bagID = 0, NUM_BAG_SLOTS do
            for _slotIndex = 1, C_Container.GetContainerNumSlots(_bagID) do
                bagButton = _G["ContainerFrame" .. (_bagID+1) .. "Item" .. (C_Container.GetContainerNumSlots(_bagID) - _slotIndex + 1)]
                if bagButton then
                    bagID = bagButton:GetParent():GetID()
                    slotIndex = bagButton:GetID()
                    linshi()
                end
            end
        end
    end
    if itemLocation then
        itemLocation:Clear()
    end
    itemGuid, bagButton, bagID, slotIndex = nil, nil, nil, nil
    return itemGuidBtnList
end

--创建动画闪烁
function ZL.CreateBagFlash(b)
    if not b then return end
    b.ZLFlashFind = b:CreateAnimationGroup()
    b.IconGlow = b:CreateTexture(nil, 'OVERLAY', nil, 7) --OVERLAY  HIGHLIGHT
	b.IconGlow:SetTexture('Interface/Buttons/UI-ActionButton-Border')
	b.IconGlow:SetBlendMode('ADD')
	b.IconGlow:SetPoint('CENTER')
    b.IconGlow:SetSize(67,67)
    -- b.IconGlow:SetAllPoints(b)
    b.IconGlow:Hide()
	
	for i = 1, 3 do
		local fade = b.ZLFlashFind:CreateAnimation('Alpha')
		fade:SetChildKey('flash')
		fade:SetOrder(i * 2)
		fade:SetDuration(.4)
		fade:SetFromAlpha(.1)
		fade:SetToAlpha(1)

		local fade = b.ZLFlashFind:CreateAnimation('Alpha')
		fade:SetChildKey('flash')
		fade:SetOrder(i * 2 + 1)
		fade:SetDuration(.4)
		fade:SetFromAlpha(1)
		fade:SetToAlpha(.1)
	end
    b.ZLFlashFind:SetToFinalAlpha(0)
end
--创建高亮图层
function ZL.CreateBagHighLightFrame(parent, edgeSize, state, frame, talbe, flash)
    parent = parent or UIParent
    local color = ZL.colorList[state] or {1, 0, 0, 1}
    local f
    if frame then
        --如果存在则重新设置父对象
        f = frame
        f:SetParent(parent)
    else
        f = CreateFrame("Frame", nil, parent, "BackdropTemplate")
        table.insert(talbe, f)
    end
    f:SetBackdrop({
        edgeFile = "Interface\\ChatFrame\\ChatFrameBackground",  --ChatFrameBackground
        edgeSize = edgeSize or 4,
        tile = true,
        insets = { left = 1, right = 1, top = 1, bottom = 1 }, -- 内边距
    })
    f:SetBackdropBorderColor(unpack(color))
    f:ClearAllPoints()
    f:SetAllPoints(parent)
    f:SetFrameLevel(parent:GetFrameLevel() + 8)
    f:Show()
    if flash then
        if not f.ag then
            f.ag = f:CreateAnimationGroup()
            f.anim = f.ag:CreateAnimation("Alpha")
            local anim = f.anim
            anim:SetOrder(1)
            anim:SetFromAlpha(0.1)
            anim:SetToAlpha(1)
            anim:SetDuration(0.5)
            f.ag:SetToFinalAlpha(1)
            f.ag:SetLooping("REPEAT")
        end
        if f.ag:Play() then f.ag:Stop() end
        f.ag:Play()
        C_Timer.After(5, function ()
            f.ag:Stop()
            f:Hide()
        end)
    end
end
--创建背包高亮
function ZL.BagHighLight()
    if (not ZL.opt.waitingBagHighLight) and (not ZL.opt.auctioningBagHighLight) and (not ZL.opt.successBagHighLight)
    and (not ZL.opt.failedBagHighLight) and (not ZL.opt.lgnoreBagHighLight) then
        return
    end
    -- if not ZL.BagHighLightList then ZL.BagHighLightList = {} end
    -- if ZL.BagHighLightList and #ZL.BagHighLightList > 0 then
    --     for _, f in ipairs(ZL.BagHighLightList) do
    --         f:Hide()
    --     end
    -- end
    if ZL_CURRENT.auctionlist and #ZL_CURRENT.auctionlist > 0 then
        local itemGuidBtnList = ZL.GetBagButtonName(true)
        local r, g, b, a
        local state
        if not next(itemGuidBtnList, nil) then return end
        -- local index = 1
        for _, data in ipairs(ZL_CURRENT.auctionlist) do
            if data.spawnUID and next(data.spawnUID, nil) and ((data.state == "waiting" and ZL.opt.waitingBagHighLight)
                or (data.state == "auctioning" and ZL.opt.auctioningBagHighLight) or (data.state == "success" and ZL.opt.successBagHighLight)
                or (data.state == "failed" and ZL.opt.failedBagHighLight) or (data.lgnore and ZL.opt.lgnoreBagHighLight)
            ) then
                if data.lgnore and ZL.opt.lgnoreBagHighLight then
                    state = "lgnore"
                else
                    if data.state == "waiting" and ZL.opt.waitingBagHighLight then
                        state = "waiting"
                    elseif data.state == "auctioning" and ZL.opt.auctioningBagHighLight then
                        state = "auctioning"
                    elseif data.state == "success" and ZL.opt.successBagHighLight then
                        state = "success"
                    elseif data.state == "failed" and ZL.opt.failedBagHighLight then
                        state = "failed"
                    end
                end
                if state then
                    for _, value in pairs(data.spawnUID) do
                        if value["itemGUID"] and next(value["itemGUID"], nil) then
                            for key in pairs(value["itemGUID"]) do
                                if itemGuidBtnList[key] then
                                    r, g, b, a = unpack(ZL.colorList[state] or {1, 0, 0, 1})
                                    if not itemGuidBtnList[key].BorderTop then
                                        ZL.CreateBorder(itemGuidBtnList[key], r, g, b, a, "OVERLAY", 4)
                                    else
                                        itemGuidBtnList[key].BorderTop:SetColorTexture(r,g,b,a)
                                        itemGuidBtnList[key].BorderLeft:SetColorTexture(r,g,b,a)
                                        itemGuidBtnList[key].BorderBottom:SetColorTexture(r,g,b,a)
                                        itemGuidBtnList[key].BorderRight:SetColorTexture(r,g,b,a)
                                        itemGuidBtnList[key].BorderTop:Show()
                                        itemGuidBtnList[key].BorderLeft:Show()
                                        itemGuidBtnList[key].BorderBottom:Show()
                                        itemGuidBtnList[key].BorderRight:Show()
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end
        if itemGuidBtnList then itemGuidBtnList = nil end
    end
end

--创建鼠标移动到拍卖物品背包高亮加闪烁
function ZL.OnEnterBagHighLight(v)
    if ZL.BUILD_DATA > 5 then return end
    local itemGuidBtnList = ZL.GetBagButtonName()
    local data = ZL_CURRENT.auctionlist[v]
    if data["spawnUID"] and next(data["spawnUID"], nil) then
        for _, value in pairs(data["spawnUID"]) do
            if value["itemGUID"] and next(value["itemGUID"], nil) then
                for key, _ in pairs(value["itemGUID"]) do
                    if itemGuidBtnList[key] then
                        if not itemGuidBtnList[key].ZLFlashFind then
                            ZL.CreateBagFlash(itemGuidBtnList[key])
                        end
                        if itemGuidBtnList[key].ZLFlashFind then
                            itemGuidBtnList[key].ZLFlashFind:Stop()
                            itemGuidBtnList[key].ZLFlashFind:Play()
                        end
                    end
                end
            end
        end
    end
    itemGuidBtnList = nil
end
-- 函数：在鼠标位置显示框架
function ZL.ShowAtMouse(frame)
    local scale = frame:GetEffectiveScale()
    local x, y = GetCursorPosition()
    x = x / scale
    y = y / scale
    frame:ClearAllPoints()
    frame:SetPoint("TOPLEFT", nil, "BOTTOMLEFT", x, y)
    frame:Show()
end

function ZL.utf8len(s)
    local len = 0
    local currentIndex = 1
    local bytes = string.len(s)
    while currentIndex <= bytes do
        local char = string.byte(s, currentIndex)
        if char > 0 and char <= 127 then
            currentIndex = currentIndex + 1
        elseif char >= 194 and char <= 223 then
            currentIndex = currentIndex + 2
        elseif char >= 224 and char <= 239 then
            currentIndex = currentIndex + 3
        elseif char >= 240 and char <= 244 then
            currentIndex = currentIndex + 4
        end
        len = len + 1
    end
    return len
end

--打开设置窗口并设置为横向不可拉升
function ZL.OpenAceConfigDialog(name, path, ...)
    local AceConfigDialog = LibStub("AceConfigDialog-3.0")
    AceConfigDialog:Open(name)
    local frame = AceConfigDialog.OpenFrames[name]
    if frame then
        local actualFrame = frame.frame
        -- 设置横向不可拉升
        actualFrame:SetResizeBounds(700, 500, 700, GetScreenHeight()-30)
    end
    if path then
        LibStub("AceConfigDialog-3.0"):SelectGroup(name, path, ...)
    end
end
-- 添加到打包拍卖
function ZL.AddToPackage(v)
    ZL_CURRENT.auctionlist[v].isPackage = true
    local currentAuctionList = ZL_CURRENT.auctionlist[v]
    local itemlink = currentAuctionList.itemlink
    local _, index = ZL.FetchDataFromItemId("[打包拍卖]", 1)
    if not index then
        local spawnKey = "0" .. GetServerTime() .. "01"
        local fdata = {
            type = "自动创建",
            itemId = 0,
            itemlink = "[打包拍卖]",
            itemindex = 1,
            startbidamount = 300,
            bidIncrement = 100,
            state = "waiting",
            lgnore = false,
            endTime = nil,
            isPaused = nil,
            bidderlist = {},
            itemCount = 1,
            sourceGUID = {},
            spawnUID = {[spawnKey] = {bossName="打包拍卖", itemGUID={}}},
            stackCount = 1,
            bindType = 0,
            itemLevel = 0,
            itemSubType = "打包",
            createTime = date("%Y-%m-%d %H:%M:%S", GetServerTime()),
            itemList = {},
        }
        --ML自己创建，不参与插件同步创建
        ZL_CURRENT.auctionlist = ZL_CURRENT.auctionlist or {}
        table.insert(ZL_CURRENT.auctionlist, fdata)
        index = #ZL_CURRENT.auctionlist
    end
    if not ZL_CURRENT.auctionlist[index].itemList then ZL_CURRENT.auctionlist[index].itemList = {} end
    if not ZL_CURRENT.auctionlist[index].itemList[itemlink] then ZL_CURRENT.auctionlist[index].itemList[itemlink] = {} end
    if not ZL_CURRENT.auctionlist[index].itemList[itemlink]["itemGUID"] then
        ZL_CURRENT.auctionlist[index].itemList[itemlink]["itemGUID"] = {}
    end
    if not ZL_CURRENT.auctionlist[index].itemList[itemlink]["spawnUID"] then
        ZL_CURRENT.auctionlist[index].itemList[itemlink]["spawnUID"] = {}
    end
    if not ZL_CURRENT.auctionlist[index].itemList[itemlink]["itemindex"] then
        ZL_CURRENT.auctionlist[index].itemList[itemlink]["itemindex"] = {}
    end
    local _itemlink = ZL_CURRENT.auctionlist[index].itemList[itemlink]
    ZL_CURRENT.auctionlist[index].itemList[itemlink]["itemCount"] = (_itemlink["itemCount"] or 0) + ZL_CURRENT.auctionlist[v].itemCount
    ZL_CURRENT.auctionlist[index].itemList[itemlink]["stackCount"] = ZL_CURRENT.auctionlist[v].stackCount
    table.insert(ZL_CURRENT.auctionlist[index].itemList[itemlink]["itemindex"], ZL_CURRENT.auctionlist[v].itemindex)
    local curAuction = ZL_CURRENT.auctionlist[v]
    if curAuction["spawnUID"] then
        for key, value in pairs(curAuction["spawnUID"]) do
            ZL_CURRENT.auctionlist[index].itemList[itemlink]["spawnUID"][key] = {["bossName"]=value["bossName"]}
            if value["itemGUID"] and next(value["itemGUID"], nil) then
                for itemGUID_key in pairs(value["itemGUID"]) do
                    table.insert(ZL_CURRENT.auctionlist[index].itemList[itemlink]["itemGUID"], itemGUID_key)
                end
            end
        end
    end
    --开始同步的功能
    local fdata = {
        type = "打包拍卖",
        data1 = ZL_CURRENT.auctionlist[v],
        data2 = ZL_CURRENT.auctionlist[index],
        globalConfigData = ZL.globalConfigData(),
    }
    MyAddon:TransmitAddonInfo("AUTOAUC SYNC14", fdata)
    ZL.AuctionFrame2.entries[v].sync = true
    C_Timer.After(10, function ()
        ZL.AuctionFrame2.entries[v].sync = nil
    end)
    ZL.AuctionListSort()
end

--数字转汉字
function ZL.convertToChineseNumber(number)
    local chineseNumber = ""
    number = tostring(number)
    -- 遍历每个字符并进行转换
    for i = 1, #number do
        local digit = number:sub(i, i)
        chineseNumber = chineseNumber .. ZL.numToChinese[digit]
    end
    return chineseNumber
end

--将汉字数字转换为数字
function ZL.convert_all_chinese_numbers(input_str)
    -- 创建一个映射表，将汉字数字转换为阿拉伯数字
    local chinese_numbers = {
        ["两"] = 2,
        ["零"] = 0,
        ["一"] = 1,
        ["二"] = 2,
        ["三"] = 3,
        ["四"] = 4,
        ["五"] = 5,
        ["六"] = 6,
        ["七"] = 7,
        ["八"] = 8,
        ["九"] = 9,
        ["十"] = 10,
        ["百"] = 100,
        ["千"] = 1000,
        ["万"] = 10000,
        ["亿"] = 100000000
    }
    -- 将汉字数字转换为阿拉伯数字
    local function chinese_to_arabic(chinese_str)
        local result = 0
        local temp_num = 0
        local last_unit = 1 -- 上一个单位
    
        for i = 1, #chinese_str-2, 3 do
            local char = chinese_str:sub(i, i+2)
            local num = chinese_numbers[char]
    
            if num < 10 then
                temp_num = num
            else
                if num > last_unit then
                    result = result + (temp_num == 0 and 1 or temp_num) * num
                else
                    result = result + temp_num * num
                end
                temp_num = 0
                last_unit = num
            end
        end
    
        -- 处理最后一个数字
        if temp_num ~= 0 then
            result = result + temp_num
        end
    
        return result
    end
    local pattern = "[两零一二三四五六七八九十百千万亿]+"
    local result = input_str:gsub(pattern, function(cn_num)
        if cn_num then
            return tostring(chinese_to_arabic(cn_num))
        end
    end)
    return result
end

--获取周几
function ZL.GetWeekDay(dateString)
    local weekdays = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"}
    local currentDate
    if dateString and type(dateString) == "string" then
        local year, month, day = dateString:match("(%d+)-(%d+)-(%d+)")
        local timestamp = time({
            year = tonumber(year),
            month = tonumber(month),
            day = tonumber(day)
        })
        currentDate = date("*t", timestamp)
    else
        currentDate = date("*t")
    end
    return weekdays[currentDate.wday]
end

--格式为：“2025-01-01”, endtime 默认为今天，返回秒数
function ZL.GetDiffTime(_startTime, _endTime)
    _endTime = _endTime or date("%Y-%m-%d", GetServerTime())
    local agoYear, agoMonth, agoDay = _startTime:match("(%d+)-(%d+)-(%d+)")
    local startTime = time{year=agoYear, month=agoMonth, day=agoDay, hour=0, min=0, sec=0}

    local endyear, endmonth, endday = _endTime:match("(%d+)-(%d+)-(%d+)")
    local endTime = time{year=endyear, month=endmonth, day=endday, hour=0, min=0, sec=0} -- 当前时间
    return difftime(endTime, startTime)
end
-- 计算指定天数前的日期
function ZL.getDateDaysAgo(days)
    return date("%Y-%m-%d", time() - (days * 86400))
end
--鼠标滚轮设置文本框数字
function ZL.EditOnMouseWheel(self, delta)
    if self:HasFocus() then
        local number = self:GetNumber()
        if delta > 0 then
            number = number + 100
        else
            number = number - 100
        end
        self:SetNumber(number)
    end
end

function ZL.AddFriendFilterFunc(self, event, text, player, l, cs, t, flag, channelId, ...)
    local _msg = ERR_FRIEND_ADDED_S:gsub("%%s", "(.+)")
    if strfind(text, _msg) or strfind(text, "(.+)上线了。") or strfind(text, ERR_FRIEND_NOT_FOUND)
    or strfind(text, ERR_FRIEND_ERROR) then
        return true
    end
    return false, text, player, l, cs, t, flag, channelId, ...
end

--通过添加好友方式判断玩家是否在线
--del表示新添加的查完信息后是否要删除好友
function ZL.IsOnline(target, del, yield, noadd)
    if target == UnitName("player") then return true end
    local info = C_FriendList.GetFriendInfo(target)
    if (not info) then
        if C_FriendList.GetNumFriends() >= 100 then
            local msgStr = "好友数量已满，无法判断【" .. target .. "】是否在线，请先删除部分好友后重试"
            ZL.Print(msgStr, true, nil, 1, 0, 0)
            return false
        else
            if yield or (not noadd) then
                C_FriendList.AddFriend(target)
                C_FriendList.ShowFriends()
                if yield then
                    ZL.addNewPlayer[target] = true
                    ZL.IsOnlinePlayer = target
                    coroutine.yield()
                end
                info = C_FriendList.GetFriendInfo(target)
                if del then
                    C_Timer.After(1, function ()
                        C_FriendList.RemoveFriend(target)
                        C_FriendList.ShowFriends()
                    end)
                end
            end
        end
    end
    return info and info.connected or false
end

-- 创建一个动态表格函数
function ZL.CreateDynamicTable()
    local mt = {
        __index = function(t, k)
            if not rawget(t, k) then
                -- 动态创建一个新的行或列
                t[k] = setmetatable({}, mt)
            end
            return t[k]
        end
    }
    return setmetatable({}, mt)  -- 返回一个动态表格
end

--获取周长重置和剩余重置时间
function ZL.GetWeeklyResetTime()
    -- 获取当前服务器时间（秒）
    local currentTime = GetServerTime()
    local resetTime
    local midnightTime
    local dateTable = date("*t", currentTime)
    local currentDayOfhour = dateTable.hour
    dateTable.hour = 7
    dateTable.min = 0
    dateTable.sec = 0

    -- 计算当前是本周的第几天（1 = 周日，2 = 周一，...，7 = 周六）
    local currentDayOfWeek = dateTable.wday
    if currentDayOfWeek == 5 then
        if currentDayOfhour >= 7 then
            dateTable.day = dateTable.day + 7
        end
    elseif currentDayOfWeek > 5 then
        dateTable.day = 7 - (currentDayOfWeek - 5) + dateTable.day
    else
        dateTable.day = 5 - currentDayOfWeek + dateTable.day
    end
    resetTime = time(dateTable)
    -- 计算剩余时间（秒）
    local remainingTime = resetTime - currentTime

    -- 将剩余时间转换为天、小时、分钟和秒
    local days = floor(remainingTime / 86400)
    local hours = floor((remainingTime % 86400) / 3600)
    local minutes = floor((remainingTime % 3600) / 60)
    local seconds = remainingTime % 60
    local remainTime
    if days > 0 then
        remainTime = days .. "天" .. hours .. "时" .. minutes .. "分" .. seconds .. "秒"
    elseif hours > 0 then
        remainTime = hours .. "时" .. minutes .. "分" .. seconds .. "秒"
    elseif minutes > 0 then
        remainTime = minutes .. "分" .. seconds .. "秒"
    else
        remainTime = seconds .. "秒"
    end
    return resetTime, remainTime
end

--获取日常重置和剩余时间
function ZL.GetDailyResetTime()
    -- 获取当前服务器时间（秒）
    local currentTime = GetServerTime()

    -- 获取当前日期的0点时间（秒）
    local dateTable = date("*t", currentTime)
    dateTable.hour = 0
    dateTable.min = 0
    dateTable.sec = 0
    local midnightTime = time(dateTable)

    -- 计算下一次7点的时间（秒）
    local resetTime = midnightTime + 25200  -- 7点 = 7 * 3600秒
    if currentTime >= resetTime then
        resetTime = resetTime + 86400  -- 如果当前时间已经超过7点，重置时间为第二天的7点
    end

    -- 计算剩余时间（秒）
    local remainingTime = resetTime - currentTime

    -- 将剩余时间转换为小时、分钟和秒
    local hours = floor(remainingTime / 3600)
    local minutes = floor((remainingTime % 3600) / 60)
    local seconds = remainingTime % 60
    local remainTime
    if hours > 0 then
        remainTime = hours .. "时" .. minutes .. "分" .. seconds .. "秒"
    elseif minutes > 0 then
        remainTime = minutes .. "分" .. seconds .. "秒"
    else
        remainTime = seconds .. "秒"
    end
    return resetTime, remainTime
end

--获取专业技能CD重置时间和剩余时间
function ZL.GetCooldownTime(spellID)
    local start, duration, enabled = GetSpellCooldown(spellID)
    local resetTime, remainTime
    if enabled == 1 and start > 0 and duration > 0 then
        local serverTime, time = GetServerTime(), GetTime()
        start = start > time and (start - 2 ^ 32 / 1000) or start
        local cooldownTime = start + duration - time
        if cooldownTime > 0 then
            remainTime = cooldownTime
            resetTime = cooldownTime + serverTime
        end
    elseif start == 0 then
        resetTime = 0
        remainTime = 0
    end
    return resetTime, remainTime
end
--将秒转换成时间格式2
function ZL.ConvertSecondsToTimeString(remainingTime)
    -- 将剩余时间转换为天、小时、分钟和秒
    local days = floor(remainingTime / 86400)
    local hours = floor((remainingTime % 86400) / 3600)
    local minutes = floor((remainingTime % 3600) / 60)
    local seconds = remainingTime % 60
    local remainTime
    if days > 0 then
        remainTime = days .. "天" .. hours .. "时"
    elseif hours > 0 then
        remainTime = hours .. "时" .. minutes .. "分"
    elseif minutes > 0 then
        remainTime = minutes .. "分" .. seconds .. "秒"
    else
        remainTime = seconds .. "秒"
    end
    return remainTime
end
--只支持3天，7天周期副本，默认重置周期为3天
function ZL.GetNextInstanceReset(days)
    days = ((not days) or days == 3) and 3 or 7
    local lastResetTime
    if days == 3 then
        lastResetTime = time({year=2025, month=4, day=15, hour=7})
    else
        lastResetTime = time({year=2025, month=4, day=17, hour=7})
    end
    local currentTime = GetServerTime()
    local nextReset = lastResetTime
    while nextReset <= currentTime do
        nextReset = nextReset + days * 24 * 60 * 60
    end
    return nextReset - currentTime, date("%Y-%m-%d %H:%M", nextReset)
end

function ZL.PrintHelp()
    DEFAULT_CHAT_FRAME:AddMessage(ZL.Prefix(" 斜杠命令："))
    for _, key in ipairs(ZL.commandInfoKeyList) do
        local value = ZL.commandInfo[key]
        if value and value.label then
            if value.key == "" then
                DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00/aa|r - " .. value.label)
            else
                DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00/aa " .. value.key .. "|r - " .. value.label)
            end
        end
    end
end
function ZL.OnChatCommand(input)
    input = strtrim(input)
    local cmd, args = strmatch(input, "^([^ ]*) ?(.*)$")
    cmd = strlower(cmd)
    if ZL.commandInfo[cmd] then
        ZL.commandInfo[cmd].callback(args)
    else
        ZL.PrintHelp()
    end
end

function ZL.SaveDataRemind(reset)
    if ZL.PlayerIsML() then
        if ZL.UpdateReloadUI and reset then
            if not ZL.UpdateReloadUI:IsCancelled() then
                ZL.UpdateReloadUI:Cancel()
            end
            ZL.UpdateReloadUI = nil
        end
        if not ZL.UpdateReloadUI then
            ZL.UpdateReloadUI = C_Timer.NewTicker((ZL.opt.reloadUITimerJump or 600), function ()
                if (not InCombatLockdown()) and ZL.opt.isReloadUI and IsInInstance() and (select(2, IsInInstance()) == "raid")
                and IsInRaid(1) then
                    local isNotice = true
                    if ZL.opt.MLlootNoticeReloadUI then
                        local lootMethod = GetLootMethod()
                        if not (lootMethod == "master" or lootMethod == 2) then
                            isNotice = false
                        end
                    end
                    if isNotice then
                        if not ZL.ReloadUIFrame then ZL:CreateReloadUIFrame() end
                        ZL.ReloadUIFrame:Show()
                        C_VoiceChat.StopSpeakingText()
                        PlaySoundFile("Interface\\AddOns\\" .. addonName .. "\\sound\\" .. ZL.SoundType .. "\\baocunshuju.mp3", "Master")
                        C_Timer.After(5, function ()
                            ZL.ReloadUIFrame:Hide()
                            if ZL.opt.isSYNCAll and ZL.GetAuctioningCount() == 0 then
                                ZL.syncDada()
                            end
                        end)
                    end
                end
            end)
        end
    else
        if ZL.UpdateReloadUI then
            if not ZL.UpdateReloadUI:IsCancelled() then
                ZL.UpdateReloadUI:Cancel()
            end
            ZL.UpdateReloadUI = nil
        end
    end
end
--获取团员名单下拉菜单
function ZL.GroupMembersMenu(self, isCurrent, tempfunc)
    local menuTable = {}
    local currentRoster
    if isCurrent then
        currentRoster = ZL.GetCurrentRoster()
    else
        currentRoster = ZL.GetWagesGroupMembers()
    end
    if currentRoster then
        for i = 1, #currentRoster do
            if #currentRoster[i] > 0 then
                local group = {
                    text = "|cffffffff小队" .. tostring(i) .. "|r",
                    hasArrow = true,
                    isTitle = true,
                    menuTable = {},
                }
                for _, playerName in ipairs(currentRoster[i]) do
                    tinsert(group.menuTable, {
                        text=playerName,
                        func=tempfunc,
                    })
                end
                tinsert(menuTable, group)
                group = nil
            end
        end
    end
    return menuTable
end

--创建StaticPopup团队成员下拉框
function ZL.CreateGroupMembersDropdown()
    -- 创建按钮并绑定菜单
    ZL.GroupMembersDropdown = CreateFrame("Button", nil, ZL)
    local GroupMembersDropdown = ZL.GroupMembersDropdown
    GroupMembersDropdown:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
    GroupMembersDropdown:SetSize(200, 24)
    ZL.GUI:GetClass('Dropdown'):Bind(GroupMembersDropdown)
    GroupMembersDropdown:Hide()
end

--判断流拍物品是否可以分解
function ZL.IsDisenchantAble(itemId)
    if not itemId then return end
    local itemQuality = select(3, cGetItemInfo(itemId))
    if not itemQuality then return end
    local inventoryType = C_Item.GetItemInventoryTypeByID(itemId)
    --0表示不可以装备
    if itemQuality < 2 or itemQuality > 4 or (not inventoryType) or inventoryType == 0 or (not ZL.invTypeToSlotId[inventoryType]) or
    ZL.invTypeToSlotId[inventoryType] == 4 or ZL.invTypeToSlotId[inventoryType] == 19 or ZL.NON_DISENCHANTABLE_ITEMS[itemId] then
        return
    end
    return true
end

--获取物品装备、背包、银行的数量
function ZL.GetItemNumbers(itemId)
    if not type(itemId) == "number" or itemId <= 0 then return 0,0,0,0,0 end
    local inventoryCount = 0
    for slot = 1, 19 do -- 遍历所有装备栏（1-19）
        local item = GetInventoryItemID("player", slot)
        if item == itemId then
            inventoryCount = inventoryCount + 1
        end
    end
    local itemBagCount = GetItemCount(itemId) --获取背包+角色装备物品数量
    local bagCount = itemBagCount - inventoryCount --背包数量
    local itemTotalCount = GetItemCount(itemId, true) --获取背包+角色装备+银行物品数量
    local itemBankCount = itemTotalCount - itemBagCount --银行物品数量

    return inventoryCount, bagCount, itemBankCount, itemTotalCount
end

--获取在线总团员数和已安装插件或拍卖WA字符串数
function ZL.GetGroupMembersAndHasAddon()
    local totalMembers = 0
    local hasAddon = 0
    if ZL_PLAYERLIST.GroupMembersVersion and next(ZL_PLAYERLIST.GroupMembersVersion) and IsInRaid(1) then
        for i = 1, MAX_RAID_MEMBERS do
            local name, _, _, _, _, _, _, online = GetRaidRosterInfo(i)
            if name and online then
                totalMembers = totalMembers + 1
                if ZL_PLAYERLIST.GroupMembersVersion[ZL.GetFullName(name)] then
                    hasAddon = hasAddon + 1
                end
            end
        end
    end
    return totalMembers, hasAddon
end

function ZL.formatNumber(num)
    -- 处理小数和负数
    local sign = ""
    if num < 0 then
        sign = "-"
        num = math.abs(num)
    end

    -- 定义单位表
    local units = {
        {value = 100000000, unit = "亿"},  -- 1亿
        {value = 10000, unit = "万"},      -- 1万
    }
    
    -- 检查是否需要转换
    if num < 10000 then
        return tostring(num)
    end

    -- 遍历单位表找到合适的单位
    for _, v in ipairs(units) do
        if num >= v.value then
            local formatted = num / v.value
            if formatted == floor(formatted) then
                return sign .. formatted .. v.unit
            else
                local decimals = formatted >= 100 and 0 or (formatted >= 10 and 1 or 2)
                tostring(num):gsub("0+$", ""):gsub("%.$", "")
                local cleaned = format("%." .. decimals .. "f", formatted)
                local dot_pos = cleaned:find("%.")
                if dot_pos then
                    -- 移除末尾的0
                    cleaned = cleaned:gsub("0+$", "")
                    -- 如果小数点后面没有数字了，也移除小数点
                    if cleaned:sub(-1) == "." then
                        cleaned = cleaned:sub(1, -2)
                    end
                end
                return sign .. cleaned .. v.unit
            end
        end
    end
    -- 默认返回原始数字（理论上不会执行到这里）
    return tostring(num)
end


--同步拍卖物品数据
function ZL.SyncAuctionData(data)
    local _, index = ZL.FetchDataFromItemId(data.itemlink, data.itemindex)
    if index then
        local lgnore = ZL_CURRENT.auctionlist[index].lgnore
        ZL_CURRENT.auctionlist[index] = data
        ZL_CURRENT.auctionlist[index].lgnore = lgnore
    else
        ZL_CURRENT.auctionlist = ZL_CURRENT.auctionlist or {}
        table.insert(ZL_CURRENT.auctionlist, data)
        index = #ZL_CURRENT.auctionlist
        ZL_CURRENT.auctionlist[index].lgnore = false
    end
    return index
end

--文字转语音
function ZL.SpeakText(text)
    C_VoiceChat.StopSpeakingText()
    C_Timer.After(0.1, function ()
        C_VoiceChat.SpeakText(C_TTSSettings.GetVoiceOptionID(0), text, 4, 100, false)
    end)
end

--小地图按钮动画
function ZL.miniMapIconAnimation()
    local curAuctionList = ZL_CURRENT.auctionlist
    local count = 0
    if curAuctionList and #curAuctionList >= 1 then
        for _, data in ipairs(curAuctionList) do
            if (data.state == "auctioning") and (not data.lgnore) and ((not ZL.opt.hideWaitingAuctionCantUseItem) or
                ZL.ItemCanUseBySpec(data.itemId, data.bindType)) then
                count = count + 1
            end
        end
    end
    if count == 0 then
        _G["ZLAucitoningCountFrame"]:SetText("")
        if _G["LibDBIcon10_AUTOAUCTION"].ag:IsPlaying() then
            _G["LibDBIcon10_AUTOAUCTION"].ag:Stop()
        end
    else
        _G["ZLAucitoningCountFrame"]:SetText(count)
        if (not _G["LibDBIcon10_AUTOAUCTION"].ag:IsPlaying()) then
            _G["LibDBIcon10_AUTOAUCTION"].ag:Play()
        end
    end
end

--更新目标价
function ZL.updateTargetAmount(index)
    local data = ZL_CURRENT.auctionlist[index]
    local itemCount = data.itemCount
    local Frame1 = ZL.AuctionFrame2.entries[index]
    local bidCount = Frame1.bidFrame.bidCounts:GetNumber()
    local oldAmount = Frame1.bidFrame.bidEditBox:GetNumber()
    bidCount = bidCount > 0 and bidCount or 1
    bidCount = bidCount > itemCount and itemCount or bidCount
    local _, bidIncrement, tarbidamount, _bidCount, successList = ZL.GetNewBidAmount(index)
    if bidCount > _bidCount and #successList > 0 then
        for i = #successList, 1, -1 do
            if successList[i][2] >= bidCount then
                tarbidamount = successList[i][1] + bidIncrement
                break
            end
        end
    end
    tarbidamount = max(tarbidamount, oldAmount)
    Frame1.bidFrame.bidEditBox:SetNumber(tarbidamount)
end

function ZL.sleep(n)
    if not n or type(n) ~= "number" then return end
    local co = coroutine.running()
    if not co then return end
    C_Timer.After(n, function()
        coroutine.resume(co)
    end)
    coroutine.yield()
end

function ZL.GetWagesBiliFromWCL(sorce)
    for i, data in ipairs(ZL.opt.WCLSetting) do
        if i == 1 then
            if sorce >= data.sorceMin then
                return data.wagesBili
            end
        elseif i == #ZL.opt.WCLSetting then
            if sorce < data.sorceMax then
                return data.wagesBili
            end
        else
            if sorce >= data.sorceMin and sorce < data.sorceMax then
                return data.wagesBili
            end
        end
    end
end

--通过WCL分数更新工资比例
function ZL.UpdateWagesBiliFromWCL()
    if ZL_CURRENT.WCLSorce and next(ZL_CURRENT.WCLSorce) then
        local WagesGroupMembers = ZL.GetWagesGroupMembers()
        if WagesGroupMembers then
            ZL_CURRENT.WagesBiLi = ZL_CURRENT.WagesBiLi or {}
            local pruneName, sorce, biLi
            for _, groupData in ipairs(WagesGroupMembers) do
                for _, name in ipairs(groupData) do
                    pruneName = ZL.GetNoRealmName(name)
                    sorce = ZL_CURRENT.WCLSorce[pruneName]
                    if sorce then
                        ZL_CURRENT.WagesBiLi[name] = ZL_CURRENT.WagesBiLi[name] or {}
                        biLi = ZL.GetWagesBiliFromWCL(sorce)
                        ZL_CURRENT.WagesBiLi[name]["biLi"] = biLi
                    end
                end
            end
            if ZL.AuctionRecordFrame.playerBalanceFrame:IsShown() then
                ZL.AuctionRecordFrame.playerBalanceFrame:Update()
            end
        end
    else
        ZL.Print("没有WCL分数数据，请先导入！")
    end
end

--获取已保存副本信息--包括野外BOSS
function ZL.GetPlayerSavedInstanceInfo()
    --需要先RequestRaidInfo()，通过事件异步获取信息
    --在保存副本，BOSS被成功击杀的时候RequestRaidInfo()一次
    --打开团队窗口中的团队信息时会自动RequestRaidInfo()一次
    local instancesInfo = {updateTime = time()}

    local isKilled, reset, difficultyId, locked, extended, isRaid, difficultyName, numEncounters, instanceId, _, name
    for i = 1, GetNumSavedInstances() do
        name, _, reset, difficultyId, locked, extended, _, isRaid, _, difficultyName, numEncounters, _, _, instanceId = GetSavedInstanceInfo(i)
        if name and reset and reset > 0 and isRaid then  --(locked or extended)
            instancesInfo[instanceId] = instancesInfo[instanceId] or {}
            instancesInfo[instanceId][difficultyId] = instancesInfo[instanceId][difficultyId] or {}
            for encounterIndex = 1, numEncounters do
                _, _, isKilled = GetSavedInstanceEncounterInfo(i, encounterIndex)
                tinsert(instancesInfo[instanceId][difficultyId], isKilled and 1 or 0)
            end
        end
    end
    return instancesInfo
end

--自动切换分配方式
function ZL.autoChangeLootMethod()
    if ZL.opt.AutoChangeLootMethod and IsInRaid(1) and UnitIsGroupLeader("player") then
        if ZL.opt.SelectLootMethod == 1 then --队长分配
            if SetLootMethod then
                SetLootMethod("master", "player")
            else
                C_PartyInfo.SetLootMethod(2, "player")
            end
            C_Timer.After(1, function ()
                SetLootThreshold(ZL.opt.MarsterLootQuality+1)
            end)
        elseif ZL.opt.SelectLootMethod == 2 then --个人拾取
            if SetLootMethod then
                SetLootMethod("roundrobin")
            else
                C_PartyInfo.SetLootMethod(5)
            end
        end
    end
end
--弹出菜单是否已打开
function ZL.tdGUI_DropMenuIsShown()
    local lib = LibStub:GetLibrary(format('%s.Class.%s', 'tdGUI-1.0', 'DropMenu'))
    return lib.Public.menuList[1]:IsShown()
end
--获取当前选择副本难度列表
function ZL.EJ_GetInstanceDifficultyIDS()
    local EJ_DIFFICULTIES = {
        DifficultyUtil.ID.DungeonNormal,
        DifficultyUtil.ID.DungeonHeroic,
        DifficultyUtil.ID.DungeonMythic,
        DifficultyUtil.ID.DungeonChallenge,
        DifficultyUtil.ID.DungeonTimewalker,
        -- DifficultyUtil.ID.RaidLFR,
        DifficultyUtil.ID.Raid10Normal,
        DifficultyUtil.ID.Raid10Heroic,
        DifficultyUtil.ID.Raid25Normal,
        DifficultyUtil.ID.Raid25Heroic,
        -- DifficultyUtil.ID.PrimaryRaidLFR,
        DifficultyUtil.ID.PrimaryRaidNormal,
        DifficultyUtil.ID.PrimaryRaidHeroic,
        DifficultyUtil.ID.PrimaryRaidMythic,
        DifficultyUtil.ID.RaidTimewalker,
        DifficultyUtil.ID.Raid40,
        DifficultyUtil.ID.RaidMythicFlexible,
        
    };
    -- local function GetEJDifficultySize(difficultyID)
    --     if difficultyID ~= DifficultyUtil.ID.RaidTimewalker and not DifficultyUtil.IsPrimaryRaid(difficultyID) then
    --         return DifficultyUtil.GetMaxPlayers(difficultyID);
    --     end
    --     return nil;
    -- end
    -- local function GetEJDifficultyString(difficultyID)
    --     local name = DifficultyUtil.GetDifficultyName(difficultyID);
    --     local size = GetEJDifficultySize(difficultyID);
    --     if size then
    --         return string.format(ENCOUNTER_JOURNAL_DIFF_TEXT, size, name);
    --     else
    --         return name;
    --     end
    -- end
    local ids = {}
    for _, difficultyID in ipairs(EJ_DIFFICULTIES) do
        if EJ_IsValidInstanceDifficulty(difficultyID) then
            tinsert(ids, difficultyID)
        end
    end
    return ids
end
