提交 39d19b53 authored 作者: 贺阳's avatar 贺阳

1、把面单号的唯一约束改为物流订单号的唯一约束

2、根据物流订单号判断系统是否已存在,如果存在的话,判断是否已关联提单,如果关联提单且提单没有取消就不进行处理(包裹和包裹下的商品都不修改); 如果不存在,把包裹下的商品明细删除,创建此次推送的商品,同时修改包裹的数据 3、提单已存在,状态是草稿是要传的是update才会修改,提单不存在(包括已取消的提单)要传的是Create才会创建
上级 352656c8
...@@ -2,3 +2,5 @@ from . import res_partner ...@@ -2,3 +2,5 @@ from . import res_partner
from . import cc_node from . import cc_node
from . import cc_bill_loading from . import cc_bill_loading
from . import cc_customs_declaration_order from . import cc_customs_declaration_order
from . import cc_node_exception_reason
...@@ -195,9 +195,9 @@ class CcShipPackage(models.Model): ...@@ -195,9 +195,9 @@ class CcShipPackage(models.Model):
# 物流订单号 # 物流订单号
logistic_order_no = fields.Char(string='Logistic Order No', index=True) logistic_order_no = fields.Char(string='Logistic Order No', index=True)
# 按tracking_no,唯一 # 按logistic_order_no,唯一
_sql_constraints = [ _sql_constraints = [
('tracking_no_uniq', 'unique(tracking_no)', 'The Tracking No must be unique.') ('logistic_order_no_uniq', 'unique(logistic_order_no)', 'The Logistic Order No must be unique.')
] ]
# 运单号(面单号) # 运单号(面单号)
...@@ -320,7 +320,7 @@ class CcShipPackage(models.Model): ...@@ -320,7 +320,7 @@ class CcShipPackage(models.Model):
# 进度状态, 包括已提货、 小包查验、海关放行、小包出库、小包入库、清关失败,包裹交接 # 进度状态, 包括已提货、 小包查验、海关放行、小包出库、小包入库、清关失败,包裹交接
state = fields.Many2one('cc.node', string='Progress state',domain="[('node_type', '=', 'package')]", state = fields.Many2one('cc.node', string='Progress state',domain="[('node_type', '=', 'package')]",
default=lambda self: self.env['cc.node'].search([('node_type','=','package'), ('is_default', '=', True)], limit=1)) default=lambda self: self.env['cc.node'].search([('node_type','=','package'), ('is_default', '=', True)], limit=1))
node_exception_reason_id = fields.Many2one('cc.node.exception.reason', 'Exception Reason')
process_time = fields.Datetime('Process Time(UTC)') process_time = fields.Datetime('Process Time(UTC)')
......
# 导入odoo
import base64
import xlrd
from odoo import models, fields, api, _
# 导入日志
import logging
from odoo.exceptions import UserError
# 获取日志
_logger = logging.getLogger(__name__)
# 增加清关节点对象,继承自models.Model, 用于管理业务数据.业务数据包括节点名称、节点描述、节点顺序、是否必须节点
class CcNodeExceptionReason(models.Model):
_name = 'cc.node.exception.reason'
_description = 'CC Node Exception Reason'
code_id = fields.Many2one('cc.node', 'Node', index=True)
name = fields.Char(string='Name', translate=True)
desc = fields.Char(string='Description', translate=True)
...@@ -3,6 +3,14 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink ...@@ -3,6 +3,14 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_cc_node_base.group_user,cc_node base.group_user,ccs_base.model_cc_node,base.group_user,1,0,0,0 access_cc_node_base.group_user,cc_node base.group_user,ccs_base.model_cc_node,base.group_user,1,0,0,0
access_cc_node_base.group_erp_manager,cc_node base.group_erp_manager,ccs_base.model_cc_node,base.group_erp_manager,1,1,1,1 access_cc_node_base.group_erp_manager,cc_node base.group_erp_manager,ccs_base.model_cc_node,base.group_erp_manager,1,1,1,1
access_cc_node_exception_reason_base.group_user,cc_node_exception_reason base.group_user,ccs_base.model_cc_node_exception_reason,base.group_user,1,0,0,0
access_cc_node_exception_reason_base.group_erp_manager,cc_node_exception_reason base.group_erp_manager,ccs_base.model_cc_node_exception_reason,base.group_erp_manager,1,1,1,1
access_cc_bl_base.group_user,cc_bl base.group_user,ccs_base.model_cc_bl,base.group_user,1,0,0,0 access_cc_bl_base.group_user,cc_bl base.group_user,ccs_base.model_cc_bl,base.group_user,1,0,0,0
access_cc_bl_base.group_erp_manager,cc_bl base.group_erp_manager,ccs_base.model_cc_bl,base.group_erp_manager,1,1,1,1 access_cc_bl_base.group_erp_manager,cc_bl base.group_erp_manager,ccs_base.model_cc_bl,base.group_erp_manager,1,1,1,1
access_cc_bl_ccs_base.group_clearance_of_customs_manager,cc_bl ccs_base.group_clearance_of_customs_manager,ccs_base.model_cc_bl,ccs_base.group_clearance_of_customs_manager,1,1,1,1 access_cc_bl_ccs_base.group_clearance_of_customs_manager,cc_bl ccs_base.group_clearance_of_customs_manager,ccs_base.model_cc_bl,ccs_base.group_clearance_of_customs_manager,1,1,1,1
......
...@@ -106,7 +106,8 @@ ...@@ -106,7 +106,8 @@
<field name="internal_account_number" string="Internal Account Number"/> <field name="internal_account_number" string="Internal Account Number"/>
<field name="logistic_order_no" string="Logistic Order No"/> <field name="logistic_order_no" string="Logistic Order No"/>
<field name="buyer_region" string="Buyer Region"/> <field name="buyer_region" string="Buyer Region"/>
<field name="node_exception_reason_id" readonly="1"
attrs="{'invisible':[('node_exception_reason_id','=',False)]}"/>
</group> </group>
<group string="CC info"> <group string="CC info">
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models, api, fields from odoo import models, api, fields
from odoo.exceptions import Warning,ValidationError from odoo.exceptions import Warning, ValidationError
PUSH_TYPE = [ PUSH_TYPE = [
# ('轨迹揽收', '轨迹揽收'), # ('轨迹揽收', '轨迹揽收'),
...@@ -47,6 +47,8 @@ class BatchInputShipPackageStatusWizard(models.TransientModel): ...@@ -47,6 +47,8 @@ class BatchInputShipPackageStatusWizard(models.TransientModel):
process_time = fields.Datetime('Process Time(UTC)') process_time = fields.Datetime('Process Time(UTC)')
# 添加状态说明字段 # 添加状态说明字段
state_explain = fields.Text('State Explain', help='State Explain') state_explain = fields.Text('State Explain', help='State Explain')
node_exception_reason_id = fields.Many2one('cc.node.exception.reason', 'Exception Reason',
domain="[('code_id', '=', update_status)]")
# 批量更新小包状态 # 批量更新小包状态
def submit(self): def submit(self):
...@@ -57,9 +59,15 @@ class BatchInputShipPackageStatusWizard(models.TransientModel): ...@@ -57,9 +59,15 @@ class BatchInputShipPackageStatusWizard(models.TransientModel):
if not parcels: if not parcels:
raise ValidationError('没有找到要更新的小包.') raise ValidationError('没有找到要更新的小包.')
# 判断异常状态是否选择了异常原因
reason_obj = self.env['cc.node.exception.reason'].search([('code_id', '=', self.update_status.id)])
if reason_obj and not self.node_exception_reason_id:
raise ValidationError('请选择异常原因!')
# 更新状态 # 更新状态
parcels.write( parcels.write(
{'state': self.update_status.id, 'process_time': self.process_time, 'state_explain': self.state_explain}) {'state': self.update_status.id, 'node_exception_reason_id': self.node_exception_reason_id.id,
'process_time': self.process_time, 'state_explain': self.state_explain})
# 跳转显示本次更新状态的小包 # 跳转显示本次更新状态的小包
return { return {
...@@ -89,6 +97,6 @@ class BatchInputShipPackageStatusWizard(models.TransientModel): ...@@ -89,6 +97,6 @@ class BatchInputShipPackageStatusWizard(models.TransientModel):
if self.exclude_tracking_no: if self.exclude_tracking_no:
exclude_waybill_no_list = self.exclude_tracking_no.split('\n') exclude_waybill_no_list = self.exclude_tracking_no.split('\n')
exclude_waybill_no_list = [i.strip() for i in exclude_waybill_no_list if i.strip()] exclude_waybill_no_list = [i.strip() for i in exclude_waybill_no_list if i.strip()]
parcels = parcels.filtered(lambda r: r.waybill_no not in exclude_waybill_no_list) parcels = parcels.filtered(lambda r: r.tracking_no not in exclude_waybill_no_list)
# 排除状态 # 排除状态
return parcels return parcels
...@@ -21,14 +21,14 @@ ...@@ -21,14 +21,14 @@
<separator/> <separator/>
<field name="update_status" required="1" domain="[('node_type','=','package')]"/> <field name="update_status" required="1" domain="[('node_type','=','package')]"/>
<field name="process_time" required="1" string="Process Time(UTC)"/> <field name="process_time" required="1" string="Process Time(UTC)"/>
<field name="node_exception_reason_id" options="{'no_create':True}"/>
<field name="state_explain"/> <field name="state_explain"/>
</group> </group>
<group> <group>
<field name="is_ok"/> <field name="is_ok"/>
</group> </group>
<footer> <footer>
<button name="submit" type="object" string="Submit" class="oe_highlight" attrs="{'invisible':[('is_ok','=','false')]}"/> <button name="submit" type="object" string="Submit" class="oe_highlight" attrs="{'invisible':[('is_ok','=',False)]}"/>
<button string="Close" special="cancel"/> <button string="Close" special="cancel"/>
</footer> </footer>
</sheet> </sheet>
......
...@@ -30,7 +30,7 @@ def get_utc_time(local_time=None): ...@@ -30,7 +30,7 @@ def get_utc_time(local_time=None):
# 将本地时间转换为UTC时间 # 将本地时间转换为UTC时间
utc_time = local_time.astimezone(pytz.utc) utc_time = local_time.astimezone(pytz.utc)
# 格式化为RFC 3339格式 # 格式化为RFC 3339格式
#rfc3339_time = utc_time.isoformat(timespec='seconds') # rfc3339_time = utc_time.isoformat(timespec='seconds')
return utc_time.strftime('%Y-%m-%d %H:%M:%S') return utc_time.strftime('%Y-%m-%d %H:%M:%S')
...@@ -127,6 +127,16 @@ class CcShipPackage(models.Model): ...@@ -127,6 +127,16 @@ class CcShipPackage(models.Model):
# 增加同步日志纪录字段 # 增加同步日志纪录字段
sync_log_ids = fields.One2many('cc.ship.package.sync.log', 'package_id', 'Sync Logs') sync_log_ids = fields.One2many('cc.ship.package.sync.log', 'package_id', 'Sync Logs')
@api.model
def create(self, vals_list):
"""
第一个节点的时候 默认已同步
"""
obj = super(CcShipPackage, self).create(vals_list)
if obj.state.is_default:
obj.is_sync = True
return obj
def action_sync(self): def action_sync(self):
for record in self: for record in self:
record.is_sync = True record.is_sync = True
...@@ -146,6 +156,7 @@ class CcShipPackage(models.Model): ...@@ -146,6 +156,7 @@ class CcShipPackage(models.Model):
"time_zone": "UTC+0", "time_zone": "UTC+0",
"action_code": self.state.tk_code, "action_code": self.state.tk_code,
"operation_desc": self.state.desc, "operation_desc": self.state.desc,
"reason_code": self.node_exception_reason_id.name or "" # 异常原因
} }
] ]
} }
...@@ -157,6 +168,7 @@ class CcShipPackage(models.Model): ...@@ -157,6 +168,7 @@ class CcShipPackage(models.Model):
tt_api_obj = self.env["ao.tt.api"].sudo() tt_api_obj = self.env["ao.tt.api"].sudo()
response = tt_api_obj.callback_track(data) response = tt_api_obj.callback_track(data)
response_data = response.json() response_data = response.json()
logging.info('callback_track response:%s' % response)
if response_data['code'] != 0: if response_data['code'] != 0:
# 清关文件回传错误 # 清关文件回传错误
self.is_sync = False self.is_sync = False
...@@ -178,6 +190,7 @@ class CcShipPackage(models.Model): ...@@ -178,6 +190,7 @@ class CcShipPackage(models.Model):
self.env['ao.tt.api.log'].create_api_log(self.tracking_no or '', '', '', 0, request_id, source='推出') self.env['ao.tt.api.log'].create_api_log(self.tracking_no or '', '', '', 0, request_id, source='推出')
return '' return ''
# 继承提单对象 # 继承提单对象
class CcBl(models.Model): class CcBl(models.Model):
_inherit = 'cc.bl' _inherit = 'cc.bl'
...@@ -195,12 +208,9 @@ class CcBl(models.Model): ...@@ -195,12 +208,9 @@ class CcBl(models.Model):
else: else:
record.unsync_package_count = 0 record.unsync_package_count = 0
# 定义一个方法, 获取提单下的所有未同步的小包,并回传小包状态 # 定义一个方法, 获取提单下的所有未同步的小包,并回传小包状态
def callback_track(self): def callback_track(self):
ship_packages = self.env['cc.ship.package'].search([('bl_id', '=', self.id), ('is_sync', '=', False)]) ship_packages = self.env['cc.ship.package'].search([('bl_id', '=', self.id), ('is_sync', '=', False)])
for package in ship_packages: for package in ship_packages:
package.callback_track() package.callback_track()
return True return True
...@@ -50,6 +50,7 @@ class TT(models.Model): ...@@ -50,6 +50,7 @@ class TT(models.Model):
timestamp = int(time.time()) timestamp = int(time.time())
sign = self.generate_sign(timestamp, push_data) sign = self.generate_sign(timestamp, push_data)
response = self.get_response(url, sign, timestamp, push_data) response = self.get_response(url, sign, timestamp, push_data)
logging.info('callback_track response:%s' % response)
return response return response
def package_invoice_query(self, push_data): def package_invoice_query(self, push_data):
......
# -*- coding: utf-8 -*-
{
'name': 'Attachment Preview',
'version': '16.0.5',
'sequence': 1,
'category': 'Services/Tools',
'summary': """This module adds a new widget, "many2many_attachment_preview", which enables the user to view attachments without downloading them.""",
'description': """ User can preview a document without downloading. """,
'author': 'Odox Softhub',
'price': 15,
'currency': 'USD',
'website': 'https://www.odoxsofthub.com',
'support': 'support@odoxsofthub.com',
'license': 'LGPL-3',
'assets': {
'web.assets_backend': [
'odx_m2m_attachment_preview/static/src/js/widget.js',
'odx_m2m_attachment_preview/static/src/scss/style.scss',
'odx_m2m_attachment_preview/static/src/xml/widget_view.xml',
],
},
'installable': True,
'application': True,
'auto_install': False,
'images': ['static/description/thumbnail.gif'],
}
<section class="oe_container">
<section class="oe_spaced mw-100 card module-index_mobile_main_section">
<div class="container shadow-sm px-5 text-center module-index_mobile_main_section"
style="padding-right:0px !important;padding-left:0px !important;">
<section class="oe_container mb-4 mt-4">
<div class="row">
<div class="col-lg-12 d-flex flex-column justify-content-center">
<h1 class="text-center"
style="font-family:sans-serif; font-weight: 800; color:#0a1e2c;">
Attachment Preview</h1>
<hr style="background-color: #C5982C; border: 2px solid #C5982C; width: 100px;" ;>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12" style="padding: 0px 0px 0px 0px !important;">
<h3 class="panel-title" style="font-size: 18px;line-height: 32px;color: #333333;">
Features
</h3>
<p>
<ul style="font-size:20px;text-align:left;">
<br>
<li>
Added new widget 'many2many_attachment_preview'.
</li>
<li>
User can preview a document without downloading.
</li>
</ul>
</p>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12" style="padding: 0px 0px 0px 0px !important;">
<h3 class="panel-title" style="font-size: 18px;line-height: 32px;color: #333333;">
Look how it to use.
</h3>
<div class="oe_demo oe_picture oe_screenshot mobile-index-img-div img-m2m-field"
style="max-height:100% !important;">
<img class="index-image" src="m2m_py.png" style="height:100%;">
</div>
<div class="oe_demo oe_picture oe_screenshot mobile-index-img-div img-m2m-field"
style="max-height:100% !important;">
<img class="index-image" src="m2m_xml.png" style="height:100%;">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12" style="padding: 0px 0px 0px 0px !important;">
<h3 class="panel-title" style="font-size: 18px;line-height: 32px;color: #333333;">
Preview will be showing on the screen.
</h3>
<div class="oe_demo oe_picture oe_screenshot mobile-index-img-div"
style="max-height:100% !important;">
<img class="index-image" src="m2m_widget.gif" style="height:100%;">
</div>
<br/>
<div class="oe_demo oe_picture oe_screenshot mobile-index-img-div"
style="max-height:100% !important;">
<img class="index-image" src="next_button.png" style="height:100%;">
</div>
</div>
</div>
</section>
<section class="oe_container" style="padding: 2rem 3rem 1rem;margin-top:5px;">
<section class="oe_container mb-4 mt-4">
<div class="panel panel-primary">
<a href="https://apps.odoo.com/apps/modules/browse?search=odx" target="_blank">
<div class="panel-heading">
<h3 class="panel-title" style="font-size: 26px;line-height: 32px;color: ##0f0b0b;">
Other Apps
</h3>
</div>
</a>
</div>
</section>
</section>
<section class="container" style="margin: 5rem auto 2rem; background-color: #fff !important;">
<div class="row" style="max-width:1540px;">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center mb-4">
<hr class="position-absolute"
style="border: 1px solid #c4c6cc !important; width: 40% !important; z-index: 0 !important;margin-top:40px;">
<h2
style="font-size: 26px;background-color: #fff !important; z-index: 1 !important; padding: 0 1rem !important;">
Help & Support</h2>
</div>
</div>
<div class="row d-flex justify-content-center align-items-center"
style="max-width:1540px; margin: 0 auto 2rem auto;">
<div class="col-lg-12" style="padding: 0rem 3rem 2rem; border-radius: 10px;">
<div class="row mt-4 d-flex justify-content-center align-items-center">
<div class="col-lg-4">
<a href="mailto:support@odoxsofthub.com<" target="_blank"
class="btn btn-block mb-2 deep_hover"
style="text-decoration: none; background-color: #4d4d4d; color: #C5982C; border-radius: 4px;"><i
class="fa fa-envelope mr-2"></i>support@odoxsofthub.com</a>
</div>
</div>
</div>
</div>
</section>
<section class="oe_container" style="padding: 2rem 3rem 1rem; background-color: #fff !important;">
<div class="row" style="max-width:1540px; margin: 0 auto; margin-right: 3rem; ">
<div class="col-lg-12 d-flex justify-content-center align-items-center">
<a href="https://www.odoxsofthub.com" target="_blank">
<img src="logo.png" alt="Odoxsofthub.com">
</a>
</div>
</div>
</section>
</div>
</section>
</section>
.modal-img {display: none;position: fixed;z-index: 2000;left: 0;top: 0;width: 100%;height: 100%;overflow: auto;background-color: rgba(0,0,0,0.9);}
.modal-img img {width:auto;height:auto;max-width: 70%;max-height: 70%;margin: auto;display: block;}
.modal-img .row{padding:0 40px;}
.close-img:hover {color:#fff !important;}
.close-img {margin-left:auto;vertical-align:middle;font-size: 30px;font-weight: bold;color: grey !important;cursor: pointer;}
#OrderPdfDownloadLink{margin-right:10px;}
.m2m-zoom-buttons{width:100%;position: absolute;bottom: 10px;left: 10px;}
#m2m-zoom-in,#m2m-download-btn,#m2m-print-pdf,#m2m-zoom-out,#m2m-forward,#m2m-backward,#m2m-play-pause,#m2m-next-btn,#m2m-prev-btn {width:40px;height:40px;font-size:15px;margin-right:5px;background-color: var(--AttachmentViewer_toolbarButton-background-color, #343a40);color: #fff;border: none;}
.m2m-widget-image{width:100px;cursor:pointer;}
.close-pdf{margin-left:auto;vertical-align:middle;font-size: 30px;font-weight: bold;color: grey !important;cursor: pointer;}
.pdf-container{display:flex;justify-content:center;align-items:center;}
.m2m-image-container{position: relative;display: inline-block;width: auto !important;padding: 2px 5px;}
.m2m-attach-delete-btn{color: red;margin-left: 5px;font-size: 15px;opacity: 0;transition: opacity 0.3s;cursor: pointer;}
.m2m-image-container:hover .m2m-attach-delete-btn { opacity: 1; }
.odx_video {
width: 100%;
height: 100%;
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="odx_m2m_attachment_preview.Many2ManyBinaryField" owl="1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.10.377/pdf.min.js"></script>
<div t-attf-class="oe_fileupload {{props.className ? props.className : ''}}" aria-atomic="true">
<div class="o_attachments">
<t t-foreach="files" t-as="file" t-key="file_index">
<t t-call="odx_m2m_attachment_preview.attachment_preview"/>
</t>
</div>
<div t-if="!props.readonly" class="oe_add">
<FileInput
acceptedFileExtensions="props.acceptedFileExtensions"
multiUpload="true"
onUpload.bind="onFileUploaded"
resModel="props.record.resModel"
resId="props.record.data.id or 0"
>
<button class="btn btn-secondary o_attach" data-tooltip="Attach">
<span class="fa fa-paperclip" aria-label="Attach"/>
<t t-esc="props.uploadText"/>
</button>
</FileInput>
</div>
</div>
</t>
<t t-name="odx_m2m_attachment_preview.attachment_preview" owl="1">
<t t-set="editable" t-value="!props.readonly"/>
<div t-attf-class="o_attachment o_attachment_many2many #{ editable ? 'o_attachment_editable' : '' } #{upload ? 'o_attachment_uploading' : ''}"
t-att-title="file.name">
<div class="o_attachment_wrap">
<t t-set="ext" t-value="getExtension(file)"/>
<t t-set="fileID" t-value="file.id"/>
<div class="o_image_box float-start" t-att-data-tooltip="'Download ' + file.name" t-att-data-id="file.id">
<!-- <a t-att-href="getUrl(file.id)" aria-label="Download">-->
<t t-if="file.mimetype.startsWith('image')">
<span t-attf-class="o_image o_hover attachment-preview-{{file.id}}"
t-on-click="() => {this.onFilePreview(file.id)}" t-attf-data-url="getUrl(file.id)"
t-att-data-mimetype="file.mimetype" t-att-data-ext="ext" role="img"
t-attf-style='background-image: url("/web/content/{{file.id}}");'/>
</t>
<t t-else="">
<span t-attf-class="o_image o_hover attachment-preview-{{file.id}}"
t-on-click="() => {this.onFilePreview(file.id)}" t-attf-data-url="getUrl(file.id)"
t-att-data-mimetype="file.mimetype" t-att-data-ext="ext" role="img"/>
</t>
<!-- </a>-->
</div>
<div class="caption">
<a class="ml4" t-att-data-tooltip="'Download ' + file.name" t-att-href="getUrl(file.id)"><t t-esc='file.name'/></a>
</div>
<div class="caption small">
<a class="ml4 small text-uppercase" t-att-href="getUrl(file.id)"><b><t t-esc='ext'/></b></a>
<div t-if="editable" class="progress o_attachment_progress_bar">
<div class="progress-bar progress-bar-striped active" style="width: 100%">Uploading</div>
</div>
</div>
<div class="o_attachment_uploaded"><i class="text-success fa fa-check" role="img" aria-label="Uploaded" title="Uploaded"/></div>
<div t-if="editable" class="o_attachment_delete" t-on-click.stop="() => this.onFileRemove(file.id)"><span class="text-white" role="img" aria-label="Delete" title="Delete">×</span></div>
</div>
</div>
</t>
</templates>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论