在uniapp上访问odoo系统上的图片
1、以url的情势访问
a:以odoo自己的域名,好比http://127.0.0.1:8069/web/image/product.template/3/image_128?unique=1740380422000,这种方式需要解决跨域的问题。
b:以文件服务器的情势,好比http://111.229.103.209/files/
2、odoo以Base64格式返回给uniapp,使用 Vue 的数据绑定来动态更新 src 属性。Base64 编码的图片会增大数据体积(约莫增加 33%),对于大图片或大量图片,大概会影响性能和加载时间。
- <template>
- <view>
- <image :src="dynamicBase64Image" style="width: 100px; height: 100px;"></image>
- </view>
- </template>
- <script>
- export default {
- data() {
- return {
- dynamicBase64Image: ''
- };
- },
- methods: {
- fetchBase64Image() {
- // 假设这里通过 API 获取 Base64 编码的图片
- uni.request({
- url: 'https://example.com/api/get-base64-image',
- success: (res) => {
- this.dynamicBase64Image = res.data.base64Image;
- }
- });
- }
- },
- onLoad() {
- this.fetchBase64Image();
- }
- };
- </script>
复制代码 最终选择了以文件服务器的情势来访问。
服务器环境:腾讯云服务器ubuntu22.04
1.使用 Nginx 托管静态文件
1.1.nginx安装
- sudo apt-get install nginx # 安装nginx
- sudo service nginx restart # 重启nginx
复制代码 1.2.nginx环境配置
- cd /etc/nginx/ # 进入nginx目录,可以通过ls查看有哪些文件
- cd sites-available # 进入sites-available
- # 备份一个default
- sudo cp default default.bak
- sudo vim default
复制代码 此中location /files就是文件共享目次
- server {
- listen 80;
- server_name 111.229.103.209; # 你的域名或服务器IP
- # 静态文件托管目录
- location /files {
- alias /etc/odoo/filestore; # 你的文件存储路径
- autoindex on; # 可选:开启目录浏览
- }
- location / {
- proxy_redirect off;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_read_timeout 900; # 根据需要调整超时时间
- proxy_connect_timeout 900; # 根据需要调整超时时间
- proxy_pass http://127.0.0.1:8069; # Odoo的默认端口是8069
- }
- location /longpolling {
- proxy_redirect off;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_read_timeout 36000s; # 长轮询可能需要较长的超时时间
- proxy_pass http://127.0.0.1:8072; # Odoo的长轮询端口通常是8072
- }
- # 如果需要HTTPS,请添加SSL配置段(略)
- }
复制代码 1.3.文件效果
2.odoo对静态文件的读写
2.1.odoo之ir.attachment
以产物图片为例:
odoo的ir.attachment有3层结构,这里的文件是图片。
1、文件自己对应了一个附件,用于存储文件自己,对于相同的文件,checksum和store_fname是相同的。
2、文件对应了一个webp附件,用于文件的附件地址。
3、产物图片,好比image_1920指向了文件的地址。对于image_1920、……、image_128,假如图片较小,odoo不会压缩图片,都会对应同一张图片;假如文件较大,odoo会根据尺寸限制压缩图片,不同尺寸的image会指向不同的图片地址。
2.2.静态文件的读写
- # -*- coding: utf-8 -*-
- import os
- import base64
- import binascii
- import urllib.parse
- from odoo import api, fields, models, _, _lt
- from odoo.exceptions import UserError
- import logging
- _logger = logging.getLogger(__name__)
- class IrAttachment(models.AbstractModel):
- _inherit = 'ir.attachment'
- attachment_url = fields.Char('Attachment URL', help="The URL of the file in the remote server")
- def _is_image_mimetype(self):
- """判断是否为图片类型"""
- return self.mimetype and (self.mimetype == 'image/jpeg' or self.mimetype == 'image/png')
- # return True
- def _sync_image_to_nginx(self, datas, filename):
- """同步图片到Nginx目录"""
- nginx_dir = self.env['ir.config_parameter'].sudo().get_param('attachment.dir', '/etc/odoo/filestore')
- # 获取数据库名(替换非法字符)
- # nginx_dir = odoo.tools.config['data_dir']
- db_name = self.env.cr.dbname.replace('/', '_').replace('\\', '_')
- # 获取模型名(替换点号为下划线)
- nginx_dir += f'/{db_name}/files/'
- base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
- url_parse = urllib.parse.urlparse(base_url)
- attachment_url = url_parse.scheme + '://' + url_parse.hostname + f'/{db_name}/files/'
- if not os.path.exists(nginx_dir):
- os.makedirs(nginx_dir, exist_ok=True)
- os.chmod(nginx_dir, 0o755) # 确保目录权限
- file_path = os.path.join(nginx_dir, filename)
- try:
- with open(file_path, 'wb') as f:
- f.write(datas)
- _logger.info(f"图片已同步到Nginx目录: {file_path}")
- return attachment_url
- except Exception as e:
- _logger.error(f"同步失败: {str(e)}")
- return False
- @api.model_create_multi
- def create(self, vals_list):
- res_ids = super().create(vals_list)
- for index in range(len(res_ids)):
- vals = vals_list[index]
- res_id = res_ids[index]
- description = vals.get('description', '')
- if not res_id.mimetype or not res_id.mimetype.startswith('image') or (description and description.startswith('resize')):
- continue
- store_fname = res_id.store_fname
- attachment_id = self.env['ir.attachment']
- if store_fname:
- attachment_id = self.env['ir.attachment'].search([
- ('id', '!=', res_id.id),
- ('res_model', '=', 'ir.attachment'),
- ('store_fname', '=', store_fname),
- ])
- if attachment_id and attachment_id.attachment_url:
- res_id.write({
- 'attachment_url': attachment_id.attachment_url
- })
- continue
- if not res_id._is_image_mimetype():
- continue
- if not vals.get('res_id'):
- continue
- attachment_id = self.env['ir.attachment'].sudo().browse(vals.get('res_id'))
- datas = vals.get('datas')
- if not datas or not attachment_id:
- continue
- # Base64解码
- file_data = base64.b64decode(datas) or False
- # 同步到Nginx
- filename = "%s_%s" % (store_fname.replace('/', '_').replace('\\', '_'), vals.get('name'))
- attachment_url = self._sync_image_to_nginx(file_data, filename)
- if attachment_url:
- attachment_id.write({'attachment_url': attachment_url})
- return res_ids
- def unlink(self):
- """删除时同步清理static文件"""
- for attach in self:
- if attach.attachment_url and os.path.exists(attach.attachment_url):
- try:
- os.remove(attach.attachment_url)
- # 尝试清理空目录
- dir_path = os.path.dirname(attach.attachment_url)
- if not os.listdir(dir_path):
- os.rmdir(dir_path)
- _logger.info(f"已删除: {attach.attachment_url}")
- except Exception as e:
- _logger.error(f"删除失败: {str(e)}")
- return super().unlink()
- def write(self, vals):
- try:
- bin_data = base64.b64decode(vals.get('datas', '')) or False
- except binascii.Error:
- raise UserError(_("Attachment is not encoded in base64."))
- if self.mimetype and self.mimetype.startswith('image'):
- checksum = self._compute_checksum(bin_data)
- attachment_id = self.env['ir.attachment'].search([
- ('id', '!=', self.id),
- ('res_model', '=', 'ir.attachment'),
- ('checksum', '=', checksum),
- ])
- if attachment_id and attachment_id.attachment_url:
- vals['attachment_url'] = attachment_id.attachment_url
- return super(IrAttachment, self).write(vals)
复制代码 

2.3.静态文件的获取和表现
- # -*- coding: utf-8 -*-
- import json
- import logging
- from odoo.http import Controller, request, route
- class ProductController(Controller):
- @route(['/api/product/list'], type='http', auth='public', methods=['GET', 'OPTIONS'], csrf=False, cors='*')
- def api_product_list(self, **kw):
- logging.info('api_product_list:%s', kw)
- product_ids = request.env['product.product'].sudo().search([])
- data = []
- for product_id in product_ids:
- domain = [
- ('res_model', '=', 'product.template'),
- ('res_field', '=', 'image_1920'),
- ('res_id', 'in', product_id.product_tmpl_id.id),
- ]
- attachment_id = request.env['ir.attachment'].sudo().search(domain)
- data.append({
- 'id': product_id.id,
- 'name': product_id.name,
- 'lst_price': product_id.lst_price,
- 'thumbnail': attachment_id.attachment_url
- })
- return json.dumps({'code': 200, 'data': data, 'count': len(product_ids)})
复制代码
3.总结
nginx静态文件的方式可以扩展到系统日记、备份等需要保存文件的场景。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! 更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |